我正在开发一款主机游戏,其中有以下代码:
typedef struct player{
char *name;
/* ... */
char location;
char traveltime;
/* ... */
}pl;
typedef struct planet{
char *name;
/* ... */
}planet;
pl *players;
planet plan[22];
pl*玩家被搞砸了
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, ".. ");
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可能会有所帮助。
在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 :) */
弱点在于(过于复杂的)内存分配。
由于tmp
缓冲区是临时的,我宁愿使用基于堆栈的缓冲区,使用您的卷积sizeof()试图分配的最大空间(作为奖励,这将比malloc()/free()
更快)。
只是不要声明它为static
,这样几个线程就可以一起工作。
您不能可靠地为行星名称分配足够的空间,因为您采用的是指针的大小,而不是它所指向的字符串的长度。
sizeof(plan[ players[i].location ].name)
这是4或8(取决于您使用的是32位系统还是64位系统)。
您可能需要使用它,可能与+1
一起使用:
strlen(plan[player[i].location].name)
你会得到准随机效应,因为你的大多数行星名称都足够短,当与分配汇总等相结合时,你实际上有大约足够的空间。当你处理一个很长的行星名称时,你就会遇到麻烦。
发生分配四舍五入是因为大多数分配器以某个最小大小的单位分配空间,该最小大小可能是8或16(甚至可能是32)个字节。因此,当你请求17个字节时,实际上可能会给你一个指向24甚至32个字节的指针,只有当你请求的17个字节溢出到超过四舍五入的大小时,你才会遇到严重的问题。您永远不应该依赖于四舍五入,因此您不应该访问超出您请求范围的内存;尽管如此,这种情况还是经常发生。