【问题标题】:segmentation fault on reading string读取字符串时出现分段错误
【发布时间】:2017-01-22 16:00:36
【问题描述】:

我有一个从标准输入读取字符串的函数,它基于answer from here

    char* ReadString (FILE* f) {
    int chr;
    int n=0;
    size_t size=4;
    char *st=(char*)malloc(size*sizeof(char));
    while (((chr=fgetc(f))!='\n') && (chr != EOF) ) {
        st[n]=chr;
        if (n+1==size)
            st=(char*)realloc(st,(size+=8)*sizeof(char));
        n++;
    }
    st[n]='\0';
return (char*)realloc(st,sizeof(char)*n);
}

功能正常,但我发现了一个问题。

int k;
printf("number\n");
scanf("%d",&k);
while (!loop) { //infinite loof for tests
        printf("Name of the file and distination\n");
        fname= ReadString(stdin);
        printf("\"%s\"\n",fname); 
}

现在我会遇到分段错误。好吧,据我了解,问题是在scanf之后,在stdin中留下了“\ n”。如果我把

while ( getchar() != '\n' ); // clean stdin 
        fname= ReadString(stdin);

我不会得到分段错误,第一个字符串会完美读取,但下一个字符串将无法正确读取,我需要输入两次。 为什么 (((chr=fgetc(f))!='\n') && (chr != EOF) ) 不起作用? -------------答案--------------

根据下面的答案,这里是未来的代码。

char* ReadString (FILE* f) {
    int chr;
    int n=0;
    size_t size=4;
    char *st=(char*)malloc(size);
    bool loop=false;
    while (!loop) {
        while (((chr=fgetc(f))!='\n') && (chr != EOF) ) {
            st[n]=chr;
            if (n+1==size)
                st=(char*)realloc(st,(size+=8)*sizeof(char));
            n++;
        }
        loop=true;
        if (n==0)
            loop=false;
    }
    if (n!=0 )
        st = (char*)realloc(st,sizeof(char)*n);
    st[n]='\0';
return st;
}

【问题讨论】:

  • 不要投malloc()
  • 乘以sizeof (char) 是多余的:sizeof (char) 定义为 1。

标签: c string


【解决方案1】:

您在上一个realloc 中有一个错误。您的字符串存储 n+1 字节,但您将分配缩短为 n 字节。

如果读取的第一个字符是换行符,则您的循环永远不会运行。您的 st 字符串由 0 个字符组成,后跟一个 '\0' 终止符,即它使用 1 个字节的存储空间。

但是n0,所以realloc(st,sizeof(char)*n) 将其重新分配到0 字节,这可能会释放字符串(或返回指向0 字节内存的指针,不能取消引用)。

最简单的解决方案是只使用return st 而不重新分配它。否则,它应该类似于return realloc(st, n+1);(但您应该真正检查所有realloc 调用是否有错误)。

【讨论】:

  • 你说得对,现在它读取了所有内容。但是现在又过了一会儿,因为标准输入有“\n”,它读取了第一个空字符串......可以忽略它吗?
  • @alex_mike 解决方案是永远不要使用scanf。通过阅读整行(使用fgets 或您的ReadString)来完成所有用户输入。一旦你有一条线,你可以使用例如将它转换为一个数字。 atoisscanf.
猜你喜欢
  • 2017-08-01
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多