【问题标题】:Reading string input from file in C从C中的文件中读取字符串输入
【发布时间】:2013-12-24 04:17:42
【问题描述】:

我有一个名为“图形”的文本文件,其中包含“脱氧核糖核酸”字样。

当我运行此代码时,它可以工作并返回第一个字符。 “d”

int main(){

    FILE *fileptr;                          
    fileptr = fopen("graphics.txt", "r");   
    char name;

    if(fileptr != NULL){ printf("hey \n"); }
    else{ printf("Error"); }

    fscanf( fileptr, "%c", &name);
    printf("%c\n", name);
    fclose( fileptr );

    return 0;
}

当我使用fscanf 函数时,我发送的参数是 FILE 对象的名称、函数将读取的数据类型以及它将存储所述数据的对象的名称,对吗?另外,为什么我必须在fscanf 的名称前面加上& 而不是printf

现在,我想让程序读取文件并获取第一个单词并将其存储在名称中。 我知道这必须是一个字符串(字符数组)。 所以我做的是这样的: 我把 name 做成了一个可以存储 20 个元素的字符数组。

char name[20];

并将fscanfprintf中的参数分别改成这个:

fscanf( fileptr, "%s", name);
printf("%s\n", name);

这样做不会导致编译器出错,但程序会崩溃,我不明白为什么。我让fscanf 知道我希望它读取一个字符串,我也让printf 知道它将输出一个字符串。我哪里做错了?我将如何完成上述任务?

【问题讨论】:

标签: c string compiler-construction scanf


【解决方案1】:

这是一个很常见的问题。 fscanf 读取数据并将其复制到您提供的位置;所以首先,你需要&,因为你提供了变量的地址(不是值)——这样fscanf就知道要复制到哪里。

但是您确实想使用“仅复制与我有空间一样多的字符”的功能。例如fgets(),其中包含一个“最大字节数”参数:

char * fgets ( char * str, int num, FILE * stream );

现在,如果您知道您只分配了 20 个字节给 str,您可以防止读取超过 20 个字节并覆盖其他内存。

非常重要的概念!

还有几点。像

这样的变量声明
char myString[20];

导致myString 是一个指向 20 字节内存的指针,您可以在其中放置一个字符串(请记住为终止的 '\0'!). So you can usemyStringas thechar *argument infscanfor fgets`。但是当您尝试读取单个字符时,该字符被声明为

char myChar;

您必须“手动”创建指向内存位置的指针,这就是您最终得到&myChar 的原因。

注意——如果你想读到空格,fscanf 是更好的函数;但是,如果您不确定分配了正确的空间量,那将是一个问题。正如评论中所建议的,您可以执行以下操作:

char myBuffer[20];
int count = fscanf(fileptr, "%19s ", myBuffer);
if(count != 1) {
  printf("failed to read a string - maybe the name is too long?\n");
}

这里使用的是fscanf 的返回值(正确转换的参数数量)。您期望转换为一个;如果这不起作用,它将打印消息(显然,您要做的不仅仅是打印消息……)

【讨论】:

  • 我让它工作了,但我现在的问题是 fgets 和 fscanf 究竟返回了什么?该值告诉我什么?..例如, fgets 它是否返回指向字符对象的指针? fscanf 返回一个 int,这个 int 是什么意思??
  • fgets 的返回值是指向字符串的指针(char *) on success, and NULL` 出错。fscanf 返回的数字是找到并转换的参数(来自参数字符串)。如果传递三个参数它只找到两个,然后返回 2,最后一个变量将具有其旧内容。
【解决方案2】:

不回答您的问题,但是; 为了更有效地使用内存,请使用 malloc 而不是静态声明。

char *myName // declara as pointer
myName = malloc(20) // same as char[20] above on your example, but it is dynamic allocation

... // do your stuff

free(myName) // lastly free up your allocated memory for myName

【讨论】: