当我运行代码时,它会产生分段错误。我只是试图打开一个文件并读取其中的数据行。我很确定有一些我不理解的东西。任何帮助将不胜感激。
#include <stdio.h>
#include <string.h>
void get_num_lines(const char *fname, int *rows);
int main (int argc, char* argv[]) {
int rows = 0;
char *ptr1 = NULL;
char str1 = '.csv';
ptr1 = strchr(argv[1], str1);
if(ptr1 != NULL){
const char *fname = argv[1];
get_num_lines(fname, &rows);
}
return(0);
}
void get_num_lines(const char *fname, int *rows)
{
FILE *fin;
fin = fopen(fname, "r");
printf("the input file name is %s", fname);
char line[256] = {0x0};
while(!feof(fin)){
fgets(line, 255, fin);
if(line != NULL){
rows++;
}
}
}
fclose(fin);
}
答案 0 :(得分:3)
您的代码存在许多小但重要的问题。主要的一个是验证您的文件实际上是否已打开以供阅读。如果未验证fopen
成功,则无法知道是否在下一次尝试从无效fin
指针读取的调用中调用未定义行为。 / p>
您已被指向解释Why is “while ( !feof (file) )” always wrong?的链接。只需要验证fgets
的返回。
接下来,虽然可以将指向rows
的指针作为参数传递给函数,但是没有正确更新它。在get_num_lines
中,您尝试使用以下内容进行更新:
rows++; /* this is wrong. this increments the address! (not the value) */
由于你传递了一个指针,你必须增加存储在该地址的值,而不是地址本身,例如。
(*rows)++; /* note the use of (..) for correct C-operator precedence */
这提出了一个更实际的问题,&#34;为什么要传递一个指针?&#34;为什么不只是使用有意义的get_num_lines
返回并简单地将行数返回给调用者? size_t get_num_lines (FILE *fin)
注意:通常的做法是打开并验证文件是否已打开以便在调用函数(此处为main()
)中读取并传递FILE *
指针作为参数而不是文件名。传递一个文件名并在函数中处理它并没有错,它只不是一般方法。
但是,您不能简单地调用fgets
来计算文件中的行数。在增加行数之前,必须验证行是否适合缓冲区(例如,您读取整行而不是更长行的第一个254
字符)。为此,您需要检查fgets
读取的行的长度,并验证读取的最后一个字符是'\n'
。
还有一个(不幸的是常见的)问题会导致你的行计数太少,只有1 如果文件有一个非POSIX文件结尾(意味着它缺少最后一个) '\n'
)。这是正确验证最终字符的副作用'\n'
- 正确运行计数功能所需的。如果文件没有最终'\n'
,则检查它将失败,导致最后一行不计数。值得庆幸的是,只需设置一个表示没有读取行尾的标志,然后在离开fgets
读取循环后检查是否设置了标志来处理。
完全放置这些部分,一个函数采用一个开放的FILE*
指针,读取并返回存在的行数可以是:
size_t fgets_nlines (FILE *fp)
{
int noeof = 0;
size_t n = 0;
char buf[BUF_SIZE] = "";
while (fgets (buf, BUF_SIZE, fp)) { /* read until EOF */
size_t len = strlen (buf); /* get buf length */
if (len && buf[len-1] != '\n') { /* if not complete line */
noeof = 1; /* set flag no EOL found */
continue; /* read until all chars in line are read */
}
noeof = 0;
n++;
}
if (noeof) /* handle non-POSIX EOF (add 1 to count) */
n++;
return n;
}
POSIX提供的第二个面向行的函数不需要文件结束检查是POSIX getline
。它还具有分配足够存储空间的好处 - 无论线路长度如何。 (这也可以被视为一个缺点)。您可以使用与getline
类似的内容执行相同的操作:
size_t getline_nlines (FILE *fp)
{
size_t lines = 0, n = 0;
char *buf = NULL;
while (getline (&buf, &n, fp) != -1)
lines++;
free (buf);
return lines;
}
使用(您必须调整函数名称)的简短示例程序可以编写如下。它将文件名作为程序的第一个参数读取(或者如果没有给出参数,则默认从stdin
读取)它在Linux上提供类似于wc -l
的输出,附加文件名作为部分读取如果名称作为参数提供,则为行计数输出,或者如果从stdin
读取,则仅输出行数,例如
#include <stdio.h>
#include <stdlib.h> /* for free if using getline */
#include <string.h>
#ifndef BUF_SIZE /* fgets buffer size */
#define BUF_SIZE 8192
#endif
size_t fgets_nlines (FILE *fp); /* comment/uncomment as required */
// size_t getline_nlines (FILE *fp);
int main (int argc, char **argv) {
size_t nlines = 0;
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed.");
return 1;
}
nlines = fgets_nlines (fp);
// nlines = getline_nlines (fp); /* same note, comment/uncomment */
if (nlines) {
if (argc > 1)
printf ("%zu %s\n", nlines, argv[1]);
else
printf ("%zu\n", nlines);
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
仔细研究,考虑所涉及的问题,以及fgets
和getline
处理非POSIX EOF的原因与原因之间的区别。如果您有任何其他问题,请与我们联系。
答案 1 :(得分:1)
char str1 = '.csv';
单引号 应该仅限字符,但您要分配多个。它只会分配最后一个字符。所以它会像char str1 = 'v'
那样对待;如果它服务于你的目的那么没有问题,否则修改为beelow
char *str1 = ".csv";
而不是将行与 NULL 进行比较,将fgets()的返回值与NULL进行比较。因为当fin到达EOF时fgets()返回NULL。
ret = fgets(line, 255, fin);
if(ret != NULL){
rows++;
答案 2 :(得分:0)
很少的事情: 1.检查argc并确保在程序exe旁边有列表1参数(argc&gt; 1) 2.检查fopen并在失败时退出