PDA

Просмотр полной версии : [Вопрос] Доступ к двухмерному массиву



oukibt
29.06.2021, 19:16
Как правильно получить в плагине доступ к двухмерному массиву?

Пример:


enum Info
{
Data1[10],
Data2,
};

native function(Array[][Info], size = sizeof array);

main()
{
new Array[][Info] = {

{ "228", 228 },
{ "100", 100 },
{ "1337", 1337 }
};

function(Array);
}

oukibt
30.06.2021, 00:02
С проблемой разобрался, но всё равно не понятно, как оно работает.

(Код на павн в посте сверху учитывается)


cell AMX_NATIVE_CALL Function(AMX *amx, cell *params)
{
cell* addr;
amx_GetAddr(amx, params[1], &addr);

int i, len;
char string[10];

// params[2] == размеру массива, в данном случае 3
// 10 - это размер массива (первого элемента) в энуменаторе
// 1 - размер второго элемента

for (i = params[2]; i < params[2] * (10 + 1) + params[2];)
{
amx_StrLen(&addr[i], &len);
amx_GetString(string, &addr[i], NULL, len + 1);

i += 10;

something = addr[i]; // addr[i] - это второй элемент энуменатора

i++;
}

return 1;
}


Каждую итерацию цикла, в string записывается первый, а в something второй элемент
И, как раз таки, не понятно, почему i начинается со значения params[2]

Daniel_Cortez
02.07.2021, 09:53
Суть в том, что в многомерных массивах данные располагаются не совсем обычным образом.
В двухмерных массивах перед содержимым массива указываются смещения до содержимого каждой строки второго измерения.
Например, если у нас есть такой массив:

new a[2][3] = {
{ 0xA, 0xB, 0xC },
{ 0xD, 0xE, 0xF }
};

то в файл *.amx попадёт следующее:

8 10 ; смещения (8 и 16 в десятичной системе)
a b c ; строка 0
d e f ; строка 1

Т.е. если требуется получить значение элемента a[1][2], то следует:
Взять адрес массива.
Прибавить номер строки 2-го измерения, умноженный на размер ячейки (в примере выше нужен элемент из 1-й строки; размер ячейки равен четырём; 1 * 4 = 4).
Прочесть значение из получившегося адреса (в примере выше это будет 10), это значение и будет смещением данных 2-й строки. Прибавить прочитанное значение к уже имеющемуся адресу.
Прибавить номер ячейки в 2-м измерении, умноженный на размер ячейки (в примере - 2 * 4 = 8).
Снова прочесть значение по получившемуся адресу. Это и будет значение из a[1][2].

Сделана эта галиматья со смещениями потому, что в Pawn строки последнего измерения могут заполняться не до конца.
Например, если сделать так:

new a[2][] = {
{ 0xA, },
{ 0xD, 0xE, 0xF }
};

то в *.amx попадёт:
8 8 a d e f
На крупных массивах это может здорово сэкономить память. Собственно, Pawn и разрабатывался с расчётом на микроконтроллеры, у которых обычно очень ограниченный объём памяти.