简体   繁体   中英

Segmentation Fault error using fgets function in c

I am writing a small code in C for copying specific string from a text file into another text file. The string is in the middle somewhere. I wrote a code in C. When I compiled, I was getting a segmentation fault error.

Please help. My code is as follows:

int main()
{
    FILE *fptr1, *fptr2;
    char c;
    char data[100];

    // Open one file for reading
    fptr1 = fopen(SPATH, "r");
    if (fptr1 == NULL)
    {
        printf("Cannot open file %s \n", SPATH);
        exit(0);
    }

    // Open another file for writing
    fptr2 = fopen(DPATH, "w");
    if (fptr2 == NULL)
    {
        printf("Cannot open file %s \n", DPATH);
        exit(0);
    }

    // Read contents from file
    while (!feof(fptr1))
    {
        fgets(data[20],29,fptr1);
        printf("\n %s",data[20]);
        fputs(data[29], fptr2);
    }   

    printf("\nContents copied to %s", "file2.txt");

    fclose(fptr1);
    fclose(fptr2);
    return 0;
}

while ( !feof (file) ) is always wrong? , because feof(file) does not test true until EOF is encountered. If you are controlling your loop with:

while ( !feof (file) ) {
    /* read statement  */
    /* write statement */
}

Your read statement will read the last line (or character) in the file, leaving the next read to trigger EOF , however, the current read succeeded and did not set EOF , your write completes OK.

What happens next?

You test feof (file) which is still false , so !feof (file) tests true and you start processing the statements within the loop again. Your read fails because the read pointer was sitting right before EOF , you have an invalid read, then you then call your write statement invoking Undefined Behavior by writing an indeterminate value to your file. One you trigger Undefined Behavior , your program can do anything from appearing to complete successfully or SEGFAULT or anything in between.

Instead, simply control your read loop with fgets itself. That way, only if fgets succeeds will you enter your loop and write values to your file, eg

#include <stdio.h>

#define MAXC  100           /* if you need a constant, #define one (or more) */
#define DPATH "file2.txt"

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

    FILE *fptr1 = NULL,     /* initialize all variables (good practice) */
         *fptr2 = NULL;
    char data[MAXC] = "";

    /* open/validate file for reading (default stdin) */
    fptr1 = argc > 1 ? fopen (argv[1], "r") : stdin;
    if (fptr1 == NULL) {
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    /* open/validate file for writing */
    fptr2 = fopen (DPATH, "w");
    if (fptr2 == NULL) {
        fprintf (stderr, "error: file open failed '%s'.\n", DPATH);
        return 1;
    }

    /* read contents from file */
    while (fgets (data, sizeof data, fptr1)) {  /* read 99-char blocks */
        printf ("%s", data);    /* (optional) output to stdout */
        fputs (data, fptr2);    /* write block to fptr2 */
    }

    printf ("\nContents copied to %s\n", DPATH);

    fclose(fptr1);
    if (fclose(fptr2) == EOF)   /* always validate close-after-write */
        perror ("fclose-fptr2");

    return 0;
}

note: don't use magic numbers or hardcoded values in your code, instead, if you need constants #define them (or for numeric constants you can also use a global enum to define them).

*Example Input File**

$ cat dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.

Check if output file exists:

$ ls -al file2.txt
ls: cannot access 'file2.txt': No such file or directory

Example Use/Output

$ ./bin/fgets_copy_file <dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.

Contents copied to file2.txt

Check file2.txt :

$ cat file2.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.

Look things over and let me know if you have further questions.

Like the other person to answer said, the definition of fgets is:

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

data is of type char* , so data[whatever] is of type char . That's no good. You should change that to just data . There are a few other places you do this. Change them to data as well.

To figure out that the problem was during the fgets, you could have used a debugger like GDB:

$ gcc foo.c -g -o myprogram // Compile your program. '-g' means to use debug, and '-o myprogram' is the name of the program you want to make.

// LOTS of warnings that you should have read, which tell you you're probably using 'data' wrong

$ gdb myprogram
(gdb) break main
Breakpoint 1 at 0x40074e: file foo.c, line 7.
(gdb) run
Starting program: /home/anthonyd973/Desktop/myprogram

Breakpoint 1, main () at foo.c:7
7       {
(gdb) next
13      fptr1 = fopen(SPATH, "r");
(gdb) next
14      if (fptr1 == NULL)
(gdb) next
23      fptr2 = fopen(DPATH, "w");
(gdb) next
24      if (fptr2 == NULL)
(gdb) next
33      while (!feof(fptr1))
(gdb) next
35      fgets(data[20],29,fptr1);
(gdb) next

Program received signal SIGSEGV, Segmentation fault. // So the problem is at line 35, during 'fgets'.
(gdb) quit
A debugging session is active.

        Inferior 1 [process 17669] will be killed.

Quit anyway? (y or n) y

$

Modify your while loop as follows:

while (!feof(fptr1))
{

    fgets(data, 99, fptr1);

    fputs(data, fptr2);

}

Please read the document about fgets(), fputs(). Just type man fgets , man fputs .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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