c-马洛克不断返回相同的指针



我有一些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 %sn", 
pos,
instr->instr,
instr->arg1,
instr->arg2);
//Add to end of instruction list
addInstruction(instr, pos);
pos++;
//Free line
free(line);
}
return 0;

}

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

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 %in", (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 %in", (int) line, (int) tok);行总是打印相同的两个值,为什么这些指针地址永远不会改变?我已经确认parseInstruction每次都返回一个唯一的指针值,但每条指令的instr槽中都有相同的指针。

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

typedef struct Instruction {
char *instr;
char *arg1;
char *arg2;

}说明书;

我做错了什么?

strtok就是这样工作的:它实际上修改了正在操作的字符串,用''替换分隔符,并返回指向该字符串的指针。(请参阅strtok(3)手册页中的"BUGS"部分,尽管这并不是一个真正的错误,只是人们通常不会期望的行为。)因此,您的初始tok将始终指向line的第一个字符。

顺便说一下,这个:

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

首先将tok设置为指向malloc的返回值,然后将其重新分配给指向strtok的返回值的点,从而完全丢弃malloc的返回值。就像写这个一样:

int i = some_function();
i = some_other_function();

完全丢弃CCD_ 11的返回值;除了更糟之外,因为丢弃malloc的返回值会导致内存泄漏。

代码中有一些问题。最令人震惊的是parseInstruction:

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

在这里,您为tok分配内存,但随后将tok设置为等于strtok的结果,这实际上会使您分配的内存无法访问(它从未使用过)。这不仅是内存泄漏,而且意味着tok == line将始终为true,因为strtok返回一个指向第一个令牌的指针(当使用第一个参数!=NULL调用时,它通常是字符串的开头)。

这就解释了你的第一个问题(价值观是相同的)。关于你的值在重复迭代中总是相同的问题,Edmund的回答很好地总结了这一点:完全是偶然的,你在释放和破坏同一块内存。

您应该去掉char *tok = malloc(...)行,只需让strtok按预期对字符串进行操作即可。这将修复你的内存泄漏。不过,您在打印输出中仍然会看到相同的值,因为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);

这里的要点是,您希望为结构中的每个字段malloc一个新的内存块,大小为strlen(...) + 1("+1"表示NUL字节),然后将字符串复制到该新内存中。

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

// free each field
free(instr->instr);
free(instr->arg1);
free(instr->arg2);
// free the struct itself
free(instr);

还有一些其他的事情可以用来清理代码(例如,你的很多赋值都是不必要的:fgets(line, 200, file)line = fgets(line, 200, file)有相同的效果),但这应该会让你走上正轨。

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

纠正

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

您为一行分配内存,处理它,然后释放它。(您也为指令分配其他内存,但不释放它,但这是单独的。)

实际情况是,当你从行中释放内存时,会有一个200个字符大小的洞(加上一些记账空间)。您使用的malloc会找到这个洞,并在循环中再次使用它。

这些都是单独的分配,但恰好每个分配都重用了内存中的相同空间。当然,这应该被视为一场意外:你所做的其他分配的改变可能会改变它

最新更新