0

I'm trying to read a text file of integers into an array in C.

My text file looks like this: (12 numbers/line)

5713    6936    8764    6702    8535    8654    8710    8332    4948    7627    5472    5311    
7331    8719    6135    6672    5786    7113    5292    6923    5683    7020    8595    8606    
6837    7003    7415    8372    8429    5726    8323    6442    8672    6488    6932    5884    
6811    7785    7189    5531    6323    8561    8283    5114    6669    7217    8307    6599    
6961    8695    6026    5580    6010    4954    8725    4955    5532    7736    5372    8712    
8343    5375    5931    6449    8223    5844    5931    5307    5436    6405    8599    6302    
8617    8222    5985    8216    5044    5259    6523    7526    8702    5878    7559    5366    
5362    7393    6633    8781    6289    6470    5342    7278    5348    8677    5779    5763    
5718    8678    6406    8774    5931    7324    6819    6393    5027    7545    8385    8795    
8277    8059    6362    6980    5899    5828    6707    7149    5621    7287    5958    6506    
6517    5710    5504    7070    8797    6840    7112    6063    7014    5419    7514    7431   

The actual file has overall 1000 numbers

Currently, I am using the following code:

int main(void){

    FILE *my_file;
    my_file = fopen("seals.txt", "r");
    size_t size = word_conter(my_file);

    int weight = 0;
    int seals[size];

    int i;
    for(i = 0; i < size; i++){
        if(fscanf(my_file, "%1d", &weight) == 1)
            seals[i] = weight;
        else break;
    }

    for(i = 0; i < size; i++){
        printf("%d\t %d\n", i, seals[i]);
    }

    
    fclose(my_file);    
    return 0;
}

EDIT: Here is word_counter :

size_t word_conter(FILE *my_file){
    
    if(my_file == NULL){
        perror("Error in file");
        exit(1);
    }

    size_t counter = 0, in_word = 0;
    char ch;

    while((ch = fgetc(my_file)) != EOF){

        if(ch == ' ' || ch == '\n' || ch == '\t' || ch == '\0'){
            if(in_word){
                in_word = 0;
                counter++;
            }
        }
        else in_word = 1;
    }

    return counter;
}

Unfortunately, my output is:

0    245589760
1    1
2    1
3    0
4    -497513808
5    32766
6    245022469
7    1
8    -497513808
9    32766
10   245022268
11   1
12   1
13   0
14   224894352
15   1
16   -497513744
17   32766
18   244994643
19   1
20   245557328
21   1
22   224894352
23   1
24   224879992
25   1
26   0
27   0
28   245584536
29   1
30   245616784
31   1
32   -497513712
33   32766
34   245024298
35   1
36   245557328
37   1
38   -799666472
39   22978
40   -497510096

And so on up to 999.

I have tried using both: fscanf(my_file, "%1d", &weight) and fscanf(my_file, "%d", &weight) but both didn't work. I have read the manual about fscanf but still couldn't get it right.

Any help would be much appreciated!

Second Edit:

I used rewind() and that did the trick!

ryyker
  • 22,849
  • 3
  • 43
  • 87

3 Answers3

2

In a nutshell, this is caused by reading through the data file twice in a row without calling rewind().

The problem occurs when fscanf() reads the file for a second time without rewinding. (first read is in word_conter() function):

        if(fscanf(my_file, "%d", &weight) == 1)//2nd read on one file descriptor
             seals[i] = weight;//program flow never gets here
        else break;

This results in execution flow jumping directly to else break;, then continuing to loop on printf() and outputting the uninitialized array: int seals[size];

Also, the function word_conter is susceptible to various inconsistencies data formatting might present within the file it is reading. Suggest stepping through code in a debugger to characterize exactly how this might be contributing to the problem.

My suggestion is to call fopen() and fclose each once inside word_counter, then re-call both again in the main function. This refactored version of size_t word_conter(FILE *my_file) supports this approach. (written to accommodate file containing 12 numbers per line as per mentioned in comments):

size_t word_counter(char *filename)
{
    char line[260] = {0};
    char *tok = NULL;
    int count = 0;
    FILE *fp = fopen(filename, "r");
    if(fp)
    {
        while(fgets(line, sizeof(line), fp))
        {
            tok = strtok(line, " \n");
            while(tok)
            {
                count++;
                tok = strtok(NULL, " \n");
            }
            memset(line, 0, sizeof(line));
        }
        fclose(fp);
    }
    return count;
}

Called in main as:

size_t size = word_counter("seals.txt");

There is also an instance of using an incorrect format specifier can invoke undefined behavior

For:

int weight = 0;

The correct format specifier is "%d". Either change:

if(fscanf(my_file, "%1d", &weight) == 1)

to:

if(fscanf(my_file, "%d", &weight) == 1)    

or change:

   int weight = 0;
   int seals[size];

to:

   long weight = 0;
   long seals[size];

(%ld is used only for long.)

Addressing each of these is likely to address the problem you are seeing. (However, because word_conter() is not shown in detail, there may be other issues.)

ryyker
  • 22,849
  • 3
  • 43
  • 87
  • @Davide - Yes, sorry, I was still editing. The fact that OP tried the correct format specifier may not have helped in light of the other omissions and mistakes in shown code. – ryyker Dec 29 '20 at 14:36
  • 1
    @ryyker Thank you for your detailed answer! Unfortunately, This still doesn't solve the issue. I have edited my question so you guys could see the word_counter method. Also, I was asked to clarify, the text file contains multiple lines of numbers and not a single line as displayed. – Tal Zichlinsky Dec 29 '20 at 14:51
  • @TalZichlinsky - looking at it now. Thanks. Is it one number per line, or more than one. How many numbers per line? (please be specific.) – ryyker Dec 29 '20 at 14:56
  • @ryyker It is 12 numbers per line. In any case, The problem is solved, using ``` rewind``` got the job done. Thank you so much for helping out! – Tal Zichlinsky Dec 29 '20 at 15:12
  • @TalZichlinsky - you are welcome. I had just come to the `rewind` conclusion, or suggesting opening the file twice. Chux beat me to it. :) – ryyker Dec 29 '20 at 15:14
2

Word counter messes up on edge cases.

Look for transitions from space to non-space. Do not forget to rewind().

size_t counter = 0;
bool in_word = false;
// char ch;
int ch;

while((ch = fgetc(my_file)) != EOF){
   if (ch == ' ' || ch == '\n' || ch == '\t' || ch == '\0') {  // better: if (isspace(ch)) {
     in_word = false;
   } else {
     if (!in_word) counter++;
     in_word = true;
   }
}
rewind(my_file); // reset to the beginning

return counter;

Even better, just go through the file twice with the same format.

size_t counter = 0;
while (fscanf(my_file, "%d", &weight) == 1) {
  counter++;
}
rewind(my_file); // reset to the beginning
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

try to replace if(fscanf(my_file, "%1d", &weight) == 1) with if(fscanf(my_file, "%d", &weight) != EOF)