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.