Добро пожаловать на Pro Pawn - Портал о PAWN-скриптинге.
Показано с 1 по 6 из 6
  1. #1
    Аватар для ex4mpl3
    Пользователь

    Статус
    Оффлайн
    Регистрация
    24.01.2023
    Сообщений
    2
    Репутация:
    0 ±

    AMX error occurred in public pc_cmd_show_licenses: Array index out of bounds

    Здравствуйте, решил написать простую систему лицензий, при вводе команды, часть отрабатывает нормально, а часть нет.

    Команда.
    1. CMD:show_licenses(playerid, params[])
    2. {
    3. new
    4. targetid;
    5.  
    6. if (sscanf(params, "d", targetid))
    7. {
    8. return SendClientMessage(playerid, COLOR_WHITE, "Введите: /show_licenses [id]");
    9. }
    10.  
    11. if (!IsPlayerConnected(targetid))
    12. {
    13. return SendClientMessage(playerid, COLOR_LIGHTRED, "Игрока с таким ником/ид нет в игре.");
    14. }
    15.  
    16. ShowLicensesArray(playerid);
    17. ShowPlayerLicenses(playerid, targetid);
    18.  
    19. return true;
    20. }


    1. enum E_LICENSES_TYPE
    2. {
    3. E_LICENSE_CAR,
    4. E_LICNESE_AIRPLANE,
    5. E_LICNESE_BOAT,
    6. E_LICNESE_MOTORBIKE,
    7. E_LICENSE_WEAPON,
    8. E_LICENSE_BUSSINES
    9. }
    10.  
    11. const
    12. MAX_LICENSES_TYPE = _:E_LICENSES_TYPE,
    13. MAX_LICENSE_NAME = 40;
    14.  
    15. new
    16. bool:g_players_licenses[MAX_PLAYERS][E_LICENSES_TYPE] = {false, ...};
    17.  
    18. static const g_licenses_name[E_LICENSES_TYPE][MAX_LICENSE_NAME] =
    19. {
    20. "Водительские права",
    21. "Лицензия на возждение самолётом",
    22. "Лицензия на вождение водным транспортом",
    23. "Лицензия на вождения мотоцкла",
    24. "Лицензия на ношей оружия",
    25. "Лицензия на ведения бизнеса"
    26. };


    ShowLicensesArray(playerid); - отрабатывает полностью нормально.
    1. stock ShowLicensesArray(playerid)
    2. {
    3. for (new i = 0; i < MAX_LICENSES_TYPE; ++i)
    4. {
    5. printf("[ShowLicensesArray]: i: %d, lic: %d", i, g_players_licenses[playerid][i]);
    6. }
    7. }

    GeneratePlayerLicenseList - доходит до строки (11) "printf("[GeneratePlayerLicenseList]: i + 1: %d", i + 1);" отрабатывает и дальше не идёт.
    1. stock GeneratePlayerLicenseList(playerid, output_string[512], const size = sizeof(output_string))
    2. {
    3. printf("[GeneratePlayerLicenseList]: ОТРАБОТАЛ");
    4. output_string[0] = EOS;
    5.  
    6. format(output_string, size, "Лицензии игрока: %s",
    7. GetPlayerName(playerid));
    8.  
    9. for (new i = 0; i < MAX_LICENSES_TYPE; ++i)
    10. {
    11. printf("[GeneratePlayerLicenseList]: i + 1: %d", i + 1);
    12. printf("[GeneratePlayerLicenseList]: g_players_licenses[playerid][i]: %d)", g_players_licenses[playerid][i]);
    13. printf("[GeneratePlayerLicenseList]: g_licenses_name[i]: %s", g_licenses_name[i]);
    14. printf("[GeneratePlayerLicenseList]: (GetPlayerLicense(playerid, i): %d)", GetPlayerLicense(playerid, i));
    15. printf("[GeneratePlayerLicenseList]: ДОШЛО!");
    16. format(output_string, size, "%s%d. %s: %s\n",
    17. output_string,
    18. i + 1,
    19. g_licenses_name[i],
    20. (GetPlayerLicense(playerid, i)) ? "Есть": "Отсутствует");
    21. }
    22. }


    Не понятно как такое происхсодит, т.к. 12 строка делаёт всё то же, что и цикл в ShowLicensesArray(playerid), но тот отрабатывает нормально, а это нет.

    В крашлоге это:
    [16:04:46] #0 00012ee8 in ?? (0, 4282148, 512) at C:ссылка\gamemodes\Tested.pwn:885 *(16 строка в GeneratePlayerLicenseList)*

    и это:
    [16:04:46] #1 00410334 in public pc_cmd_show_licenses () at C:\ссылка\gamemodes\Tested.pwn:38911 *(вообще в самый конец мода, который никак не связан)*
    Последний раз редактировалось ex4mpl3; 24.01.2023 в 18:12.

  2. #2
    Аватар для punkochel
    Пользователь

    Статус
    Оффлайн
    Регистрация
    08.12.2018
    Адрес
    Россия
    Сообщений
    146
    Репутация:
    25 ±
    Покажи как ты GeneratePlayerLicenseList вызываешь, с какими параметрами.

    UPD:
    GetPlayerName возвращает длину записанного никнейма, а не сам никнейм.
    В данном случае тебе необходимо убедиться на 100% что размер массива который будет передан в функцию через параметр output_string[] будет обеспечивать запись всего форматируемого текста.

    1. stock GeneratePlayerLicenseList(playerid, output_string[], size = sizeof(output_string))
    2. {
    3. GetPlayerName(playerid, output_string, MAX_PLAYER_NAME+1);
    4. format(output_string, size, "Лицензии игрока: %s", output_string);
    5. for(new i; i < MAX_LICENSES_TYPE; ++i) {
    6. format(output_string, size, "%s%d. %s: %s\n",
    7. output_string,
    8. i+1,
    9. g_licenses_name[i],
    10. (GetPlayerLicense(playerid, i)) ? ("Есть") : ("Отсутствует"));
    11. }
    12. return 1;
    13. }


    В целом, подобная практика использования таким способом функций не есть хорошо. Данный способ обладает несколькими недостатками: если функция расположена не в поле зрения, то подсчитать размер подходящего массива будет крайне неудобно и как следствие, результат будет не тот которого ты ожидаешь.
    Последний раз редактировалось punkochel; 24.01.2023 в 19:08.

  3. Пользователь сказал cпасибо:
    ex4mpl3 (25.01.2023)
  4. #3
    Аватар для Shaolinka
    Пользователь

    Статус
    Оффлайн
    Регистрация
    19.01.2020
    Сообщений
    69
    Репутация:
    8 ±
    Во первых посоветовал бы не играться со стеком, выделяя память в том случае, где это вовсе не нужно. В твоём случае нет нужды сохранять названия подпунктов диалога с лицензиями в двумерном массиве. Это понты, раз уж на то пошло, на реальном примере, спустя время, будешь прибегать к наиболее оптимальному варианту, не потребляющему столько байтов. Дальше хотелось бы подметить то, что нельзя присваивать данные двумерному массиву таким образом, коим это делаешь Ты. Тем более, если речь о булевых значениях, то нет смысла делать такое, ибо пр-тумолчанию итак false будет. Хотя, если бы вторая мера не была перечислением, то можно было бы провернуть такое:

    PHP код:
    new boolg_players_licenses[MAX_PLAYERS][MAX_LICENSES_TYPE] = {{false, ...}, ...}; 
    но если речь о перечислении, то придётся тогда уж либо циклом присваивать всем элементам той или иной статус(вариант не из лучших), либо же создавать массив на n кол-во элементов(MAX_LICENSES_TYPE), устанавливая всем элементам false статус.

    Насчёт проблемы, то почему не указан const и видеть бы, при каких условиях вызывается GeneratePlayerLicenseList. И к слову, не понимаю к чему очищать массив изначально. Судя по всему в output_string поступает глобальный массив, где вполне себе могут быть данные. К рассчёту памяти в этом случае тоже стоило бы подойти рациональнее, потому как не уверен, что там и впрямь всё 512 ячеек нужны. Ну и к слову, ты забыл скобки в тернарке, поэтому вот:

    PHP код:
    format(output_stringsize"%s%d. %s: %s\n",
                    
    output_string
                    
    1
                    
    g_licenses_name[i],
                    (
    GetPlayerLicense(playeridi) ? ("Есть") : ("Отсутствует"))); 
    - - - Добавлено - - -

    Цитата Сообщение от punkochel Посмотреть сообщение
    Покажи как ты GeneratePlayerLicenseList вызываешь, с какими параметрами.

    UPD:
    GetPlayerName возвращает длину записанного никнейма, а не сам никнейм.
    В данном случае тебе необходимо убедиться на 100% что размер массива который будет передан в функцию через параметр output_string[] будет обеспечивать запись всего форматируемого текста.

    1. stock GeneratePlayerLicenseList(playerid, output_string[], size = sizeof(output_string))
    2. {
    3. GetPlayerName(playerid, output_string, MAX_PLAYER_NAME+1);
    4. format(output_string, size, "Лицензии игрока: %s", output_string);
    5. for(new i; i < MAX_LICENSES_TYPE; ++i) {
    6. format(output_string, size, "%s%d. %s: %s\n",
    7. output_string,
    8. i+1,
    9. g_licenses_name[i],
    10. (GetPlayerLicense(playerid, i)) ? ("Есть") : ("Отсутствует"));
    11. }
    12. return 1;
    13. }
    Если мне не изменяет память, то использовав формат в надежде записать: Лицензии игрока %s, ник не будет передан, ибо формат при записи в массив новых данных, чистит его от старых. Поэтому гораздо-более благонадежнее было бы создать отдельное хранилище под ник. А ещё лучше записывать его куда-нибудь, когда игрок подключается к серваку. И, к слову, длину output_string всё же стоило бы указать, ибо в более новых версиях компилятор реагирует на нефиксированный размер массив, выводя предупреждение

  5. Пользователь сказал cпасибо:
    ex4mpl3 (25.01.2023)
  6. #4
    Аватар для punkochel
    Пользователь

    Статус
    Оффлайн
    Регистрация
    08.12.2018
    Адрес
    Россия
    Сообщений
    146
    Репутация:
    25 ±
    Цитата Сообщение от Shaolinka Посмотреть сообщение
    Если мне не изменяет память, то использовав формат в надежде записать: Лицензии игрока %s, ник не будет передан, ибо формат при записи в массив новых данных, чистит его от старых. Поэтому гораздо-более благонадежнее было бы создать отдельное хранилище под ник. А ещё лучше записывать его куда-нибудь, когда игрок подключается к серваку. И, к слову, длину output_string всё же стоило бы указать, ибо в более новых версиях компилятор реагирует на нефиксированный размер массив, выводя предупреждение
    В случае с моим примером не будет никаких предупреждений. А о том что может не хватить размера я указал. Если автор хочет использовать функцию так, пусть использует. Понятное дело что лучше записывать в массив подобные данные, дабы не обращаться каждый раз к серверу.
    Я бы вообще отказался от подобных извращений и писал бы код форматирования там, где непосредственно он и используется.

    Цитата Сообщение от Shaolinka Посмотреть сообщение
    Если мне не изменяет память, то использовав формат в надежде записать: Лицензии игрока %s, ник не будет передан, ибо формат при записи в массив новых данных, чистит его от старых. Поэтому гораздо-более благонадежнее было бы создать отдельное хранилище под ник.
    format будет использовать значения, которые ему будут переданы. То есть заполнение стека произойдет в обратном направлении от записи параметров, поэтому output_string будет иметь свое значение до записи в себя-же.
    Пример (обе функции дадут одинаковый результат):
    1. stock Function()
    2. {
    3. new str[5+1];
    4. for(new i; i < sizeof(str); i++) {
    5. format(str, sizeof(str), "%s%i", str, i);
    6. }
    7. printf("%s", str); // Output: 01234
    8. }
    9.  
    10. stock Function2()
    11. {
    12. new str[5+1],
    13. str_val[1+1];
    14. for(new i; i < sizeof(str); i++) {
    15. valstr(str_val, i);
    16. strcat(str, str_val);
    17. }
    18. printf("%s", str); // Output: 01234
    19. }
    Последний раз редактировалось punkochel; 24.01.2023 в 19:49.

  7. Пользователь сказал cпасибо:
    ex4mpl3 (25.01.2023)
  8. #5
    Аватар для ex4mpl3
    Пользователь

    Статус
    Оффлайн
    Регистрация
    24.01.2023
    Сообщений
    2
    Репутация:
    0 ±
    Помогло, спасибо всем за помощь и советы

    - - - Добавлено - - -

    но если речь о перечислении, то придётся тогда уж либо циклом присваивать всем элементам той или иной статус(вариант не из лучших), либо же создавать массив на n кол-во элементов(MAX_LICENSES_TYPE), устанавливая всем элементам false статус.
    Не понял какая разница, ведь если даже перечислитель - всё равно сработает.

    1. new bool: g_players_licenses[MAX_PLAYERS][E_LICENSES_TYPE] = {{false, ...}, ...};

  9. #6
    Аватар для punkochel
    Пользователь

    Статус
    Оффлайн
    Регистрация
    08.12.2018
    Адрес
    Россия
    Сообщений
    146
    Репутация:
    25 ±
    Цитата Сообщение от ex4mpl3 Посмотреть сообщение
    Не понял какая разница, ведь если даже перечислитель - всё равно сработает.
    1. new bool: g_players_licenses[MAX_PLAYERS][E_LICENSES_TYPE] = {{false, ...}, ...};
    Сработает, но pawn уже по умолчанию установит 0/false для значения переменной/массива.
    Хотя это актуально и для Си, за исключением локальных переменных. Поэтому непонятно откуда такой формат.
    Это просто будет более лаконичнее выглядеть, и любому сразу станет ясно что тут хранятся false:
    1. new bool:g_players_licenses[MAX_PLAYERS][E_LICENSES_TYPE];

 

 

Информация о теме

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

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •