繁体   English   中英

字符串上的 fscanf 导致分段错误

[英]fscanf on string causes segmentation fault

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

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

我的问题是我可以扫描整数,但是扫描字符串会导致 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;
}

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

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", &seed[i])必须是fscanf(in, "%d", &(*seed)[i])

相反,使得seed的指针数组,只是使它的指针int ,并尽可能多的分配空间int只要你想:

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

然后,您可以将seed[i]用于数组的元素i而不必使用(*seed)[i]

char string;

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

char string[100];

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

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

然后你可以使用fscanf(in, "%s", string); . 请注意,您不想传递&string 那是数组或指针的地址,具体取决于您定义string 您想传递第一个字符的地址,即&string[0] ,或等效的string (如果string是一个数组,它会在此表达式中自动转换为指向其第一个元素的指针,因此它等效于&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.)

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

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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM