0

I have this segment of two functions that should count the number of words of a file.txt. My problem is that fopen don't stop of returning me the NULL value, so I can't run the function properly. I look more than one time and I'm sure that I have my file.txt in the folder.

I expect to return the number of words from texto.txt

int contadorPalabras(char str[]) {
    int k, j;
    k = 0;
    j = 0;
    while (str[k] != '\0') {
        if (str[k] == ' ') {
            j += 1;
            while (str[k + 1] == ' ') {
                k += 1;
            }
        }
        k += 1;
    }
    if (str[0] == ' ') {
        j -= 1;
    }
    if (str[k - 1] == ' ') {
        j -= 1;
    }
    return (j + 1);
}

int palabras_en_txt() {
    char cad[10000];
    int total, j;
    j = 0;
    FILE *fichero;
    fichero = fopen("texto.txt", "r");
    if (fichero == NULL) {
        printf("Hubo un problema en la apertura del archivo especificado.\n");
        return 404;
    }

    while (feof(fichero) == 0) {
        cad[j] = fgetc(fichero);
        j += 1;
    }
    fclose(fichero);
    printf("%s", cad[j]);

    total = contadorPalabras(cad);

    return total;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • 2
    Welcome to Stack Overflow! [Why `while(!feof(file))` is always wrong](https://stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong) – Barmar Mar 08 '23 at 16:06
  • 3
    When `fopen()` returns `null` you should check `errno` for the reason, then fix it. Most likely your working directory is not where the file is, so you should use a full pathname. – Barmar Mar 08 '23 at 16:07
  • 2
    ... or make sure the current working directory of the program is the folder where the texto.txt file is. This totally depends on your environnement/IDE/OS/the_way you_run_the_program etc. – Jabberwocky Mar 08 '23 at 16:15

2 Answers2

4

One of two things is possible:

  • texto.txt does not live in the same directory as your executable; as an experiment, use an absolute path on the file name - "/path/to/texto.txt";

  • Your executable not have permission to read texto.txt - check the file permissions.

When fopen fails it will set errno, from which you can display an error message:

#include <errno.h>
...
fichero = fopen( "texto.txt", "r" );
if ( fichero == NULL )
{
  perror( "failed to open texto.txt" );
  ...
}

This will give you some information as to why the operation failed ("file not found" or "permission denied" or something else).

Finally, do not use feof as your loop condition - it only returns true after you've tried to read past the end of the file. You should test the return value of fgetc instead:

int c;
while ( j < 10000 && (c = fgetc( fichero )) != EOF )
{
  cad[j] = c;
  ...
}
John Bode
  • 119,563
  • 19
  • 122
  • 198
  • 1
    You might also hint that `j` should be tested against the length of the `cad` array to avoid a buffer overflow and a null terminator must be set after the last character stored into it – chqrlie Mar 08 '23 at 17:24
  • @chqrlie: D'oh. I'll add that condition to the code. I'll offer up being two weeks out of coronary bypass surgery as my excuse. – John Bode Mar 08 '23 at 20:59
  • Sorry to hear that you got a close call at 58, but glad you are recovering. Are you still actively programming ? – chqrlie Mar 08 '23 at 21:54
  • @chqrlie: Yeah, still have a job, just on leave until I'm fully recovered. *Quintuple* bypass, including one 100% blockage where the cardiologist said "I don't understand how that vein is still working." Miracle I hadn't had a heart attack yet. So, yeah. – John Bode Mar 08 '23 at 22:47
  • I worked on an image analysis software in the '90s to assess the stenosis level of coronary arteries... Quite amazing you still have both ventricules fully functional. Best wishes ! – chqrlie Mar 08 '23 at 23:53
0

There are multiple problems:

  • when the file cannot be opened, you should issue an error message documenting the cause for the failure. You can use perror() or strerror(errno)` for this purpose. This will help track down your problem.

  • the loop while (feof(fichero) == 0) is incorrect. You should store the return value of fgetc(fichero) in an intand compare it toEOF. Furthermore, you should check that j` does not exceed the array length and you should set a null terminator after the last character read from the file:

    int c; size_t j = 0; while ((c = fgetc(fichero)) != EOF) { if (j < sizeof(cad) - 1) cad[j++] = c; } cad[j] = '\0';

  • contadorPalabras only tests for strings of spaces. You should also check for TABs and newlines that may separate words. The macro isspace() from <ctype.h> can be used to test for all white space characters.

  • there is no need to store the whole file in memory for this task: you can keep the last and the current character read from the file to count the transitions from non-word to word.

  • returning 404 in case of error is humorous but inappropriate as this is a valid count of words.

Here is a modified version:

int palabras_en_txt(void) {
    int total = 0;
    int last, c;
    FILE *fichero = fopen("texto.txt", "r");
    if (fichero == NULL) {
        perror("Hubo un problema en la apertura del archivo especificado");
        return -1;
    }

    last = '\n';
    while ((c = fgetc(fichero)) != EOF) {
        if (isspace(last) && !isspace(c))
            total += 1;
        last = c;
    }
    fclose(fichero);
    printf("words: %d\n", total);
    return total;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189