我试图为用户输入重新创建一个简单的String解析器。我可以毫无问题地获取输入字符串,并确定其中有多少单独的字符串,以正确地为malloc提供正确的大小。最初我没有在stdin中找到Strings的数量,只是重新分配我的String数组以允许多一个String的空间,然后malloc新的String。既然我有这个尺寸,我相信这不是必要的,因为我可以提供具有适当尺寸的malloc。
(尝试使用calloc(),在同一地点进行segfaulted)
我感到困惑的是,当我在我的代码中留下realloc时没有问题(除了知道它可能会以不合需要的方式调整我的数组)。但是,如果我删除realloc,我的代码段错误即时fgets()尝试执行。
这就是我调用解析器的地方,以及我的#includes。 " appserver.h"保存所有原型和std(lib / bool / io),string / unistd / limits.h
#include "appserver.h"
int main(int argc, char *argv[])
{
if(argc != 4)
{
exit(0);
}
struct userInput user = { parseInt(*argv[1]), parseInt(*argv[2]), argv[3] };
printf("> ");
char **newArgs = stringParser();
for (int i = 0; newArgs[i] != NULL; i++)
{
free(newArgs[i]);
}
free(newArgs);
}
以下是我的解析器代码。如果我将realloc取消注释,我可以毫无问题地逐步执行我的代码(在gdb节目中单步执行"输入"使用stdin中的整个字符串)但是,如果我将其注释掉,我会尝试检索fgets()中的用户输入。为什么注释掉realloc()甚至会影响fgets()?
char **stringParser()
{
char *input;
fgets(input, INT_MAX, stdin);
int size = numberOfStrings(input);
char **inputArray = malloc((size)*(sizeof(char*)));
inputArray[0] = malloc(sizeof(char*));
strcpy(inputArray[0], strtok(input, " "));
for(int i = 1; i < size /*inputArray[i-1] != NULL*/; i++)
{
// inputArray = realloc(inputArray, (i+1)*sizeof(char*));
inputArray[i] = malloc(sizeof(char*));
strcpy(inputArray[i], strtok(NULL, " "));
printf("Inside inputArray[%d]: %s\n", i-1, inputArray[i-1]);
}
return inputArray;
}
以下是我的numberOfStrings()方法的代码以及可能值得研究的事件,但是我也使用gdb逐步完成它,看起来非常具体。
int numberOfStrings(char *input)
{
int count = 0;
char *tempCopy = malloc(sizeof(char*));
strcpy(tempCopy, input);
char* token = strtok(tempCopy, " ");
while(token != NULL)
{
token = strtok(NULL, " ");
count++;
}
free(tempCopy);
return count;
}
<小时/> 编辑: 我想跟进,以确保我避免了大多数潜在的未定义行为。 我没有改变main中的任何内容,所以这里是
**stringParser()
中的更改
char **stringParser()
{
char *input = nextLine(stdin);
int size = numberOfStrings(input, strlen(input));
char **inputArray = calloc(size, sizeof(*inputArray));
char *token = strtok(input, " ");
inputArray[0] = malloc(strlen(token));
strcpy(inputArray[0], token);
for(int i = 1; i < size - 1; i++)
{
token = strtok(NULL, " ");
inputArray[i] = malloc(strlen(token));
strcpy(inputArray[i], token);
}
free(input);
inputArray[size-1] = (char*)NULL;
return inputArray;
}
主要变化领域是:
calloc()
代替malloc()
,但如果我的理解是正确的,那么calloc(size, sizeof(*inputArray))
的行为相同(忽略&#39; 0&#39;或垃圾值初始化) malloc((size)*sizeof(*inputArray))
*nextLine(FILE *input)
,允许我逐个字符地扫描stdin
,直到我到达EOF
或'\n'
。这样做的好处是可以准确分配用户输入所需的内存量。sizeof(char*)
相反)count++
。这些变化刚刚让我发现我不再有任何内存泄漏。我不敢假设我已经避免了所有未定义的行为,但是,我想我现在做得好一点。我确定不要用一堆其他问题堵塞这篇文章,但是如果有人觉得它有用或相关,我想留下这个更新。
答案 0 :(得分:1)
realloc()
的来电不会影响fgets()
- 至少,不是直接,可预测或可靠。
fgets(input, INT_MAX, stdin)
中stringParser()
的第一次调用具有未定义的行为,因为指针input
未初始化。
实际上,fgets()
的调用可能会覆盖它不应该覆盖的某些内存区域。
通过添加(或注释掉)realloc()
的调用,结果将是对程序使用的内存布局进行一些调整(例如,更改代码或数据是否位于内存位置)被fgets()
)覆盖。
但这不是因为realloc()
直接影响fgets()
。这只是一个副作用,即调用realloc()
会改变程序中的某些内容。
评论realloc()
电话或重新插入电话的效果可能是任何事情。例如,如果使用不同的编译器设置(如优化标志)或甚至不同的编译器构建代码,则可能会产生不同的效果。
消除fgets()
传递数组
char input[some_positive_value];
fgets(input, sizeof(input), stdin);
或初始化指针以指向合适的缓冲区。
char *input = malloc(some_positive_value); /* remember to `free()` when done */
fgets(input, some_positive_value, stdin);
请注意,如上所述,循环需要realloc()
调用
// inputArray = realloc(inputArray, (i+1)*sizeof(char*));
inputArray[i] = malloc(sizeof(char*));
没有realloc()
调用,inputArray[i]
的赋值也会有未定义的行为。如果你还没有看到这种症状,你就会幸运 - 再次,这是一种你不能依赖的情感。
检查各种函数(fgets()
,realloc()
等)实际上是否成功也是一个好主意。您的代码正在根据一个假设继续进行,即功能全部按预期工作,但如果它们失败(例如realloc()
的内存重新分配失败),则行为将是未定义的。