为什么这段代码表现不可预测?

时间:2012-03-11 16:08:26

标签: c segmentation-fault malloc

我正在开发一款控制台游戏,其中包含以下代码:

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

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

pl *players;
planet plan[22];

pl *玩家使用

进行malloc
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是玩家的数量。这个想法是这个代码循环遍历所有玩家,检查他们是否正在旅行,如果是,则打印一条消息,说明他们的目的地。 这有十分之九的工作效果,但有时会在free(tmp)时出现分段错误,它会在malloc或者打印时产生段错误

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

为什么会这样做,我该如何解决?

知道我在两年前的笔记本电脑上使用Arch Linux可能会有所帮助。

3 个答案:

答案 0 :(得分:0)

sizeof(plan[ players[i].location ].name)中,您正在使用指针大小。 你可能想要最大行星名称的大小......

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

VS

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

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

答案 1 :(得分:0)

弱点在于(过于复杂)的内存分配。

由于你的tmp缓冲区是临时的,我宁愿使用基于堆栈的缓冲区,使用你的复杂sizeof()尝试分配的最大空间(作为奖励,这将比malloc()/free()更快)。

只是不要声明它static所以几个线程可以一起工作。

答案 2 :(得分:0)

你没有为你的星球名称可靠地分配足够的空间,因为你正在使用指针的大小,而不是它所指向的字符串的长度。

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

这是4或8(取决于您使用的是32位还是64位系统)。

您可能需要使用此功能,可能需要使用+1,而不是:

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

你得到的是准随机效应,因为你的行星名称大多数都足够短,当与分配总结等结合使用时,你实际上有足够的空间。当你处理一个长行星名称时,你就会遇到麻烦。

分配向上发生是因为大多数分配器以某个最小大小为单位分配空间,这可能是8或16(或甚至32个)字节。因此,当您请求17个字节时,实际上可能会给出一个指向24个字节甚至32个字节的指针,如果溢出所请求的17个字节足以超过舍入大小,则只会遇到严重问题。你永远不应该依赖于综合,因此你不应该访问你所要求范围之外的内存;然而,它经常发生。