11

When I try to run my program, I get the wrong number of lines printed.

LINES: 0

This is the output although I have five lines in my .txt file

Here is my program:

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

I am sure it is a simple mistake but I am new to programming. Any help would be greatly appreciated.

Michael_19
  • 4,799
  • 6
  • 24
  • 20
  • You should give a title that summarizes the error, not what you do when you get the error. – Nobody moving away from SE Oct 04 '12 at 18:05
  • 5
    Comparing a `char` against `EOF` is asking for trouble. – Carl Norum Oct 04 '12 at 18:06
  • 5
    To clarify what CarlNorum is saying, you should be putting the return of fgetc in an int. EOF could be outside the range of char. – CrazyCasta Oct 04 '12 at 18:24
  • 1
    @Bane `fgetc()` returns an int to be able to pass EOF back as an invalid character value. – Joachim Isaksson Oct 04 '12 at 18:25
  • 1
    Try running it in a debugger and see where it crashes (the debugger will tell you). – CrazyCasta Oct 04 '12 at 18:27
  • @JoachimIsaksson I made changes to compare int to EOF but now I get the wrong output when I run the program. It prints 0 lines read when there are 5 in my .txt file that I pass as an argument. – Michael_19 Oct 04 '12 at 18:43
  • 5
    @Michael_19 Your question was answered and so you changed it since it still doesn't work. Generally, you should have accepted the answer, and if you still needed help with a new problem that you're running into, posted a new question with the updated code. – Ben Richards Oct 04 '12 at 18:51
  • 1
    With the changed/fixed code this question and answers to it look meaningless. You should ask questions about the current code and present the current code. If you have multiple problems, either ask separate questions or, if they're related, provide information on all of them with the relevant code (it could be 2 versions of the same code). – Alexey Frunze Oct 05 '12 at 05:11
  • This question is a mess – Chris Aug 28 '23 at 05:19

9 Answers9

28
while(!feof(fp))
{
  ch = fgetc(fp);
  if(ch == '\n')
  {
    lines++;
  }
}

But please note: Why is “while ( !feof (file) )” always wrong?.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • If errors do occur with this one could always break out of loop within it by `while(1){ //Other code here if(feof(fp)){break;}} ` – Ben Dworkin Apr 25 '18 at 21:56
  • 22
    Why do you present this "always wrong" pattern as the answer? – Roland Illig Feb 18 '19 at 07:44
  • Why this answer has got most votes? The code in the question always get function `countlines` returning `0` because of `if (fp == NULL); return 0;` isn't it? – rustyhu Jul 22 '21 at 06:51
  • Not only it is wrong it is also prohibitively slow. Using `fread` instead of `getc` accelerates processing of large files at least by two orders of magnitude. (See my answer below: https://stackoverflow.com/questions/12733105/c-function-that-counts-lines-in-file/70708991#70708991) – Mike Siomkin Jan 14 '22 at 10:21
  • 1
    @MikeSiomkin I agree. I don't really like this (old!) answer myself and would probably have deleted it, but can't do since it's accepted. Please regard this as a quick & dirty solution and not something to use in professional production code. – Lundin Jan 14 '22 at 10:27
7

The accepted answer takes 34 (!) seconds to count lines in a 1.3 Gb CSV file on my Core i9 CPU and SSD drive. Please, don't use fgetc to read large files. This is prohibitively slow. The following snippet does the job in 300 ms:

#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;
}
Mike Siomkin
  • 667
  • 8
  • 15
4

You declare

int countlines(char *filename)

to take a char * argument.

You call it like this

countlines(fp)

passing in a FILE *.

That is why you get that compile error.

You probably should change that second line to

countlines("Test.txt")

since you open the file in countlines

Your current code is attempting to open the file in two different places.

Eric J.
  • 147,927
  • 63
  • 340
  • 553
  • I made a mistake, main is supposed to take in an argument value with the name of the file. The program compiles, but I get a segment fault (core dumped) error. – Michael_19 Oct 04 '12 at 18:13
  • 3
    You should accept an answer that addressed your original question, rather than completely changing the question entirely, and ask a new question. – Eric J. Oct 04 '12 at 19:38
4

You have a ; at the end of the if. Change:

  if (fp == NULL);
  return 0;

to

  if (fp == NULL) 
    return 0;
Klas Lindbäck
  • 33,105
  • 5
  • 57
  • 82
3

You're opening a file, then passing the file pointer to a function that only wants a file name to open the file itself. You can simplify your call to;

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

EDIT: You're changing the question around so it's very hard to answer; at first you got your change to main() wrong, you forgot that the first parameter is argc, so it crashed. Now you have the problem of;

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

which will always return 0. Remove that extra semicolon, and you should get a reasonable count.

Joachim Isaksson
  • 176,943
  • 25
  • 281
  • 294
  • I changed the code to take an argument value that is the name of the text. I get the error segment fault (core dumped) when I run the program now. – Michael_19 Oct 04 '12 at 18:15
  • @Michael_19 Well, `main` doesn't really take the arguments that way. Try `int main(int argc, char *argv[])` – Joachim Isaksson Oct 04 '12 at 18:30
  • @Michael_19 Ok, a last attempt to answer, but you keep changing your question so the existing answers don't apply anymore, and the answers get less and less useful to others. If you have any more questions, please accept an answer that helps you and ask a new question with your new problem. – Joachim Isaksson Oct 04 '12 at 19:12
2

Here is my function

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

}

Samir
  • 6,405
  • 5
  • 39
  • 42
0

I don't see anything immediately obvious as to what would cause a segmentation fault. My only suspicion is that your code expects to get a filename as a parameter when you run it, but if you don't pass it, it will attempt to reference one, anyway.

Accessing argv[1] when it doesn't exist would cause a segmentation fault. It's generally good practice to check the number of arguments before trying to reference them. You can do this by using the following function prototype for main(), and checking that argc is greater than 1 (simply, it will indicate the number entries in argv).

int main(int argc, char** argv)

The best way to figure out what causes a segfault in general is to use a debugger. If you're in Visual Studio, put a breakpoint at the top of your main function and then choose Run with debugging instead of "Run without debugging" when you start the program. It will stop execution at the top, and let you step line-by-line until you see a problem.

If you're in Linux, you can just grab the core file (it will have "core" in the name) and load that with gdb (GNU Debugger). It can give you a stack dump which will point you straight to the line that caused the segmentation fault to occur.

EDIT: I see you changed your question and code. So this answer probably isn't useful anymore, but I'll leave it as it's good advice anyway, and see if I can address the modified question, shortly).

Ben Richards
  • 528
  • 5
  • 14
0

I feel @Lundin 's answer was almost correct but you need to add a (lines++) command outside the loop cause the last line is not counted that way as it does not contain a \n.

-1

Here is complete implementation in 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