Malloc不断返回相同的指针

时间:2012-12-03 02:56:55

标签: c pointers malloc

我有一些C代码来解析文本文件,先逐行解析然后再写入标记

这是逐行解析它的函数:

int parseFile(char *filename) {
//Open file
FILE *file = fopen(filename, "r");
//Line, max is 200 chars
int pos = 0;
while (!feof(file)) {
    char *line = (char*) malloc(200*sizeof(char));
    //Get line
    line = fgets(line, 200, file);
    line = removeNewLine(line);
    //Parse line into instruction
    Instruction *instr = malloc(sizeof(instr));
    instr = parseInstruction(line, instr);
    //Print for clarification
    printf("%i: Instr is %s arg1 is %s arg2 is %s\n", 
        pos,
        instr->instr,
        instr->arg1,
        instr->arg2);
    //Add to end of instruction list
    addInstruction(instr, pos);
    pos++;
    //Free line
    free(line);
}
return 0;

}

这是将每一行解析为一些标记并最终将其放入一个Instruction结构中的函数:

Instruction *parseInstruction(char line[], Instruction *instr) {
//Parse instruction and 2 arguments
char *tok = (char*) malloc(sizeof(tok));
tok = strtok(line, " ");
printf("Line at %i tok at %i\n", (int) line, (int) tok);
instr->instr = tok;
tok = strtok(NULL, " ");
if (tok) {
    instr->arg1 = tok;
    tok = strtok(NULL, " ");
    if(tok) {
        instr->arg2 = tok;
    }
}
return instr;

}

ParseInstruction中的行printf("Line at %i tok at %i\n", (int) line, (int) tok);总是打印相同的两个值,为什么这些指针地址永远不会改变?我已经确认parseInstruction每次都返回一个唯一的指针值,但是每个指令在它的instr插槽中都有相同的指针。

为了清楚起见,指令定义如下:

typedef struct Instruction {

char *instr;
char *arg1;
char *arg2;

}指示;

我做错了什么?

4 个答案:

答案 0 :(得分:4)

这就是strtok的工作原理:它实际上修改了它所操作的字符串,用'\0'替换了分隔符,并将指针返回到该字符串。 (参见the "BUGS" section in the strtok(3) manual page,虽然这不是一个真正的错误,只是一种人们通常不会期望的行为。)因此,您的初始tok将始终指向{{的第一个字符。 1}}。

顺便说一下,这个:

line

首先将char *tok = (char*) malloc(sizeof(tok)); tok = strtok(line, " "); 设置为指向tok的返回值,然后将其重新指定为指向malloc的返回值,从而完全放弃返回值strtok。这就像写这个:

malloc

完全丢弃int i = some_function(); i = some_other_function(); 的返回值;除了它更糟糕,因为丢弃some_function()的返回值会导致memory leak

答案 1 :(得分:2)

我可以在代码中看到一些问题。最令人震惊的是parseInstruction

char *tok = (char*) malloc(sizeof(tok));
tok = strtok(line, " ");

在这里,您为tok分配内存,但是然后将tok设置为等于strtok的结果,这有效地使您分配的内存无法访问(它从未使用过)。这不仅是内存泄漏,而且意味着tok == line将始终为真,因为strtok返回指向第一个标记的指针(当使用第一个参数调用时!= {{1通常是字符串的开头。)

这解释了你的第一个问题(价值是相同的)。至于你的值在重复迭代中总是总是的问题,Edmund的答案总结得很好:完全是偶然的,你是自由的,并且在同一块内存中使用malloc。 / p>

你应该摆脱NULL行,然后让char *tok = malloc(...)按照预期对字符串进行操作。这将修复你的内存泄漏。您仍会在打印中看到相同的值,因为这是strtok的工作原理。

你最终会遇到这个代码的一个严重问题是你用指针指向指向{{1的内存空间的指令结构。 }} 的。这在循环的每次迭代期间都可以正常工作,但是当你在每次迭代结束时释放时,那个内存消失了,只有其他人才能回收。现在可能会因快乐事故而奏效,但最终你会SEGFAULT到处都是。{{3}}。如果你希望每个strtok拥有自己的私有内存,你会想要做更多这样的事情:

line

这里的要点是,你希望struct Instruction结构中每个字段的一大块内存,大小为// You already do this part, but with a bug; use this code instead Instruction *instr = (Instruction *)malloc(sizeof(Instruction)); // Then, inside parseInstruction, make these relevant changes instr->instr = (char *)malloc(strlen(tok) + 1); strcpy(instr->instr, tok); instr->arg1 = (char *)malloc(strlen(tok) + 1); strcpy(instr->arg1, tok); instr->arg2 = (char *)malloc(strlen(tok) + 1); strcpy(instr->arg2, tok); (“+1”代表NUL字节),然后将字符串复制到新的内存中。

到了免费的时候,请确保你释放所有的内存:

malloc

还有一些其他事情可以用来清理你的代码(例如,你的许多作业是不必要的:strlen(...) + 1// free each field free(instr->instr); free(instr->arg1); free(instr->arg2); // free the struct itself free(instr); 具有相同的效果),但这应该是让你走上正确的轨道。

答案 2 :(得分:1)

必须是sizeof(char)而不是sizeof(tok)

纠正它

char *tok = (char*) malloc(sizeof(tok));
    to

char *tok = (char*) malloc(sizeof(char));

答案 3 :(得分:1)

你为一条线分配内存,处理它,然后释放它。 (你还为指令分配了其他内存,但是没有释放它,但这是独立的。)

当您从线路中释放内存时,会发生一个大小为200个字符的洞(加上一些簿记空间)。您正在使用的malloc找到此漏洞,并在下次循环时重复使用它。

这些都是单独的分配,但它恰好发生在内存中的相同空间被重用于每个。当然,这应当被视为事故:您所做的其他分配的更改可能会改变它。