0

Code works perfectly fine with any compiler on Windows, but not on Linux. On Linux it returns more than double the rows and a negative number of columns. Win8.1 x86_64, Linux 16.04 64bit. I have GCC v5.3 on Windows (MINGW), but GCC v5.4.0 on Linux.

#include <stdio.h>

// count Lines of a file
size_t countLinesOfFile(char *fileName)
{
    FILE *fp = fopen(fileName, "r");
    char ch;
    size_t lines = 0;
    do {
        ch = fgetc(fp);
        if(ch == '\n' || ch == '\r')
            lines++;
    } while (ch != EOF);
    //while (!feof(fp))

    // if last line doesn't end with a new line character! augment No of lines
    if(ch != '\n' || ch != '\r')
        lines++;

    fclose(fp);
    return lines;
}

// assuming that the file has equal number of columns for all its lines
// (or just 1 line)
size_t countColumnsOfFile(char *fileName)
{
    FILE *fp = fopen(fileName, "r");
    char ch;
    size_t columns = 0;
    while ((ch != '\n' || ch != '\r') && ch != EOF) { // we only want to count one line so which ever comes first
        ch = fgetc(fp);
        columns++;
    }
    columns--;
    //feof(fp) = found end of file, returns non zero(true) if found

    fclose(fp);
    return columns;
}
KeyC0de
  • 4,728
  • 8
  • 44
  • 68

2 Answers2

5

You're incrementing lines when you read both \r and \n. When you create a text file on Windows, it uses CRLF as the newline sequence, but the C stdio library combines these into a single \n character (unless you open the file in binary mode).

Unix just uses LF as the newline character. If you copy the file from Windows to Unix, it will read each of CR and LF as separate characters, \r and \n. Your code increments line for each of them, so you count each line twice. This won't happen for files that you create on Unix.

So you should just count \n characters. As long as you open the file in text mode (the default), this is the only newline character you should ever see. The C library is required to translate whatever the OS's newline sequence is into this character.

BTW, this line is wrong in two ways:

// if last line doesn't end with a new line character! augment No of lines
if(ch != '\n' || ch != '\r')

First, if you want to test if a character is not \n or \r, you should use &&, not ||. See Why non-equality check of one variable against many values always returns true?

Second, the loop ends when ch == EOF, so it will always be unequal to \r and \n. If you want to test how the last line ends, you need to save each character into another variable before repeating the ch = fgetc(fp); assignment.

The column counting code has the same problem of testing for a character that doesn't match any of a list. It should be

while (ch != '\n' && ch != '\r' && ch != EOF) { // we only want to count one line so which ever comes first
Community
  • 1
  • 1
Barmar
  • 741,623
  • 53
  • 500
  • 612
0

I fixed it. I was a little confused with this back then. Here is the code, plain and simple. It doesn't work on MAC (you have to replace "\n" with "\r").

// count lines of a file
size_t countLinesOfFile(char *fileName)
{
    FILE *fp = fopen(fileName, "r");
    char ch;
    size_t lines = 1; // every file starts from line #1

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

    fclose(fp);
    return lines;
}

// assuming that the file has equal ammount of columns
// calculate columns of a file (maximum ammount of columns in any given line)
size_t countColumnsOfFile(char *fileName)
{
    FILE *fp = fopen(fileName, "r");
    char ch;
    size_t columns = 0;

    while (ch != '\n' && ch != EOF) {
        ch = fgetc(fp);
        columns++;
    }
    // note that #(chars in the line) = #(columns) - 1

    fclose(fp);
    return columns;
}


int main()
{
    printf("lines = %d\n", countLinesOfFile("file.txt"));
    printf("columns = %d\n", countColumnsOfFile("file.txt"));
}
KeyC0de
  • 4,728
  • 8
  • 44
  • 68