Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/unity3d/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
动态创建的C字符串_C_Arrays_String_Realloc - Fatal编程技术网

动态创建的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;
}