使用 malloc 时的奇怪行为
Odd behaviour when using malloc
我是 C 的新手,在使用 malloc 时遇到了一个奇怪的行为。
我从标准输入 (fgets) 读取输入文本并将其传递给函数 myfunction。
void myfunction(char* src) {
printf("src: |%s|\n", src);
int srcLength = strlen(src);
printf("src length: %d\n", 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,我遇到了这种尴尬的行为。好像 char*:
中没有字符
src: |asdf|
src length: 4
|| || || ||
char* src(来自标准输入)可能有问题。但我不确定,因为输入字符串打印正确 (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
。
正如许多人在评论中所说,您遇到了范围问题。为避免这种情况,您需要在 readStdin()
内分配内存。引用@MOehm 的评论
Once you've left readStdin, buffer becomes invalid. Accessing it is undefined behaviour, which you should avoid. (I guess that the problem is not the malloc, but the additional variable output, which happens to occupy part of the space that was previously occupied by buffer, thus corrupting it.)
#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] = '[=10=]';
}
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
将按预期工作。
Odd behaviour when using malloc
是的,这很奇怪……也许不是。您的代码具有未定义的行为,因此一切都可能发生。
问题是,如果 fgets
成功,text
最终将作为指向 buffer
的指针。但是 buffer
是函数中的局部变量,所以一旦 readStdin
returns 变量 buffer
不再存在。因此,您向 myfunction
传递了一个无效指针,当您使用它时(即对于 read/write),您有未定义的行为。
一旦你有未定义的行为,就没有意义去推理正在发生的事情......但如果我们尝试这样做,对大多数系统的可能解释是:
buffer
位于堆栈上。当 readStdin
returns 时,堆栈指针递减(或递增),因此 buffer
现在位于堆栈的未使用部分。当你调用一个新函数时,新函数也会需要一些堆栈space。多少取决于函数使用的变量数量。换句话说 - 变量越多,需要的堆栈 space 就越多。由于新变量将覆盖堆栈的某些部分 - 从而覆盖保存过时 buffer
变量的部分内存 - buffer
的破坏量可能会随着函数调用中变量的数量而变化.这可能就是你看到的。
但请注意,上面的解释是系统特定的。它不是 C 标准指定的内容。尽管如此,这仍然是大多数系统的工作方式。
怎么办?
而不是
char buffer[400];
做
char* buffer = malloc(400);
我不明白为什么在执行 char* output = malloc(200);
时不会出现编译错误:您必须转换为 char*
,例如 char* output = (char*) malloc(200);
我是 C 的新手,在使用 malloc 时遇到了一个奇怪的行为。
我从标准输入 (fgets) 读取输入文本并将其传递给函数 myfunction。
void myfunction(char* src) {
printf("src: |%s|\n", src);
int srcLength = strlen(src);
printf("src length: %d\n", 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,我遇到了这种尴尬的行为。好像 char*:
中没有字符src: |asdf|
src length: 4
|| || || ||
char* src(来自标准输入)可能有问题。但我不确定,因为输入字符串打印正确 (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
。
正如许多人在评论中所说,您遇到了范围问题。为避免这种情况,您需要在 readStdin()
内分配内存。引用@MOehm 的评论
Once you've left readStdin, buffer becomes invalid. Accessing it is undefined behaviour, which you should avoid. (I guess that the problem is not the malloc, but the additional variable output, which happens to occupy part of the space that was previously occupied by buffer, thus corrupting it.)
#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] = '[=10=]';
}
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
将按预期工作。
Odd behaviour when using malloc
是的,这很奇怪……也许不是。您的代码具有未定义的行为,因此一切都可能发生。
问题是,如果 fgets
成功,text
最终将作为指向 buffer
的指针。但是 buffer
是函数中的局部变量,所以一旦 readStdin
returns 变量 buffer
不再存在。因此,您向 myfunction
传递了一个无效指针,当您使用它时(即对于 read/write),您有未定义的行为。
一旦你有未定义的行为,就没有意义去推理正在发生的事情......但如果我们尝试这样做,对大多数系统的可能解释是:
buffer
位于堆栈上。当 readStdin
returns 时,堆栈指针递减(或递增),因此 buffer
现在位于堆栈的未使用部分。当你调用一个新函数时,新函数也会需要一些堆栈space。多少取决于函数使用的变量数量。换句话说 - 变量越多,需要的堆栈 space 就越多。由于新变量将覆盖堆栈的某些部分 - 从而覆盖保存过时 buffer
变量的部分内存 - buffer
的破坏量可能会随着函数调用中变量的数量而变化.这可能就是你看到的。
但请注意,上面的解释是系统特定的。它不是 C 标准指定的内容。尽管如此,这仍然是大多数系统的工作方式。
怎么办?
而不是
char buffer[400];
做
char* buffer = malloc(400);
我不明白为什么在执行 char* output = malloc(200);
时不会出现编译错误:您必须转换为 char*
,例如 char* output = (char*) malloc(200);