Введение в программирование на SourcePawn. Часть 5.

Сообщения
207
Реакции
420
Помог
10 раз(а)
Введение в программирование на SourcePawn. Строки.

Строки - это массивы символов. Это означает, что помимо обращения к самой строке, Вы можете обращаться к определённым символам по индексу.
Концом строки считается всегда нулевой символ.
Т.е., функции SM и расширения всегда читают строку до нулевого байта (0 или '\0').
Размер строки указывается при её создании в квадратных скобках:
Код:
char szString[16] = "Hello, Dev-CS!";
Размер строки здесь - 16, а в ней записано 15 байт (14 сам текст + 1 нулевой).
Выделять буфер большого размера без причины считается всегда плохим тоном. Например, я сомневаюсь, что у кого-то IP-адрес игрока будет занимать 1024 байт.
Вообще, у SourcePawn есть константы размеров, которые удобно использовать.
  • PLATFORM_MAX_PATH - применяется в буферах под путь файла. Константа равна 256.
  • MAX_TARGET_LENGTH - применяется в буферах для имени игрока. Равна 32 (с недавнего апдейта SM, из-за очередных "скрытых" фич CS:GO, это число подняли до 128).
И так далее. Вообще, MAX_TARGET_LENGTH обычно ещё применяют для указания размера строки под IP-адрес или SteamID.
Для получения размера "буфера" строки внутри функции, где эта строка была объявлена, применяется инструкция пре-процессора (компилятора) sizeof(). Вы могли видеть её вызовы в таких функциях, как Format(), FormatEx(), strcopy() и так далее.
Код:
char szString[16];
FormatEx(szString, sizeof(szString), "Hello, Dev-CS!");

// Хочется показать, как работать с этой же инструкцией с двумерными массивами. Тут есть подводный камень.
// sizeof(szString[0]) выплюнет ошибку ещё на процессе компиляции.
// Правильнее записывать sizeof(szString[])
char szString[2][32];
FormatEx(szString[0], sizeof(szString[]), "My first SourcePawn code!");
FormatEx(szString[1], sizeof(szString[]), "Learning sizeof() features...");
Ещё есть strlen(). Он возвращает кол-во уже записанных в строке байт.
Код:
char szString[16] = "Hello, Dev-CS!";
int iBufferLength = sizeof(szString); // 16
int iStringLength = strlen(szString); // 14
С этим, надеюсь, разобрались.

Очистка строк
Есть множество способов очистки строк:
  • strcopy(szString, sizeof(szString), "");
  • Format(szString, sizeof(szString), "");
  • szString = "";
  • szString[0] = '\0';
  • szString[0] = 0;
Самыми оптимальными считаются два нижних. По сути, это одно и то же.
Как мы уже знаем, строка для функций SM заканчивается на нулевой байт. То есть, если мы присвоим первому символу значение нулевого байта, то для всех функций, строка будет пустой.
В двух верхних вариантах мы обращаемся к "сторонним" функциям, что занимает некоторое время.
Потому самыми оптимальными считаются два нижних варианта, т.к. выполнение кода за пределы виртуальной машины не выходит.

А что, если надо обрезать одну строку, и передать значения? Тогда мы можем воспользоваться "фичей" строк, когда строка заканчивается на нулевой байт. Банальный пример: есть строка, в которой перечисляются номера групп пользователя через запятую. Как мы можем вытянуть из неё эти номера и передать их сторонней функции?
Допустим, что максимальное кол-во групп - это 10. Тогда объявляем числовой массив размером 10, и просто итерируемся по строке:
C++:
// для примера: в szGroups хранится строка "2,5,10,99,22"
int[10] iGroupIds;
int iCurrentGroup, i;
while (i != -1) {
  i = FindCharInString(szGroups, ',', true);
  iGroupIds[iCurrentGroup++] = StringToInt(szGroups+1);
  if (i != -1)
    szGroups[i] = 0;
}
И так, что здесь происходит?
  • Объявляется массив типа int с именем iGroupIds и размером 10.
  • Объявляется две переменные с типом int и стандартным значением 0: iCurrentGroup (для хранения индекса массива, в который будет записываться номер группы) и i (для хранения позиции запятой после поиска)
  • Пока последняя найденная позиция запятой - не -1 (что означает "такого символа нет"), производить снова и снова её поиск с конца, преобразовывать строку в число, и занулливать позицию запятой (если опять же, позиция запятой не -1), чтобы функции больше не залезали туда.
Таким простым способом мы получаем массив номеров групп и кол-во оных.

Исходя из того факта, что строка всегда заканчивается на нулевой байт, можно так же проверять строку на пустоту:
Код:
if (szString[0] == 0) {
  // строка пустая
}
Или наоборот:
Код:
if (szString[0] != 0) {
  // строка не пуста
}
Для форматирования строки (подстановки некоторых значений других переменных), в SourcePawn есть аж две инструкции: Format() и FormatEx(). Основное отличие между ними - Format() создаёт временный буфер, в котором производит форматирование, и потом копирует его значение в переданную строку, а FormatEx() пишет напрямую в переданный буфер. Из этого простейшего описания можно сделать вывод, что выгоднее всего использовать FormatEx(), но есть ситуации, когда его использовать нельзя. Самый простейший пример:
C++:
char szBuffer[64];
strcopy(szBuffer, sizeof(szBuffer), "Dev-CS.RU");

// неверно.
// мы получим строку вида: Hello, Hello, *мусор виртуальной машины*
FormatEx(szBuffer, sizeof(szBuffer), "Hello, %s!", szBuffer);

// верно.
// Hello, Dev-CS.RU!
Format(szBuffer, sizeof(szBuffer), "Hello, %s!", szBuffer);
Довольно просто, да? Если используется в форматировании буфер, в который и идёт запись - используем Format(), в противном случае FormatEx().

Так же есть ещё функция VFormat(). Она по сути тоже делает форматирование строки, но применяется в других ситуациях. Мы обязательно её рассмотрим позднее.
 

Пользователи, просматривающие эту тему

Сейчас на форуме нет ни одного пользователя.
Сверху Снизу