PDA

Просмотр полной версии : [Вопрос] Вопрос про sscanf.



DmitriyVasilev
07.03.2019, 18:08
Здравствуйте, почему в одной команде просто назначен sscanf а в другой
new giveplayerid;
if(sscanf(params, "u",giveplayerid)) return SCM(playerid, -1, !"Введите: /iwep [playerid]");
зачем объявлять переменную?

Seviel
07.03.2019, 19:30
В giveplayerid будет храниться id игрока.

u - user, он может быть указан с помощью id(например: 15) или часть ника(например: Nick).

DeimoS
07.03.2019, 23:14
Здравствуйте, почему в одной команде просто назначен sscanf а в другой
new giveplayerid;
if(sscanf(params, "u",giveplayerid)) return SCM(playerid, -1, !"Введите: /iwep [playerid]");
зачем объявлять переменную?

Потому что в первом случае используется параметр params для хранения данных, в котором просто может не оказаться ячеек. Для params выделяется столько ячеек, сколько символов ввёл игрок в качестве параметров. И если, например, написать такую команду:
CMD:test(playerid, params[])
{
if(sscanf(params, "I(-1)", params[0]))// Если игрок не ввёл число, то sscanf попытается автоматически подставить "-1"
return SendClientMessage(...);
....
return 1;
}
То, если ввести "/test", команда не выполнится, так как случится выход за пределы массива, ибо мы никаких параметров не передали с командой => в params не существует нулевой ячейки.

Или если, например, попытаться записать текст из параметра, который находится не напоследнем месте. Например:
CMD:test(playerid, params[])
{
if(sscanf(params, "s[30]ii", params[0], params[1], params[2]))
return SendClientMessage(...);
....
return 1;
}
Если ввести "/test Привет 11 62", то sscanf сначала запишет слово "Привет" в ячейки с нулевой по пятую, а потом перезапишет первую и вторую ячейку указанными числами, портя записанное ранее слово (это довольно распространённая проблема у любителей не объявлять переменные для хранения параметров).
"]0 - П
1 - р
2 - и
3 - в
4 - е
5 - т
6 - \0

0 - П
1 - 11// Вот эти ячейки будут перезаписаны => данные уже испорчены и команда работает неправильно
2 - 62
3 - в
4 - е
5 - т
6 - \0


Да и на читаемость это очень сильно влияет, ибо гораздо понятнее смысл передаваемых данных в таком случае:
format(string, sizeof(string), "Игрок %s купил %s за $%d на слот %d", player_name, item_name, item_price, item_slot);
Нежели чем в таком:
format(string, sizeof(string), "Игрок %s купил %s за $%d на слот %d", player_name, params[2], params[0], params[1]);
В первом случае достаточно посмотреть на имя переменной, чтоб понять какие данные там хранятся. Во втором случае нужно смотреть на строку, выискивать среди неё нужный заполнитель и сопоставлять "params[..]" с найденным заполнителем (либо вообще лезть в шапку команды и смотреть структуру sscanf).


Если и использовать params для хранения параметров команды, то только в качестве хранения текста, по типу:
CMD:pm(playerid, params[])
{
new giveplayerid;
if(sscanf(params, "rs[128]", giveplayerid, params))// Запишем введённое сообщение в params
return SendClientMessage(playerid, -1, "/pm id text");
if(giveplayerid == INVALID_PLAYER_ID)
return SendClientMessage(playerid, -1, "Игрок не найден!");
SendClientMessage(giveplayerid, -1, params);// и отобразим его получателю
return 1;
}
В этом случае и вышеперечисленных проблем не будет, и читаемость не сильно упадёт, ибо сразу понятно, что массив params хранит какой-то текст.

Daniel_Cortez
08.03.2019, 11:29
И если, например, написать такую команду:
CMD:test(playerid, params[])
{
if(sscanf(params, "I(-1)", params[0]))// Если игрок не ввёл число, то sscanf попытается автоматически подставить "-1"
return SendClientMessage(...);
....
return 1;
}
То, если ввести "/test", команда не выполнится так как случится выход за пределы массива, ибо мы никаких параметров не передали с командой => в params не существует нулевой ячейки.
В любой строке есть как минимум символ '\0', поэтому в массиве params всегда гарантируется наличие 0-й ячейки.

DeimoS
08.03.2019, 12:39
В любой строке есть как минимум символ '\0', поэтому в массиве params всегда гарантируется наличие 0-й ячейки.

Да, точно. Забыл про нуль-символ. Ну сути это не меняет и пример тогда будет таким:
CMD:test(playerid, params[])
{
if(sscanf(params, "I(-1)I(-1)", params[0], params[1]))// Если игрок не ввёл число, то sscanf попытается автоматически подставить "-1"
return SendClientMessage(...);
....
return 1;
}