我是C的新手,在使用malloc时遇到了一个奇怪的行为。
我从stdin(fgets)读取输入文本,并将其传递给函数myfunction。
void myfunction(char* src) {
printf("src: |%s|n", src);
int srcLength = strlen(src);
printf("src length: %dn", srcLength);
// CAUSES ODD BEHAVIOR IN MY SITUATION
// char* output = malloc(200);
//
// if (output == NULL) {
// exit(EXIT_FAILURE);
// }
for (int i=0; i < srcLength; ++i) {
char currChar = src[i];
printf("|%c| ", currChar);
}
}
当执行没有malloc的函数时(见注释),我得到的是:
src: |asdf|
src length: 4
|a| |s| |d| |f|
但有了malloc,我就有了这种尴尬的行为。就好像字符中没有字符一样*:
src: |asdf|
src length: 4
|| || || ||
char*src(来自stdin)可能有问题。但我不确定,因为输入字符串打印正确(src: |asdf|
)。
有人能支持我吗,如何分析问题的根源?
更新1:
以下是从stdin读取并调用myfunction的代码。
int main(int argc, char **argv) {
char *input = NULL;
input = readStdin();
myfunction(input);
return EXIT_SUCCESS;
}
char* readStdin(void) {
char buffer[400];
char *text = fgets(buffer, sizeof(buffer), stdin);
return text;
}
myfunction
和readStdin
在不同的文件中,但我希望这无关紧要。
更新2:
正如支持者在评论中提出的那样,我解决了范围问题。
我将readStdin
的功能原型更改为:
char* readStdin(char* input);
并且我用分配的input
调用readStdin
。
char* input = malloc(400);
在readStdin
中,我用函数参数替换了buffer
。
使用malloc 时的奇怪行为
是的,这很奇怪。。。。或者也许不是。你的代码有未定义的行为,所以一切都可能发生。
问题是,如果fgets
成功,text
最终将成为指向buffer
的指针。但是buffer
是函数中的局部变量,所以一旦readStdin
返回,变量buffer
就不存在了。因此,您向myfunction
传递了一个无效指针,并且当您使用它(即用于读/写)时,您有未定义的行为。
一旦你有了未定义的行为,就没有理由对正在发生的事情进行推理……但如果我们无论如何都试图这样做,对大多数系统的一个可能解释是:
buffer
位于堆栈上。当readStdin
返回时,堆栈指针递减(或递增),因此buffer
现在位于堆栈的未使用部分。当你调用一个新函数时,这个新函数也需要一些堆栈空间。多少取决于函数使用的变量数量。换句话说,变量越多,需要的堆栈空间就越多。由于新变量将覆盖堆栈的某些部分,从而覆盖内存中保存过时buffer
变量的部分,因此buffer
的破坏量可能会随着函数调用中变量的数量而变化。这可能就是你所看到的。
但请注意,以上解释是系统特定的。它不是C标准规定的。尽管如此,大多数系统都是这样工作的。
该怎么办?
代替
char buffer[400];
进行
char* buffer = malloc(400);
正如许多人在评论中所说,您存在范围问题。为了避免这种情况,您需要在readStdin()
中分配内存。引用评论中的@MOehm
一旦您离开readStdin,缓冲区将无效。访问它是未定义的行为,您应该避免这种行为。(我想问题不在于malloc,而在于额外的变量输出,它恰好占用了之前由缓冲区占用的部分空间,从而损坏了它。)
#define SIZE 400
char* readStdin(void) {
char buffer[SIZE];
char *text = NULL
fgets(buffer, sizeof(buffer), stdin);
text = malloc(sizeof(char) * (strlen(buffer) + 1));//allocate memory
strcpy(text, buffer);//and copy the buffer into it.
int length = strlen(text);
if (text[length - 1] == 'n') {
text[length - 1] = ' ';
}
return text;
}
现在你的主要功能应该是这样的:
int main(int argc, char *argv[])
{
char *input = NULL;
input = readStdin();
myfunction(input);
free(input);//must now free it.
input = NULL;
return EXIT_SUCCESS;
}
试着做出这些改变,你会发现你所有的问题都会消失。现在MyFunction
将按预期工作。
我不明白为什么在执行char* output = malloc(200);
时不会出现编译错误:必须转换为char*
,就像char* output = (char*) malloc(200);
一样