分段 在 c 中使用 fgets 函数时出错



我正在用C编写一个小代码,用于将特定字符串从一个文本文件复制到另一个文本文件中。字符串在中间的某个地方。 我用 C 写了一个代码。编译时,我遇到了分段错误。

请帮忙。我的代码如下:

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;
}

而 ( !feof (file( ( 总是错误的?,因为feof(file)在遇到EOF之前不会测试true。如果您通过以下方式控制循环:

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

您的 read 语句将读取文件中的最后一行(或字符(,留下下一次读取以触发EOF,但是,当前读取成功并且没有设置EOF,您的写入完成正常。

接下来会发生什么?

你测试feof (file)它仍然是false,所以!feof (file)测试true,你再次开始处理循环中的语句。读取失败,因为读取指针位于EOF之前,您有一个无效的读取,然后您调用您的 write 语句,通过将不确定的值写入文件来调用未定义的行为。一旦你触发了未定义的行为,你的程序就可以做任何事情,从看起来成功完成或SEGFAULT或介于两者之间的任何事情。

相反,只需使用fgets本身来控制读取循环。这样,只有当fgets成功时,您才会进入循环并将值写入文件,例如

#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 %sn", DPATH);
fclose(fptr1);
if (fclose(fptr2) == EOF)   /* always validate close-after-write */
perror ("fclose-fptr2");
return 0;
}

注意:不要在代码中使用幻数或硬编码值,相反,如果您需要常量#define它们(或者对于数字常量,您也可以使用全局enum来定义它们(。

*示例输入文件**

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

检查输出文件是否存在:

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

示例使用/输出

$ ./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

检查file2.txt

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

仔细查看,如果您有其他问题,请告诉我。

就像对方回答说的,fgets的定义是:

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

datachar*型,所以data[whatever]char型。那可不行。您应该将其更改为仅data.还有其他一些地方可以这样做。将它们也更改为data

要确定问题出在 fget 期间,您可以使用像 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
$

按如下方式修改while循环:

while (!feof(fptr1))
{
fgets(data, 99, fptr1);
fputs(data, fptr2);
}

请阅读有关 fgets((, fputs(( 的文档。只需键入man fgetsman fputs即可。

相关内容

  • 没有找到相关文章

最新更新