动态创建的C字符串
我试图从用户那里获取一个表达式,并将其放入一个动态创建的字符串中。代码如下:动态创建的C字符串,c,arrays,string,realloc,C,Arrays,String,Realloc,我试图从用户那里获取一个表达式,并将其放入一个动态创建的字符串中。代码如下: 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 (
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,这可能是问题的原因吗?不,XCode不是问题的一部分(是一个可怜的工人责备他的工具) 您尚未初始化exp
exp
,这将导致问题
检测EOF的代码已完全损坏;必须测试scanf()
的返回值才能检测EOF。您最好使用getchar()
和int c
:
int c;
while ((c = getchar()) != EOF && c != '\n')
{
...
}
如果您觉得必须使用scanf()
,则需要测试对scanf()
的每个调用:
在循环中检查realloc()
的结果;那很好。在循环之后,您不检查realloc()
的结果(并且您没有缩小分配);请每次检查
您应该考虑使用一个时间分配多个字节的机制,而不是每个字符读取一个代码> > RealCube()/代码>;那太贵了
当然,如果目标只是读取一行,那么使用POSIX将是最简单的,它将为您处理所有分配。或者,您可以使用读台词。您可以使用固定缓冲区收集数据,然后将其复制到大小适当的动态分配缓冲区。您还应该考虑到这一行很长的可能性,因此您应该检查您是否实际得到了换行符。在Windows XP/cc上,正如Michael所说,如果exp初始化为NULL,它就会起作用。下面是一个固定的代码,带有注释,解释与问题中的代码不同之处:
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;
}
在ubuntu/gcc上检查-如果exp被初始化为NULL,则没有问题(否则会崩溃)。您是否尝试过最简单的测试-仅调用main()+以获取_exp()?在XCode的命令行中如何调用它?与
c=getc()
不同,scanf(“%c”,&c)
永远不会产生EOF
值。因此,测试EOF
是不必要的。请注意,标准IO函数是行缓冲的,在按enter键之前不会返回任何内容。这方面没有标准的方法,它依赖于操作系统,我不知道如何在MacOS中实现。另一件事,在这种情况下,您可以通过为(;;){something…;if(endcondition)break;somethingmore…;}
避免重复代码。正如其他人所说,请注意,将缓冲区逐字节增长是非常低效的。您应该使用每个realloc将缓冲区加倍,然后在读取整行并且知道确切大小时,最终将其realloc到正确的大小。
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;
}