Как правильно работать с двумерными массивами?

Сообщения
43
Реакции
1
Предупреждения
5
В условиях одномерного массива все более-менее ясно, а вот двумерный у меня почему-то с каждым оборотом while перезаписывается. По сути мой код принимает новые записи в следующую ячейку массива и затирает предыдущие.

Представьте, пожалуйста, пример кода, который правильно заполнит двумерный массив из файла через цикл while. Спасибо.

Код:
new arr[32][64];
/* Суть такова:
[1] - Раздел 1
[1][1] - Раздел 1, Пункт 1.
*/
 
  • Нравится
Реакции: ssx
Сообщения
1,082
Реакции
58
Помог
11 раз(а)
VasyaVas990, вот пример с циклом for
Код:
FillingArray() {
    new
        Array[6][6],
        Size = sizeof iBuffer;

    for(new i, p; i < Size; ++i) {
        for(p = 0; p < Size; ++p)
            Array[i][p] = random(255);
    }
}
 

fgd

Сообщения
92
Реакции
25
Помог
12 раз(а)
VasyaVas990
C++:
new Float:fOrigin[3];

ReadFIle()
{
    //szData = путь к файлу.
    new file = fopen(szData, "r");
    
    if(file)
    {
        new szOrigin[3][32];
        while(!feof(file))
        {
            fgets(file, szData, charsmax(szData));
            trim(aData);
            
            if(szData[0] == EOS || szData == ';')
                continue;
            
            if(szData[0] == '"')
            {
                parse(szData, szOrigin[0], charsmax(szOrigin[]), szOrigin[1], charsmax(szOrigin[]), szOrigin[2], charsmax(szOrigin[]);
                
                fOrigin[0] = str_to_float(szOrigin[0]);     
                fOrigin[1] = str_to_float(szOrigin[1]);     
                fOrigin[3] = str_to_float(szOrigin[2]);     
            }
        }
        fclose(file);
    }
    else
    {
        server_print("Error opening file");
    }
}
 
Сообщения
1,082
Реакции
58
Помог
11 раз(а)
VasyaVas990
C++:
new Float:fOrigin[3];

ReadFIle()
{
    //szData = путь к файлу.
    new file = fopen(szData, "r");
   
    if(file)
    {
        new szOrigin[3][32];
        while(!feof(file))
        {
            fgets(file, szData, charsmax(szData));
            trim(aData);
           
            if(szData[0] == EOS || szData == ';')
                continue;
           
            if(szData[0] == '"')
            {
                parse(szData, szOrigin[0], charsmax(szOrigin[]), szOrigin[1], charsmax(szOrigin[]), szOrigin[2], charsmax(szOrigin[]);
               
                fOrigin[0] = str_to_float(szOrigin[0]);    
                fOrigin[1] = str_to_float(szOrigin[1]);    
                fOrigin[3] = str_to_float(szOrigin[2]);    
            }
        }
        fclose(file);
    }
    else
    {
        server_print("Error opening file");
    }
}
А как же вопрос про двумерный массив?
 

fgd

Сообщения
92
Реакции
25
Помог
12 раз(а)
Code_0xABC, как я должен объяснить что не так у него с двухмерным массивом, если он даже не показал как он выполняет эту обработку?
В условиях одномерного массива все более-менее ясно, а вот двумерный у меня почему-то с каждым оборотом while перезаписывается. По сути мой код принимает новые записи в следующую ячейку массива и затирает предыдущие.

Представьте, пожалуйста, пример кода, который правильно заполнит двумерный массив из файла через цикл while. Спасибо.

Код:
new arr[32][64];
/* Суть такова:
[1] - Раздел 1
[1][1] - Раздел 1, Пункт 1.
*/
 
Сообщения
43
Реакции
1
Предупреждения
5
Code_0xABC, как я должен объяснить что не так у него с двухмерным массивом, если он даже не показал как он выполняет эту обработку?
Вот фрагмент кода (if defined MODE). По переменным вывод работает как часы, а конкретным указателям ячейка (например [1] [1]) постоянно искажается. Ведь так же не должно быть, чтобы одна ячейка с каждым проходом цикла выводила разные результаты.

Код:
$1000$
$$2000$
$$$5000$
$$$cs_mansion
$$$ccs_militia
Мне не жалко опубликовать весь плагин, главное помогите проблему решить.
Код:
LoadMaps()
{
    // Переменные для корректной работы функции
    new buff[256], fp = fopen("addons/amxmodx/configs/maps.ini", "rt");
 
    // Если файл отсутствует, блокируем плагин и выводим сообщение в консоль сервера
    if(!fp) set_fail_state("File ^"addons/amxmodx/configs/maps.ini^" not found");

    // [Если объявлена константа] Показывать карты в зависимости от онлайна
    #if defined MAP_ON_PLAYERS
        new minpl[3], maxpl[3];
    #endif

    // [Если объявлена константа] Режим выбора сценария игры (карты)
    #if defined MODE_SCENARIES

        new szMenuMulti[64]
        formatex(szMenuMulti, 63, "%L", LANG_PLAYER, "TITLE_MENU");

        // До тех пор, пока файл не будет прочитан до конца
        while(!feof(fp))
        {
            // Читает строки из файла (файл, массив, куда будет помещена информация, максимальная длина массива)
            fgets(fp, buff, charsmax(buff));
         
            // Очистить пробелы; кавычки в полученных строках
            trim(buff); remove_quotes(buff);

            // Пропускаем строки с символами комментированиия или разделения
            if(!buff[0] || buff[0] == ';') continue;

            // Загружаем заголовки сценариев
            if(buff[0] == '[')
            {
                // Обнуляем счетчик для записи карт в свой сценарий
                g_iMapCount = 0;

                // Записываем заголовки
                parse(buff, g_sMapScenario[g_iMapScenarioCount], charsmax(g_sMapScenario[]));

                // [Если объявлена константа] Команда /maps в чате.
                #if defined MAPSMENU

                    // [Сценарии] Создать пункты меню со сценариями номинаций
                    menu_additem(g_iScenariesMenu, g_sMapScenario[g_iMapScenarioCount]);

                    // [Меню для сценариев карт] Создаем меню c картами под каждый конкретный сценарий
                    g_iMapsMenu[g_iMapScenarioCount] = menu_create(szMenuMulti, "mapsmenu_handler");
                    formatex(szMenuMulti, 63, "%L", LANG_PLAYER, "MENU_EXIT")
                    menu_setprop(g_iMapsMenu[g_iMapScenarioCount], MPROP_EXITNAME, szMenuMulti);
                    formatex(szMenuMulti, 63, "%L", LANG_PLAYER, "MENU_NEXT")
                    menu_setprop(g_iMapsMenu[g_iMapScenarioCount], MPROP_NEXTNAME, szMenuMulti);
                    formatex(szMenuMulti, 63, "%L", LANG_PLAYER, "MENU_PREV")
                    menu_setprop(g_iMapsMenu[g_iMapScenarioCount], MPROP_BACKNAME, szMenuMulti);

                    // С каждым проходом увеличиваем индекс g_sMapScenario[] на единицу
                    g_iMapScenarioCount++;

                #endif
         
            }else
            {
                // [Если объявлена константа] Показывать карты в зависимости от онлайна
                #if defined MAP_ON_PLAYERS

                    // Получаем нужные аргументы с файла по отдельности (текст для разбивки по аргументам, первый оргумент, второй...)
                    parse(buff, g_sMapScenario[g_iMapScenarioCount][g_iMapCount], charsmax(g_sMapScenario[]), minpl, charsmax(minpl), maxpl, charsmax(maxpl));

                #else

                    // Получаем нужные аргументы по отдельности (текст для разбивки по аргументам, первый оргумент, второй...)
                    parse(buff, g_sMapScenario[g_iMapScenarioCount][g_iMapCount], charsmax(g_sMapScenario[]));
                 
                    // Если отсутствует карта на сервере или (функция ниже) была заблокирована, или не совпадает с ожидаемой - пропускаем
                    if(!is_map_valid(g_sMapScenario[g_iMapScenarioCount][g_iMapCount]) || _is_map_blocked(g_sMapScenario[g_iMapScenarioCount][g_iMapCount]) || !strcmp(g_sMapScenario[g_iMapScenarioCount][g_iMapCount], g_sCurMap)) continue;

                #endif

                // [Если объявлена константа] Показывать карты в зависимости от онлайна
                #if defined MAP_ON_PLAYERS
             
                    // Записываем минимальный, максимальный порог карты (для показа игроку)
                    g_MapPlayerData[g_iMapScenarioCount][g_iMapCount][1] = str_to_num(minpl);
                    g_MapPlayerData[g_iMapScenarioCount][g_iMapCount][2] = str_to_num(maxpl);

                #endif

                // [Если объявлена константа] Команда /maps в чате.
                #if defined MAPSMENU

                    /* [Карты] Создаем пункты меню
                        1. Идентификатор меню
                        2. Название пункта */
                    menu_additem(g_iMapsMenu[g_iMapScenarioCount -1], g_sMapScenario[g_iMapScenarioCount][g_iMapCount]);

                #endif

                server_print(g_sMapScenario[g_iMapScenarioCount][g_iMapCount]);
            }

            // Запоминает количество имеющихся карт в файле
            g_iMapCount++;
        }

    #else

        // До тех пор, пока файл не будет прочитан до конца
        while(!feof(fp) && g_iMapCount < MAX_MAPS)
        {
            // Читает строки из файла (файл, массив, куда будет помещена информация, максимальная длина массива)
            fgets(fp, buff, charsmax(buff));
         
            // Очистить пробелы; кавычки в полученных строках
            trim(buff); remove_quotes(buff);

            // Пропускаем строки с символами комментированиия или разделения
            if(!buff[0] || buff[0] == ';' || buff[0] == '[') continue;

            // [Если объявлена константа] Показывать карты в зависимости от онлайна
            #if defined MAP_ON_PLAYERS

                // Получаем нужные аргументы по отдельности (текст для разбивки по аргументам, первый оргумент, второй...)
                parse(buff, g_sMap[g_iMapCount], charsmax(g_sMap[]), minpl, charsmax(minpl), maxpl, charsmax(maxpl))

            #else

                // Получаем нужные аргументы по отдельности (текст для разбивки по аргументам, первый оргумент, второй...)
                if(parse(buff, g_sMap[g_iMapCount], charsmax(g_sMap[])))
                {
                    // Если отсутствует карта на сервере или (функция ниже) была заблокирована, или не совпадает с ожидаемой - пропускаем
                    if(!is_map_valid(g_sMap[g_iMapCount]) || _is_map_blocked(g_sMap[g_iMapCount]) || !strcmp(g_sMap[g_iMapCount], g_sCurMap)) continue;
                }

            #endif

            // [Если объявлена константа] Показывать карты в зависимости от онлайна
            #if defined MAP_ON_PLAYERS
         
                // Записываем минимальный, максимальный порог карты (для показа игроку)
                g_MapPlayerData[g_iMapCount][1] = str_to_num(minpl);
                g_MapPlayerData[g_iMapCount][2] = str_to_num(maxpl);
            #endif

            // [Если объявлена константа] Команда /maps в чате.
            #if defined MAPSMENU

                // Создать пункт для меню номинации
                menu_additem(g_iMapsMenu, g_sMap[g_iMapCount]);
            #endif

            // Запоминает количество имеющихся карт в файле
            g_iMapCount++;
        }
    #endif



    // Закрываем файл
    fclose(fp);

    // Если никаких данных обработано не было
    if(!g_iMapCount)
 
        // Блокируем плагин с сообщением в консоли сервера
        set_fail_state("[Load Maps] Nothing loaded. Plugin stopped!");
     
    // Иначе если в файле с картами была объявлена лишь одна карта
    else if(g_iMapCount == 1)
     
        // Блокируем плагин с сообщением в консоли сервера
        set_fail_state("[Load Maps] Critical loaded maps. Add maps in ^"addons/amxmodx/configs/maps.ini^". Plugin stopped!");

    // Иначе если количество объявленных карт меньше необходимого количества кандидатов для голосования
    else if(g_iMapCount < SELECTMAPS)
 
        // Отправляем заметку в указанный файл (отсутствует, автоматически создастся)
        log_to_file("lite_mapchooser.log", "[Load Maps] WARNING! Too little maps for voting! [Load: %d / Min: %d]", g_iMapCount, SELECTMAPS);

}
 
Последнее редактирование:
Сообщения
1,082
Реакции
58
Помог
11 раз(а)
VasyaVas990, до сих пор твои объяснения не понятны, что у тебя не так
 
Последнее редактирование:
Сообщения
673
Реакции
242
Помог
11 раз(а)
чувак не усложняй себе жизнь, зачем постоянно хранить данные в памяти, используй Array массив
Array - динамичный массив. В отличие от обычных двумерных массивов, где нужно указывать длину строки и кол-во самих строк, в динамичных нужно указать только длину строки, т.е. они имеют неограниченный размер. Это может быть полезным, к примеру, при получении информации из файла

( Массивы (Array и Trie) • Русское сообщество по скриптингу AMXX/SM/Metamod (amx-x.ru) )



Код:
\\Ячейки в файле
enum _:DATA_MODELS_PRECACHE
{
    DISCRIPTION[64],
    MODEL_CT[64],
    MODEL_TT[64]
}

new Array:g_aModelsArray;
new g_iDigitalStoreListSize;
public plugin_precache()
{
    new szCfgDir[64], szCfgFile[128];
    get_localinfo("amxx_configsdir", szCfgDir, charsmax(szCfgDir));
    formatex(szCfgFile, charsmax(szCfgFile), "%s/files.ini", szCfgDir);
    if(file_exists(szCfgFile))
    {
        new aDataModelsRead[DATA_MODELS_PRECACHE], szBuffer[256], iLine, iLen;
        g_aModelsArray = ArrayCreate(DATA_MODELS_PRECACHE);

        while(read_file(szCfgFile, iLine++, szBuffer, charsmax(szBuffer), iLen))
        {
            if(!iLen || szBuffer[0] == ';') continue;
            parse
            (
            szBuffer,
            aDataModelsRead[DISCRIPTION],         charsmax(aDataModelsRead[DISCRIPTION]),
            aDataModelsRead[MODEL_CT],             charsmax(aDataModelsRead[MODEL_CT]),
            aDataModelsRead[MODEL_TT],            charsmax(aDataModelsRead[MODEL_TT])
            );
            
            ArrayPushArray(g_aModelsArray, aDataModelsRead);
            
        }
        g_iDigitalStoreListSize = ArraySize(g_aModelsArray);
    }
}


public Cmd_ModelsMenu(id)
{
    new aDataDayMode[DATA_MODELS_PRECACHE]
    
    for(new i; i < g_iDigitalStoreListSize; i++)
    {
        ArrayGetArray(g_aModelsArray, i, aDataDayMode);
    
        server_print("%s %s %s", aDataDayMode[DISCRIPTION], aDataDayMode[MODEL_CT], aDataDayMode[MODEL_TT])
    }
}
Код:
native get_user_level(pId);

//создаем аррей
new Array:g_aData;

//создаем структуру для Аррей, она будет инициализировать размер
//допустим я хочу чтобы аррей хранил ник игрока и его уровень умноженный на 2 (уровен по нативу беру)
enum eData_Players {
    Players_Name[32], //ник обычно на 32 символа
    Players_Level //exp это int, значит размер не нужен
}

public plugin_init() {
    
    //регистрируем аррей и выставляем ему наш размер
    g_aData = ArrayCreate(eData_Players);
    
    //регаем команду которая изменяет Players_Level, а именно умножает уровень уже на 3
    register_clcmd("say /level", "ClientCmd_MultiLevel");
    
    //выводим все записаные ячейки в консоль
    register_clcmd("say /get", "ClientCmd_GetArray");
}

public client_putinserver(pId) {
    //создаем массив и помещаем в него eData_Players, чтоб сформировать помещаемые данные для Аррей
    new aData[eData_Players];
    
    get_user_name(pId, aData[Players_Name], charsmax(aData[Players_Name])); //помещаем в наш временный массив ник, в ячейку Players_Name (она как раз на 32 символа)
    
    //помещаем в временный массив в ячейку  Players_Level уровень умноженный на 2
    aData[Players_Level] = get_user_level(pId) * 2;
    
    //теперь помещаем все сформированные данные в наш Аррей
    ArrayPushArray(g_aData, aData);
}

public ClientCmd_MultiLevel(pId) {
    new aData[eData_Players];
    new szName[32]; get_user_name(pId, szName, charsmax(szName));
    //нам нужно узнать какой столбец в Array пренадлеждит игроку. Проверяем ячейку по никам
    for(new iPos; iPos < ArraySize(g_aData); iPos++) { //ArraySize возвращает количество ячеек которые мы сохранили в него (с +1). Аналог sizeof
        //указываем ячейку и получаем из нее в aData данные (Name и Level)
        ArrayGetArray(g_aData, iPos, aData);
        if(equal(aData[Players_Name], szName)) {//если это ячейка игрока то переумножаем его уровень и сохраняем
            aData[Players_Level] = get_user_level(pId) * 3;
            //Push добавляет новую ячейку, а Set меняет существующую (обновляет ее значение)
            ArraySetArray(g_aData, iPos, aData);
            break;
        }
    }
}

public ClientCmd_GetArray(pId) {
    new aData[eData_Players];
    //по очереди получаем каждую ячейку из аррай и выводим её значения
    for(new iPos; iPos < ArraySize(g_aData); iPos++) { //ArraySize возвращает количество ячеек которые мы сохранили в него (с +1). Аналог sizeof
        //указываем ячейку и получаем из нее в aData данные (Name и Level)
        ArrayGetArray(g_aData, iPos, aData);
        client_print(pId, print_console, "Ник(Players_Name): %s, Уровень(Players_Level): %d", aData[Players_Name], aData[Players_Level]);
    }
}
 
Последнее редактирование:
Сообщения
43
Реакции
1
Предупреждения
5
Code_0xABC, ладно, я попробую тебе донести проблему на твоем языке. Ну раз ты не понимаешь моего вопроса, то проблема в Pawn или тебе.

Вот так из файла все записи выводится правильно и по порядку:
Код:
server_print(g_sMapScenario[g_iMapScenarioCount][g_iMapCount]);
А если посмотреть так (код ниже), то видно, что вторичные ячейки массива (то есть список карт) постоянно перезаписыаются:
Код:
server_print(g_sMapScenario[1][1]);
Так быть не должно. По сути, цикл должен был мне выводить одно название карты, а не все, что там есть. Тебе лень код посмотреть, зато меня тут осуждаешь. Горит от таких, ппц.
 

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

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