C语言函数:计算文件中的行数。

11

当我尝试运行程序时,我打印的行数是错误的。

LINES: 0

尽管我的.txt文件中有五行内容,但这是输出结果:

以下是我的程序:

#include<stdio.h>
#include<stdlib.h>

int countlines(char *filename);

void main(int argc, char *argv[])
{
  printf("LINES: %d\n",countlines(argv[1]));         
}


int countlines(char *filename)
{
  // count the number of lines in the file called filename                                    
  FILE *fp = fopen(filename,"r");
  int ch=0;
  int lines=0;

  if (fp == NULL);
  return 0;

  lines++;
  while ((ch = fgetc(fp)) != EOF)
    {
      if (ch == '\n')
    lines++;
    }
  fclose(fp);
  return lines;
}

我确信这是一个简单的错误,但我是编程新手。非常感谢任何帮助。


5
charEOF进行比较容易引发问题。 - Carl Norum
5
为了澄清CarlNorum的说法,您应该将fgetc的返回值放在int中。EOF可能超出char的范围。 - CrazyCasta
1
@Bane fgetc()返回一个int值,以便将EOF作为无效字符值传回。 - Joachim Isaksson
1
尝试在调试器中运行它,看看它在哪里崩溃(调试器会告诉你)。 - CrazyCasta
5
@Michael_19 你的问题已经得到了答复,因此你修改了它,但由于仍然无法解决问题。一般来说,你应该接受答案,如果你仍然需要帮助解决新的问题,可以发布一篇新问题并附上更新后的代码。 - Ben Richards
显示剩余4条评论
9个回答

28

