1

I am trying to make a program that reads numbers from a text file named numbers.txt that contains different numbers in each line.

For example:

8321
12
423
0
...

I have created this program, but it does not work properly. I have tried many things and don't know what to do. Can someone guide me in the right direction? Thank you!

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

#define MAX_LEN 1000

int main(int argc, char *argv[]) {
    char str[MAX_LEN];
    FILE *pFile = fopen(argv[1], "r");
    int num;
    int sum = 0;
    int count = 0;

    if (pFile == NULL) {
        printf("Error opening file.\n");
        return 1;
    }

    while (!feof(pFile) && !ferror(pFile)) {
        if (fscanf(pFile, "%d", &num) == 1) {
            count++;
            while (strcmp(fgets(str, MAX_LEN, pFile), "\0") == 0) {
                printf("%s", str);
                //sum = sum + (int)(fgets(str, MAX_LEN, pFile));
                printf("\n");
            }
        }
    }
    fclose(pFile);

    printf("count = %d \n", count);
    printf("sum = %d \n", sum);

    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
Mark Santos
  • 108
  • 11
  • Does this help? [c language : read file content as numbers and add them together](https://stackoverflow.com/questions/4320335/c-language-read-file-content-as-numbers-and-add-them-together) – Abra Apr 23 '20 at 17:00
  • 1
    "but it does not work properly." lacks information. What was the file contents, was was seen, what was expected? A small example would help a lot. – chux - Reinstate Monica Apr 23 '20 at 17:11
  • As a stylistic nitpick, I'm opposed to the `pFile` – just call it `file`, no need to encode the pointerness in the variable name. IMO. – Arkku Apr 23 '20 at 17:33
  • Just edited the question and gave an example of the .txt file. – Mark Santos Apr 23 '20 at 17:46

3 Answers3

1

strcmp(fgets(str, MAX_LEN, pFile),"\0") is wrong in many ways. For one, the argument of strcmp must be a string (which a null pointer isn't), but fgets returns NULL on error or end of file. You need to check that it didn't return NULL and then you can compare the string in str. However, there is no need to strcmp against "\0" (or, in this case equivalently, "") to detect the end of file, because that's when fgets returns NULL.

Another issue is that you are reading with both fscanf and fgets – pick one and stick with it. I recommend fgets since it's generally easier to get right (e.g., on invalid input it's a lot harder to recover from fscanf and make sure you don't get stuck in an infinite loop while also not losing any input). Of course you need to parse the integer from str after fgets, though, but there are many standard functions for that (e.g., strtol, atoi, sscanf).

Don't use !feof(file) as the loop condition (see, e.g., Why is “while ( !feof (file) )” always wrong?). If you are reading with fgets, end the loop when it returns NULL.

Arkku
  • 41,011
  • 10
  • 62
  • 84
  • 1
    To clarify, it's not incorrect as such to read with both `fscanf` and `fgets`, but it makes it harder to understand the program, especially if the input is more complicated. `fgets` is usually easier to get right, but admittedly in this case you could just `while (fscanf(pFile, " %d", &num) == 1) { sum += num; ++count; }`. – Arkku Apr 23 '20 at 17:28
  • So when we do `fscanf` and it returns `1`, that means that there is a number in that line, and it stores that number into the variable `num`? – Mark Santos Apr 23 '20 at 17:51
  • @MarkSantos Yes, `*scanf` functions return the number of items assigned, in this case you are only trying to read the one (`num`), so a return value of one means it succeeded. Anyway, you should always read the documentation of the functions you use, preferably set up your editor or IDE to display it for you automatically, and always check what the return values are. – Arkku Apr 23 '20 at 18:06
0

You can use strtok to split the numbers in each line, then using atoi function to convert string to int.

For example:

while(fgets(str, MAX_LEN, pFile)) { 
   // if the numbers are separated by space character
   char *token = strtok(str, " ");
   while(token != NULL) {
       sum += atoi(token);
       strtok(NULL, " ");
   }
}

if there is only one number per line, you do not need to use strtok:

while(fgets(str, MAX_LEN, pFile)) { 
    sum += atoi(str);
    // OR
    sscanf(str,"%d\n", &new_number)
    sum += new_number;

}
Hitokiri
  • 3,607
  • 1
  • 9
  • 29
  • It's not clear to me from the question that there would be more than one number per line. If there are, then `strtok` is good suggestion, but you are missing the assignment to `token` inside the inner loop. – Arkku Apr 23 '20 at 17:21
  • Only one number per line. Example: line 1: 812 line 2: 4 line 3: 999 ... – Mark Santos Apr 23 '20 at 17:23
  • @Arkku i dont understand the missing that you were talking about ? – Hitokiri Apr 23 '20 at 17:27
  • @Hitokiri The inner loop condition is `token != NULL` but you are not assigning `token` inside that loop, only before it. Anyway, it's irrelevant since the OP has confirmed that it's only one number per line. – Arkku Apr 23 '20 at 17:30
0

Your program has multiple problems:

  • no test if a command line argument was passed.
  • while (!feof(pFile) && !ferror(pFile)) is always wrong to iterate through the file: feof() gives valid information only after a actual read attempt. Just test if the read failed.
  • if fscanf(pFile, "%d", &num) == 1) add the number instead of just counting the numbers.
  • strcmp(fgets(str, MAX_LEN, pFile), "\0") will fail at the end of the file, when fgets() returns NULL.

If the file only contains numbers, just read these numbers with fscanf() and add them as you progress through the file.

Here is a modified version:

#include <stdio.h>

int main(int argc, char *argv[]) {
    FILE *pFile;
    int num
    int sum = 0;
    int count = 0;

    if (argc < 2) {
        printf("Missing filename\n");
        return 1;
    }
    if ((pFile = fopen(argv[1], "r")) == NULL) {
        printf("Error opening file %s\n", argv[1]);
        return 1;
    }
    while (fscanf(pFile, "%d", &num) == 1) {
        sum += num;
        count++;
    }
    fclose(pFile);

    printf("count = %d \n", count);
    printf("sum = %d \n", sum);

    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189