PDA

Просмотр полной версии : [Вопрос] Почему не записывается текст в многомерный массив?



execution
06.06.2019, 12:03
Не могу понять, почему не записывает в массив.



enum RecentPlayerAction
{
RPC_act_1[MAX_CHATBUBBLE_LENGTH + 1],
RPC_act_2[MAX_CHATBUBBLE_LENGTH + 1],
RPC_act_3[MAX_CHATBUBBLE_LENGTH + 1],
RPC_act_4[MAX_CHATBUBBLE_LENGTH + 1],
RPC_act_5[MAX_CHATBUBBLE_LENGTH + 1],
RPC_act_6[MAX_CHATBUBBLE_LENGTH + 1],
RPC_act_7[MAX_CHATBUBBLE_LENGTH + 1]
}

new
gRecentPlayerAction[MAX_PLAYERS][RecentPlayerAction],
NULL_gRecentPlayerAction[RecentPlayerAction]
;


При входе обнуляю



gRecentPlayerAction[playerid] = NULL_gRecentPlayerAction;


Сама запись:



stock AddRecentPlayerAction(playerid, const string[])
{
if(strlen(string) > MAX_CHATBUBBLE_LENGTH)
return 0;

for(new j = sizeof(gRecentPlayerAction[]), i = 0; i < j - 1;)
{
gRecentPlayerAction[playerid][RecentPlayerAction:i] = gRecentPlayerAction[playerid][RecentPlayerAction:++i];
}

new
h_, m_, s_;

gettime(h_, m_, s_);

format(stringer, sizeof stringer, "[%2d:%2d:%2d] %s",
h_, m_, s_, string);

strmid(gRecentPlayerAction[playerid][RecentPlayerAction:0], stringer, 0, MAX_CHATBUBBLE_LENGTH);

return 1;
}


(Проверял длину, не выходит за пределы MAX_CHATUBBLE_LENGTH)

DeimoS
06.06.2019, 12:42
Потому что ты не указал размер массива gRecentPlayerAction, а указал лишь размер строки.
strmid(gRecentPlayerAction[playerid][RecentPlayerAction:0], stringer, 0, MAX_CHATBUBBLE_LENGTH, MAX_CHATBUBBLE_LENGTH);
sizeof не умеет определять размер отдельного члена перечисления в многомерном массиве, из-за чего на месте размера массива оказывается 0, в результате чего данные и не записываются. Это относится ко всем функциям, работающим со строками (всегда, когда нужно работать с многомерными массивами, размер массива указывай явно, если того требует функция).

for(new j = sizeof(gRecentPlayerAction[]), i = 0; i < j - 1;)
Крайне странный цикл. Если "j" используется только в условии, гораздо практичнее делать так:
for(new i = 0; i < sizeof(gRecentPlayerAction[]) - 1;)
Ибо в твоём текущем варианте цикл каждую итерацию будет обращаться к переменной j, отнимать от неё единицу и только потом сравнивать, а в варианте с sizeof размер массива подставится на этапе компиляции и сравнение в цикле будет происходить с обычным числом, без всяких расчётов.



new
h_, m_, s_;

gettime(h_, m_, s_);

format(stringer, sizeof stringer, "[%2d:%2d:%2d] %s",
h_, m_, s_, string);

strmid(gRecentPlayerAction[playerid][RecentPlayerAction:0], stringer, 0, MAX_CHATBUBBLE_LENGTH);

Почему вот тут сразу не записать текст в массив gRecentPlayerAction? Зачем тут stringer?
new
h_, m_, s_;

gettime(h_, m_, s_);

format(gRecentPlayerAction[playerid][RecentPlayerAction:0], MAX_CHATBUBBLE_LENGTH+1, "[%2d:%2d:%2d] %s",
h_, m_, s_, string);



Чтоб не мучиться с тегами при работе с перечислением, можно сделать так:
enum _:RecentPlayerAction
{
RPC_act_1[MAX_CHATBUBBLE_LENGTH + 1],
RPC_act_2[MAX_CHATBUBBLE_LENGTH + 1],
RPC_act_3[MAX_CHATBUBBLE_LENGTH + 1],
RPC_act_4[MAX_CHATBUBBLE_LENGTH + 1],
RPC_act_5[MAX_CHATBUBBLE_LENGTH + 1],
RPC_act_6[MAX_CHATBUBBLE_LENGTH + 1],
RPC_act_7[MAX_CHATBUBBLE_LENGTH + 1]
}
Тогда не нужно будет указывать "RecentPlayerAction:" в случаях, когда обращаешься к ячейкам массива, а не членам перечисления

А что это вообще за система? Какое предназначение цикла внутри функции? Не особо похоже, что твой код будет работать так, как ты задумал, если судить по тому, как ты объявил массив и как потом с ним работаешь.

