我正在尝试从用户处获取表达式并将其放入动态创建的字符串中。这是代码:
char *get_exp() {
char *exp, *tmp = NULL;
size_t size = 0;
char c;
scanf("%c", &c);
while (c != EOF && c != '\n') {
tmp = realloc(exp, ++size * sizeof char);
if (tmp == NULL)
return NULL;
exp = tmp;
exp[size-1] = c;
scanf("%c", &c);
}
tmp = realloc(exp, size+1 * sizeof char);
size++;
exp = tmp;
exp[size] = '\0';
return exp;
}
但是,由于某种原因,每次读取的第一个字符都是换行符,因此while循环退出。我正在使用XCode,可能是导致问题的原因吗?
答案 0 :(得分:1)
不,XCode不是你问题的一部分(这是一个谴责他的工具的穷人)。
您尚未初始化exp
,这会导致问题。
检测EOF的代码完全被破坏了;您必须测试scanf()
的返回值以检测EOF。使用getchar()
int c
时,您可以做得更好:
int c;
while ((c = getchar()) != EOF && c != '\n')
{
...
}
如果您认为必须使用scanf()
,那么您需要测试对scanf()
的每次通话:
char c;
while (scanf("%c", &c) == 1 && c != EOF)
{
...
}
你确实在循环中检查realloc()
的结果;这很好。在循环之后你不会检查realloc()
的结果(并且你没有缩减你的分配);请每次检查。
您应该考虑使用一次分配多个字节的机制,而不是每个字符读取一个realloc()
;这很贵。
当然,如果目标只是读取一行,那么最简单的方法是使用POSIX getline()
,它会为你处理所有的分配。或者,您可以使用
fgets()
阅读该行。您可以使用固定缓冲区来收集数据,然后将其复制到适当大小的动态分配缓冲区。您还可以考虑线路很长的可能性,以便检查您是否确实获得了新线路。
答案 1 :(得分:0)
在Windows XP / cc上,就像迈克尔所说,如果将exp初始化为NULL,它就可以工作。
答案 2 :(得分:0)
这是一个固定的代码,其中的注释解释了与问题中的代码不同的内容:
char *get_exp()
{
// keep variables with narrowest scope possible
char *exp = NULL;
size_t size = 0;
// use a "forever" loop with break in the middle, to avoid code duplication
for(;;) {
// removed sizeof char, because that is defined to be 1 in C standard
char *tmp = realloc(exp, ++size);
if (tmp == NULL) {
// in your code, you did not free already reserved memory here
free(exp); // free(NULL) is allowed (does nothing)
return NULL;
}
exp = tmp;
// Using getchar instead of scanf to get EOF,
// type int required to have both all byte values, and EOF value.
// If you do use scanf, you should also check it's return value (read doc).
int ch = getchar();
if (ch == EOF) break; // eof (or error, use feof(stdin)/ferror(stdin) to check)
if (ch == '\n') break; // end of line
exp[size - 1] = ch; // implicit cast to char
}
if (exp) {
// If we got here, for loop above did break after reallocing buffer,
// but before storing anything to the new byte.
// Your code put the terminating '\0' to 1 byte beyond end of allocation.
exp[size-1] = '\0';
}
// else exp = strdup(""); // uncomment if you want to return empty string for empty line
return exp;
}