繁体   English   中英

C 在 fscanf 中使用 char* 导致错误分段错误:11

[英]C Using char* in fscanf causing error Segmentation fault: 11

我是 C 的新手,在使用fscanf从 a.txt 文件中读取所有字符串时遇到了一个问题。

代码如下:

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

int main() {
    FILE *spIn;
    char *numIn;

    spIn = fopen("data.txt", "r");

    if (spIn == NULL) {
        printf("Can't Open This File \n");
    }

    while ((fscanf(spIn, "%s", numIn)) == 1) {
        printf("%s\n", numIn);
    };

    fclose(spIn);
    return 1;
}

这会引发错误: Segmentation fault: 11

txt文件的原始数据为:

1 2 345 rrtts46
dfddcd gh 21
789 kl

整数、字符串、空格和换行符的混合。

至少 4 种可能导致某种故障的候选未定义行为 (UB)。

  1. 代码未能将已初始化的指针传递给fscanf(spIn,"%s",numIn)
  2. 即使fopen()失败,代码也会调用fscanf()
  3. 即使fopen()失败,代码也会调用fclose()
  4. fscanf(spIn,"%s",numIn))没有宽度限制,比gets()差。

文本文件实际上没有字符串'\0'终止的数据)也没有int ,它们有(各种带有'\n'终止的字符)。

要读取一行并保存为字符串,请使用fgets() 不要使用fscanf()来读取数据行。

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

int main() {
  FILE *spIn = fopen("data.txt", "r");
  if (spIn == NULL) {
    printf("Can't Open This File \n");
  } else {
    char buf[100];
    while (fgets(buf, sizeof buf, spIn)) {
      printf("%s", buf);
    }
    fclose(spIn);
  }
}

char* numIn是一个指针,它是未初始化的,你不能真正在其中存储任何东西,你需要为其分配 memory 或使其指向某个有效的 memory 位置:

#include<stdlib.h> // for malloc

char* numIn = malloc(100); // space for 99 char + null terminator byte    
//...
while ((fscanf(spIn, "%99s", numIn)) == 1)
{
    printf("%s\n",numIn);
};

或者:

char str[100];
char *numIn = str;

在这个小代码中没有什么意义,你可能应该让numIn一个固定大小的数组开始:

char numIn[100];

请注意,您应该在*scanf中使用宽度说明符以避免缓冲区溢出。 但这仍然有一个问题,它将逐字读取,而不是逐行读取。

查看您的输入文件,使用fgets似乎是一个更好的选择,它可以读取完整的行,包括空格:

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

int main()
{
    FILE *spIn;
    char numIn[100];
    spIn = fopen("data.txt", "r");

    if (spIn != NULL)
    {
        while ((fgets(numIn, sizeof numIn, spIn)))
        {
            numIn[strcspn(numIn, "\n")] = '\0'; // removing \n
            printf("%s\n", numIn);
        }
        fclose(spIn);
    }
    else
    {
        perror("Can't Open This File");
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

由于fgets还解析\n字符,我将使用strcspn删除它。

尽管您确实验证了fopen的返回值,但即使无法打开,执行也会继续,但我也解决了这个问题。

暂无
暂无

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

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