【问题标题】:fscanf on string causes segmentation fault字符串上的 fscanf 导致分段错误
【发布时间】:2020-03-20 14:16:17
【问题描述】:

我有一个三行输入文件。 第一行是整数,第二行是带空格的整数,第三行是字符串。

我必须扫描它们而不是根据整数操作字符串。

我的问题是我可以扫描整数,但是扫描字符串会导致 fclose 出现分段错误。

我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h> 

int main()
{
    FILE* in = fopen("be.txt", "r");
    FILE* out = fopen("ki.txt", "w");

    if(in==NULL){
        printf("Error opening in!\n");
        return -1;
    }
    if(out==NULL){
        printf("Error opening out!\n");
        return -1;
    }

    int brknglength, i;

    fscanf(in, "%d", &brknglength);

    printf("%d\n", brknglength);

    int* seed[brknglength];
    seed[brknglength] = malloc(sizeof(int[brknglength]));

    for(i = 0; i < brknglength; i++){
        if (fscanf(in, "%d", &seed[i]) != 1) {
            printf("%d", i);
        }
        printf("%d.: %d \n", i, seed[i]);

    }

    char string;

    fscanf(in, "%s", &string);


    free(seed[brknglength]);

    fclose(in);
    fclose(out);
    return 0;
}

导致分段错误的原因是什么?

【问题讨论】:

  • char string; 只是一个字符。 fscanf(in, "%s", &amp;string); 需要一个足够大的数组,在这种情况下它应该是 fscanf(in, "%s", string); 而没有 &amp; 运算符。
  • int* seed[brknglength]; seed[brknglength] = malloc(sizeof(int[brknglength])); 是错误的。只使用int seed[brknglength]; 并删除free(seed...);
  • 我认为您应该将int* seed[brknglength] 更改为int seed[brknglength]。否则,您将得到一个未初始化的指针数组,您在技术上使用fscanf 对每个指针进行初始化(很可能其值未指向程序中正确分配的内存块)。
  • 与大多数高级语言不同,C 没有内置的字符串类型。在你的 C 编程书中学习字符串。

标签: c file segmentation-fault scanf


【解决方案1】:

您的第一个问题出现在这里:

int* seed[brknglength];

这定义了堆栈上的int 指针数组。

seed[brknglength] = malloc(sizeof(int[brknglength]));

这会初始化数组后面的元素并覆盖您的堆栈。 要修复它,请使用:

int seed[brknglength]; /* use without free(seed) */

或:

int *seed = malloc(sizeof(int[brknglength]));
/* ... */
free(seed);

后者也适用于不支持可变长度数组的编译器。


您的第二个问题是将字符串读入单个char 变量,这也会覆盖堆栈。尝试类似:

char string[100];
fscanf(in, "%99s", &string);

请注意,"%s" 在空白处停止。使用 "%99[^\t\n]" 之类的东西来定义您自己的分隔符,或者使用 "%99c" 来定义固定长度的字符串。

GNU 编译器为所有这些情况提供了修饰符 "m"(=分配内存)作为方便的非标准扩展:

char *string;
fscanf(in, "%ms", &string);
/* ... */
free(string);

【讨论】:

    【解决方案2】:

    int* seed[brknglength];
    seed[brknglength] = malloc(sizeof(int[brknglength]));

    看起来您在这里尝试做的是使seed 成为指向int 数组的指针并为其分配空间。但是,这是错误的语法。因为[ ] 的优先级高于*,所以int* seed[brknglength]; 定义了一个指向int 的指针数组。此外,对象的名称是seed,而不是seed[brknglength],因此您可以使用seed = … 为它分配一个值,而不是使用seed[brknglength] = …

    要创建一个指向数组的指针并为其分配空间,请使用:

    int (*seed)[brknglength];
    seed = malloc(sizeof *seed);
    

    这些可以组合(这不违反上面关于使用seed = 进行赋值的注意事项——初始化有一个特殊的语法):

    int (*seed)[brknglength] = malloc(sizeof *seed);
    

    但是,您可能不希望这样。如果size 是指向数组的指针,那么您必须在要引用数组的任何地方使用*seed。所以fscanf(in, "%d", &amp;seed[i]) 必须是fscanf(in, "%d", &amp;(*seed)[i])

    不要将seed 设为指向数组的指针,只需将其设为指向int 的指针,并为任意数量的int 分配空间:

    int *seed = malloc(brknglength * sizeof *seed);
    

    那么你可以使用seed[i]作为数组的元素i,而不必使用(*seed)[i]

    char string;

    这将string 定义为单个char。但是fscanf(in, "%s", &amp;string); 会读取与输入一样多的字符,直到出现空白字符为止。所以你需要传递fscanf 一个指向许多char 中的第一个的指针。您可以将string 声明为一个数组:

    char string[100];
    

    或指向已分配空间的指针:

    char *string = malloc(100 * sizeof *string);
    

    然后你可以使用fscanf(in, "%s", string);。请注意,您不想传递&amp;string。那是数组或指针的地址,取决于您如何定义string。您想传递第一个字符的地址,即&amp;string[0],或者等价的string。 (如果string是一个数组,在这个表达式中会自动转换成指向它的第一个元素的指针,所以它等价于&amp;string[0]。)

    请注意,fscanf 将读取与输入包含的字符一样多的字符,直到出现空白字符为止。这可以超过您为string 提供的任何大小。所以你需要确保输入没有太多的字符或告诉fscanf限制它的读取量,你可以这样做:

    fscanf(in, "%99s", string);
    

    或:

    int n = 99;
    fscanf(in, "%*s", n, string);
    

    请注意,fscanf 应被告知最多读取比string 中的空格少一个字符,因为它需要添加一个终止空字符。

    要释放这些对象,请使用:

    free(seed);
    free(string); // (If defined as a pointer, not an array.)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-02
      • 1970-01-01
      • 1970-01-01
      • 2011-07-19
      • 2013-05-26
      • 2019-09-25
      相关资源
      最近更新 更多