简体   繁体   English

在C中使用fscanf进行分段错误

[英]Segmentation Fault using fscanf in C

I am trying to read names from a text file in my code for .c, but I keep getting a segmentation fault from fscanf and can't seem to find out what the problem is. 我正在尝试从我的.c代码中的文本文件中读取名称,但是我一直从fscanf遇到分段错误,似乎无法找出问题所在。

I tried multiple options, including increasing the char array size, but I have no idea what is wrong, any help would be appreciated. 我尝试了多种选择,包括增加char数组的大小,但是我不知道出了什么问题,我们将不胜感激。

I also executed this in the DevC++ and it worked, but when I used gcc, it gave me that segfault error. 我也在DevC ++中执行了该命令,并且它起作用了,但是当我使用gcc时,它给了我segfault错误。

in main 在主要

FILE* infile;
char buffer[20];

in a switch case in main 在主开关箱中

infile = fopen("pathway", "r");
for (i=-1; i < name; i++)
{
     fscanf(infile, "%s", buffer);
}
fclose(infile);

the file 文件

Zeda'Taxu
Khano'Balme
Goni
...
...

There are a couple of points to be made (1) never skimp on buffer size . 有几点要注意(1) 永远不要忽略缓冲区大小 20 is horribly insufficient for a large percentage of names in use. 对于使用中的很大一部分名称, 20都非常不足。 64 may be a reasonable size, and then you take that reasonable size and double it. 64可能是一个合理的大小,然后您选择该合理的大小并将其加倍

Next, (2) it is unclear what name does in your code, but since it is used in a for loop limit, that seems to be the number of names you wish to limit your read to. 接下来,(2)不清楚代码中将使用什么name ,但是由于在for循环限制中使用了该名称,因此这似乎是您希望限制读取的名称的数量。 You must control your read loop so it exits when 1 - your read index is no longer less than your name limit && fgets() returns a valid pointer, eg 您必须控制读取循环,以便在1时退出-您的读取索引不再小于name限制&& fgets()返回有效的指针,例如

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

#define MAXNM 128   /* if you need a constant, #define one (or more) */
#define NUMNM  10   /*        ( Don't skimp on buffer size! )        */

