почему этот код ведет себя непредсказуемо? - PullRequest
0 голосов
/ 11 марта 2012

Я работаю над консольной игрой, в которой у меня есть следующие фрагменты кода:

typedef struct player{
        char *name;
        /* ... */
        char location;
        char traveltime;
        /* ... */
}pl;

typedef struct planet{
        char *name;
        /* ... */
}planet;

pl *players;
planet plan[22];

pl * проигрыватели malloc'd с

players=malloc(NPLAYERS*sizeof(pl));

где NPLAYERS - количество игроков. plan [] - это массив всех планет в игре.

players[i].location

- расположение игроков в качестве индекса для планирования [], если игроки [i] .traveltime == 0. Если игроки [i] .traveltime> 0, игрок отправляется к игроку [i] .location. Поэтому, когда игрок путешествует, я хочу отобразить окно ncurses с надписью «На пути к (планете)».

для этого я использую:

char *tmp, msg[]="PLAYER 1", i;
for(i=0; i!=NPLAYERS; ++i){
            infobox(msg);
            if( players[i].traveltime>0){
                    tmp=malloc( sizeof("en route to ")+sizeof(plan[ players[i].location ].name)+4)
                    strcpy(tmp, "en route to ");
                    strcat(tmp, plan[ players[i].location ].name);
                    strcat(tmp, "..\0");
                    infobox(tmp);
                    free(tmp);
            }
            ++msg[7];
  }

где infobox (char msg []) печатает окно ncurses, содержащее сообщение для stdout, а NPLAYERS - количество игроков. Идея состоит в том, что этот код перебирает всех игроков, проверяет, путешествуют ли они, и если да, печатает сообщение с указанием их пунктов назначения. Это работает девять из десяти раз, но иногда оно дает ошибку сегментации при свободном (tmp), это дает ошибку сегмента при malloc или печатает

    ***** glibc detected *** ./st: malloc(): memory corruption [a hex number] ***

после malloc. Почему это происходит и как я могу это решить?

Это может помочь узнать, что я использую Arch Linux на двухлетнем ноутбуке.

Ответы [ 3 ]

0 голосов
/ 11 марта 2012

Слабым местом является (слишком сложное) распределение памяти.

Поскольку ваш буфер tmp является временным, я бы предпочел использовать буфер на основе стека, используя максимальное пространство, которое ваш свернутый sizeof ()пытается выделить (в качестве бонуса это будет быстрее, чем malloc()/free()).

Только не объявляйте это static, чтобы несколько потоков могли работать вместе.

0 голосов
/ 11 марта 2012

Вы недостаточно надежно выделяете место для имен планет, потому что вы берете размер указателя, а не длину строки, на которую он указывает.

sizeof(plan[ players[i].location ].name)

Это 4 или8 (в зависимости от того, используете ли вы 32-разрядную или 64-разрядную систему).

Возможно, вам придется использовать это, возможно, с +1 вместо:

strlen(plan[player[i].location].name)

Вы получаете квазислучайные эффекты, потому что большинство названий ваших планет достаточно короткие, что в сочетании с округлением распределения и т. Д. У вас фактически достаточно места.Когда вы обрабатываете длинное имя планеты, вы начинаете сталкиваться с проблемами.

Сведение ресурсов происходит потому, что большинство распределителей выделяют пространство в единицах минимального размера, который может быть 8 или 16 (или, возможно, даже32) байта.Поэтому, когда вы запрашиваете, скажем, 17 байтов, вам может фактически быть дан указатель на 24 или даже 32 байта, и вы столкнетесь с серьезными проблемами только в том случае, если переполните 17 запрошенных вами байтов на столько, чтобы превысить округленный размер.Вы никогда не должны полагаться на округление, поэтому вы не должны получать доступ к памяти за пределами запрошенного вами диапазона;тем не менее, это обычно происходит.

0 голосов
/ 11 марта 2012

В sizeof(plan[ players[i].location ].name) вы берете размер указателя . Вы, вероятно, хотите использовать размер максимального имени планеты ...

    tmp=malloc( sizeof("en route to ")+sizeof(plan[ players[i].location ].name)+4);

против

    //tmp = malloc(13 + sizeof(char *) + 4);
    //tmp = malloc(17 + sizeof(char *));

    tmp = malloc(1700); /* arbitrary big enough value :) */
...