如果这个过程中出现错误,可以通过 while(1){ //Other code here if(feof(fp)){break;}} 来打破循环。 - Ben Dworkin
22
你为什么将这个“总是错误”的模式作为答案呈现? - Roland Illig
为什么这个答案得到了最多的投票?问题中的代码总是会得到函数countlines返回0,因为if (fp == NULL); return 0;,不是吗? - rustyhu
不仅是错误的,而且速度非常慢。使用fread而不是getc可以将大文件的处理加速至少两个数量级。(请参见下面的答案:https://dev59.com/mWcs5IYBdhLWcg3wk0-X#70708991) - Mike Siomkin
1
@MikeSiomkin 我同意。我自己也不太喜欢这个(旧的!)答案,可能会删除它,但由于它已被接受,所以无法删除。请将其视为一个快速而粗略的解决方案,而不是在专业生产代码中使用的东西。 - Lundin

7

在我的Core i9 CPU和SSD驱动器上,接受的答案需要34(!)秒来计算1.3 Gb CSV文件中的行数。 请不要使用fgetc读取大型文件。 这样做速度极慢。 下面的代码片段能在300毫秒内完成任务:

#include <stdio.h>

#define BUF_SIZE 65536

int count_lines(FILE* file)
{
    char buf[BUF_SIZE];
    int counter = 0;
    for(;;)
    {
        size_t res = fread(buf, 1, BUF_SIZE, file);
        if (ferror(file))
            return -1;

        int i;
        for(i = 0; i < res; i++)
            if (buf[i] == '\n')
                counter++;

        if (feof(file))
            break;
    }

    return counter;
}

4
您声明
int countlines(char *filename)

需要传递一个char *参数。

调用方法如下:

countlines(fp)

传入一个 FILE *。

这就是为什么你会得到编译错误。

你可能应该将第二行改为

countlines("Test.txt")

由于你在countlines中打开了文件

你当前的代码试图在两个不同的位置打开文件。


我犯了一个错误,main函数应该带一个文件名参数。程序编译通过,但出现了段错误(core dumped)。 - Michael_19
3
你应该接受回答原问题的答案,而不是完全改变问题,并提出一个新问题。 - Eric J.

4
你在 if 的末尾加了一个分号。 请修改为:
  if (fp == NULL);
  return 0;

to

  if (fp == NULL) 
    return 0;

7
这是为什么没有使用 { } 的 if 语句会带来不良后果的原因之一。 - Lundin

3

您正在打开一个文件,然后将文件指针传递给一个只想要文件名以打开文件本身的函数。您可以简化调用;

void main(void)
{
  printf("LINES: %d\n",countlines("Test.txt"));
}

编辑:您的问题已经发生了变化,所以很难回答;起初您将对main()函数的更改弄错了,忘记了第一个参数是argc,因此程序崩溃了。现在您面临的问题是:

if (fp == NULL);   // <-- note the extra semicolon that is the only thing 
                   //     that runs conditionally on the if 
  return 0;        // Always runs and returns 0

这段代码会一直返回0。去掉多余的分号,你就能得到一个合理的计数。


我修改了代码,使其接受一个参数值,即文本的名称。现在运行程序时,我遇到了段错误(core dumped)的错误。 - Michael_19
@Michael_19 嗯,main 函数并不是以那种方式接收参数的。请尝试使用 int main(int argc, char *argv[]) - Joachim Isaksson
@Michael_19 好的,最后一次尝试回答,但是你不断改变问题,导致现有的答案不再适用,而且答案对其他人越来越没有用处。如果你还有更多问题,请接受一个能帮助你的答案,并提出新问题。 - Joachim Isaksson

2
这是我的函数。
char *fileName = "input-1.txt";
countOfLinesFromFile(fileName);

void countOfLinesFromFile(char *filename){
FILE* myfile = fopen(filename, "r");
int ch, number_of_lines = 0;
do
{
    ch = fgetc(myfile);
    if(ch == '\n')
        number_of_lines++;
}
while (ch != EOF);
if(ch != '\n' && number_of_lines != 0)
    number_of_lines++;
fclose(myfile);
printf("number of lines in  %s   = %d",filename, number_of_lines);

}


0

我没有看到任何明显的原因会导致分段错误。我唯一怀疑的是,你的代码在运行时期望得到一个文件名作为参数,但如果你没有传递它,它仍然会尝试引用一个。

argv[1]不存在时访问它导致分段错误。通常最好在尝试引用它们之前检查参数的数量。你可以通过使用以下main()函数的原型,并检查argc是否大于1(简单地说,它将指示argv中的条目数)来实现这一点。

int main(int argc, char** argv)

一般来说,找出导致"段错误"(segfault)的原因最好的方法是使用调试器。如果你在Visual Studio中,可以在主函数顶部设置断点,然后选择"使用调试运行"而不是"无调试运行"来启动程序。它会在顶部停止执行,并允许您逐行步进,直到看到问题所在。
如果你在Linux上,你可以直接获取核心文件(名称中会有"core"),并用GNU调试器(gdb)加载它。它可以给你一个堆栈转储,指向导致段错误发生的代码行。
注:我注意到你改变了你的问题和代码。因此这个答案可能不再有用,但我会保留它,因为它仍然是一个好的建议,同时也会尽快回答修改后的问题。

0

我觉得@Lundin的答案几乎是正确的,但你需要在循环外添加一个(lines++)命令,因为最后一行不包含\n,这样就无法计算。


-1

以下是C/C++的完整实现

#include <stdio.h>

void lineCount(int argc,char **argv){

        if(argc < 2){
             fprintf(stderr,"File required");
             return;
        }
        FILE *fp = fopen(argv[1],"r");



        if(!fp){
            fprintf(stderr,"Error in opening file");
            return ;      
        }

        int count = 1; //if a file open ,be it empty, it has atleast a newline char
        char temp;

        while(fscanf(fp,"%c",&temp) != -1){
                if(temp == 10) count++;
        }

        fprintf(stdout,"File has %d lines\n",count);
   }

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

        lineCount(argc,argv);
        return 0;
}
https://github.com/KotoJallow/Line-Count/blob/master/lineCount.c

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接