int main (int argc, char **argv) {

    char buffer[MAXNM];
    size_t ndx = 0, name = NUMNM;
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
    ...
    while (ndx < name && fgets (buffer, MAXNM, fp)) {
        buffer[strcspn (buffer, "\n")] = 0; /* overwrite \n with nul-char */
        fprintf (stdout, "name[%2zu] : %s\n", ndx++ + 1, buffer);
    }

Above a simple ndx (index) variable is used along with the return from fgets to control your read loop. 在上面有一个简单的ndx (索引)变量,与fgets的返回值一起使用来控制您的读取循环。 This eliminates your problem of having less lines than names in the file, but then blindly pushing ahead reading from a stream in error-state until name iterations take place. 这消除了您的具有比行少的问题names的文件中,但随后一味向前推,从流读取错误状态,直到name重复发生。 By using ndx < NUMNM && fgets (buf, MAXC, fp) as the loop control, you gracefully exit when either condition in no longer true avoiding Undefined Behavior . 通过使用ndx < NUMNM && fgets (buf, MAXC, fp)作为循环控件,当其中任一条件不再为true时,您可以正常退出以避免Undefined Behavior

(3) if you intend to store the name from each buffer , you then need to allocate storage for each name and copy buffer to the new storage before your next iteration or the prior name will be lost when buffer is refilled. (3)如果要存储每个buffer的名称,则需要为每个名称分配存储空间,然后在下一次迭代之前将buffer复制到新存储空间,否则当重新填充buffer时,先前的名称将丢失。

(4) fgets reads up to, and includes, the trailing '\\n' at the end of the buffer filled. (4) fgets读取并包含填充缓冲区末尾'\\n' You do not want to store your names with '\\n' s dangling off the end. 您不想使用结尾的'\\n'来存储名称。 strcspn is one of the simplest and most robust ways of determining the number of characters in buffer before the '\\n' and then simply overwriting the '\\n' with the nul-character . strcspn是确定'\\n'之前的buffer的字符数,然后简单地用nul-character覆盖'\\n'的最简单,最可靠的方法之一。 You need nothing more than was shown above, eg 您只需要上面显示的内容,例如

        buffer[strcspn (buffer, "\n")] = 0; /* overwrite \n with nul-char */

Refer to strspn(3) - Linux manual page and see if you can figure out exactly how that works. 请参考strspn(3)-Linux手册页 ,看看您是否可以确切了解它是如何工作的。

(5) Always check the return of every file opening (and closing after the stream has been written to), and always check the return of every user-input function. (5) 始终检查每个打开的文件(以及在写入流之后关闭的文件)的返回,并始终检查每个用户输入函数的返回。 There is no more critical step in your code than validating the data you receive from a file or a user Before you attempt to process that data. 在您的代码中,没有什么比验证从文件或用户收到的数据更关键的步骤了, 然后再尝试处理该数据。 Otherwise you are just inviting Undefined Behavior with as little as the slip of a keystroke, or a single misspelling. 否则,您只需轻按一下键或一次拼写错误即可邀请未定义行为

Putting it altogether in a program that takes the filename to open as the first argument to the program (or reads from stdin by default if no argument is provided), you could do something like: 将其放到一个程序中,该程序以打开的文件名作为程序的第一个参数(如果没有提供参数,则默认情况下从stdin读取),您可以执行以下操作:

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

#define MAXNM 128   /* if you need a constant, #define one (or more) */
#define NUMNM  10   /*        ( Don't skimp on buffer size! )        */

int main (int argc, char **argv) {

    char buffer[MAXNM];
    size_t ndx = 0, name = NUMNM;
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    while (ndx < name && fgets (buffer, MAXNM, fp)) {
        buffer[strcspn (buffer, "\n")] = 0; /* overwrite \n with nul-char */
        fprintf (stdout, "name[%2zu] : %s\n", ndx++ + 1, buffer);
    }

    if (fp != stdin)    /* close file if not stdin */
        fclose (fp);
}

Example Input File 输入文件示例

Now exercise your input routine with a file containing 11 names, one more than NUMNM allows to be read, eg 现在,使用包含11个名称的文件来练习输入例程,该文件比NUMNM允许读取的名称多一个,例如

$ cat dat/namesonly.txt
Zeda'Taxu
Khano'Balme
Goni
Ryan,Elizabeth
McIntyre,Osborne
DuMond,Kristin
Larson,Lois
Thorpe,Trinity
Ruiz,Pedro
Ali,Mohammed
Vashti,Indura

Example Use/Output 使用/输出示例

Reading and stopping a NUMNM names 读取和停止NUMNM个名称

$ ./bin/fgetsnames <dat/namesonly.txt
name[ 1] : Zeda'Taxu
name[ 2] : Khano'Balme
name[ 3] : Goni
name[ 4] : Ryan,Elizabeth
name[ 5] : McIntyre,Osborne
name[ 6] : DuMond,Kristin
name[ 7] : Larson,Lois
name[ 8] : Thorpe,Trinity
name[ 9] : Ruiz,Pedro
name[10] : Ali,Mohammed

Look things over and let me know if you have further questions. 仔细检查一下,如果您还有其他问题,请告诉我。

I see two reasons which could lead to undefined behaviour. 我看到两个可能导致不确定行为的原因。

First, a possible NULL in infile ; 首先, infile可能为NULL Second, exceeding the buffer size in one of the lines of the file. 其次,超出文件行之一中的缓冲区大小。 In order not to change to much of your logic, a quick fix could be: 为了不改变您的大部分逻辑,快速修复方法可能是:

FILE* infile;
char buffer[20];
infile = fopen("pathway", "r");
if (infile!=NULL) {
  for (i=-1; i < name; i++) {
     fscanf(infile, "19%s", buffer);
  }
}

You might consider using fgets instead. 您可以考虑改用fgets Confer, for example, the following example copied from here : 例如,授予从此处复制的以下示例:

 #include <stdio.h> int main () { FILE *fp; char str[60]; /* opening file for reading */ fp = fopen("file.txt" , "r"); if(fp == NULL) { perror("Error opening file"); return(-1); } if( fgets (str, 60, fp)!=NULL ) { /* writing content to stdout */ puts(str); } fclose(fp); return(0); } 

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

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