c - 在 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)
不测试。如果您通过以下方式控制循环:true
EOF
while ( !feof (file) ) {
/* read statement */
/* write statement */
}
您的读取语句将读取文件中的最后一行(或字符),让下一次读取触发EOF
,但是,当前读取成功且未设置EOF
,您的写入完成正常。
接下来发生什么?
您测试feof (file)
which is still false
,因此!feof (file)
测试true
并再次开始处理循环中的语句。您的读取失败,因为读取指针位于之前EOF
,您的读取无效,然后您通过向文件写入不确定的值来调用调用未定义行为的写入语句。一旦你触发Undefined Behavior,你的程序可以做任何事情,从出现到成功完成或 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 %s\n", 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.
如果您还有其他问题,请仔细查看并告诉我。
推荐阅读
- ios - Google 日历 API 删除/更新重复事件在 URLSession 上返回 412
- azure - 无法在 Windows VM 上使用 terraform 和 Azure VM 扩展自动映射 Azure 存储共享
- sql-server - 从多个表中选择一列 MSSQL
- java - Arraylist 包含和保留所有不给出与 Sql 内连接相同的结果
- node.js - 在 oracle CLOB 流中写入 utf8 字符串会产生额外的空格 (node.js)
- sql - 有没有办法可以在使用 SQLite 的选择的输出中获取行/序列号?
- r - R:循环自定义 dplyr 函数
- vbscript - 提供程序错误“8007203e”无法识别搜索过滤器。在 Functions.asp 中,第 669 行
- java - 将双向 x,y 点转换为纬度和经度?
- sql - 在比较同一表中的两行值时更新列