execution
06.06.2019, 15:06
Ибо в твоём текущем варианте цикл каждую итерацию будет обращаться к переменной j, отнимать от неё единицу и только потом сравнивать, а в варианте с sizeof размер массива подставится на этапе компиляции и сравнение в цикле будет происходить с обычным числом, без всяких расчётов.


Согласен, многие изменения вносились и не заметил.



А что это вообще за система? Какое предназначение цикла внутри функции? Не особо похоже, что твой код будет работать так, как ты задумал, если судить по тому, как ты объявил массив и как потом с ним работаешь.


Записывать последние действия игрока. Благодарю за помощь :thank_you:

UPD: Но почему-то всё равно не записывает :search:

DeimoS
06.06.2019, 16:04
Потому что ты неправильно записываешь данные? Точнее, не понимаешь как работают перечисления (enum).

В текущем виде:

enum RecentPlayerAction
{
RPC_act_1[MAX_CHATBUBBLE_LENGTH + 1],
RPC_act_2[MAX_CHATBUBBLE_LENGTH + 1],
RPC_act_3[MAX_CHATBUBBLE_LENGTH + 1],
RPC_act_4[MAX_CHATBUBBLE_LENGTH + 1],
RPC_act_5[MAX_CHATBUBBLE_LENGTH + 1],
RPC_act_6[MAX_CHATBUBBLE_LENGTH + 1],
RPC_act_7[MAX_CHATBUBBLE_LENGTH + 1]
}

new
gRecentPlayerAction[MAX_PLAYERS][RecentPlayerAction];

Твой массив будет равносилен такой записи:

new
gRecentPlayerAction[MAX_PLAYERS][1015];

А не такой:

new
gRecentPlayerAction[MAX_PLAYERS][7][MAX_CHATBUBBLE_LENGTH + 1];

И твой текущий цикл, во-первых, сам по себе работает неправильно, ибо ты значение следующей ячейки записываешь в текущую, а, во-вторых, будет смещать символы на одну ячейку вперёд, а не на "MAX_CHATBUBBLE_LENGTH + 1" ячеек, из-за чего следующая запись текста перезапишет весь прошлый текст.
В общем, тебе нужно разобраться с тем, как работают enum =)




Как-то так должно быть. Но не проверял
#define MAX_RECENT_PLAYER_ACTION 7

new gRecentPlayerAction[MAX_PLAYERS][MAX_RECENT_PLAYER_ACTION][MAX_CHATBUBBLE_LENGTH + 1];
new NULL_gRecentPlayerAction[MAX_CHATBUBBLE_LENGTH + 1];

stock ClearRecentPlayerAction(playerid)
{
for(new i; i < MAX_RECENT_PLAYER_ACTION; i++)
gRecentPlayerAction[playerid][i] = NULL_gRecentPlayerAction;
}

stock GetRecentPlayerAction(playerid, actionid)
{
return gRecentPlayerAction[playerid][actionid];
}


stock AddRecentPlayerAction(playerid, const string[])
{
for(new i = MAX_RECENT_PLAYER_ACTION-1; i != 0; i--)
{
if(isnull(gRecentPlayerAction[playerid][i-1]))
continue;
gRecentPlayerAction[playerid][i] = gRecentPlayerAction[playerid][i-1];
}

new h_, m_, s_;
gettime(h_, m_, s_);
format(gRecentPlayerAction[playerid][0], MAX_CHATBUBBLE_LENGTH, "[%2d:%2d:%2d] %s",
h_, m_, s_, string);
return 1;
}

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

А вот тебе функция определения последней занятой ячейки:
stock GetRecentPlayerActionLastID(playerid)
{
for(new i = MAX_RECENT_PLAYER_ACTION-1; i != 0; i--)
{
if(isnull(gRecentPlayerAction[playerid][i]))
continue;
return i;
}
return 0;
}

Использовать так:
for(new i, j = GetRecentPlayerActionLastID(playerid); i <= j; i++)
{
print(GetRecentPlayerAction(playerid, i));
}

execution
06.06.2019, 16:12
Понятно. Думал обойтись очищение массива без цикла, но увы. Спасибо ещё раз.

DeimoS
06.06.2019, 16:18
Там всего 7 итераций. Можешь обойтись без цикла

new gRecentPlayerAction[MAX_PLAYERS][MAX_RECENT_PLAYER_ACTION][MAX_CHATBUBBLE_LENGTH + 1];
new NULL_gRecentPlayerAction[MAX_RECENT_PLAYER_ACTION][MAX_CHATBUBBLE_LENGTH + 1];

stock ClearRecentPlayerAction(playerid)
{
gRecentPlayerAction[playerid] = NULL_gRecentPlayerAction;
}
но,как видишь, приходится в 7 раз больше памяти выделять. Не думаю, что избавление от цикла на 7 итераций стоит того. Вот если бы было хотя бы 1000 итераций и больше + очищение нужно было бы делать часто, тогда можно задуматься.