Yahya Alami
Yahya Alami

Reputation: 47

Issue while trying reading data from a text file

I'm trying to read data from a text file, and I'm trying to put each line of the text in a pointer to char. I created char* ligne[nl]; where nl is the number of text lines.

The issue is that when I try to print each ligne[] of the text, I found out that the ligne values have only the last line and not all the lines of the text. Take a look at the code:

First my file text contains these lines:

mama
kaka
sasa

I'm using CodeBlocks C, and the code is:

int main(void) {
    int i=0 ,k;
    char *ligne[3] = {NULL}; // three char pointer that take each ligne
    char word[25] = "";

    FILE* file = fopen("dico.txt", "r");

    if(file != NULL){
        while (fgets(word, 25, file) != NULL ){
            ligne[i] = word;
            i++;
        }

        // print each ligne of the file text
        for( i =0 ; i < 3 ; i++){
            printf("%s" , ligne[i]);
            printf("\n");
        }
    }
    return 0;
}

And the result of printing ligne[i] is:

sasa
sasa
sasa

instead of:

mama
kaka
sasa

What am I doing wrong?

Upvotes: 0

Views: 81

Answers (3)

stack_tom
stack_tom

Reputation: 950

The problem is that you are making each index in the ligne array point to the word array. So, when you are done with the fgets while loop, all the indices will be pointing to the data inside the word array, which is sasa (since this was the last word put into the word array, i.e., you overwrote the other words). A possible solution is to declare your ligne array as follows:

char ligne[4][25].

Then call fgets as such :

fgets(ligne[i], 25, file)

On each round of the while loop.

Upvotes: 2

Zac Howard-Smith
Zac Howard-Smith

Reputation: 94

You are overwriting the previously read value with any new reads. Debugging will show that each ligne element points to the same memory address. Instead explicitly create a multi dimensional array and manually reference which element you want to assign to.

const unsigned int NUM_LINES = 3;
int i = 0;
char *ligne[3] = { NULL }; // three char pointer that take each ligne
char word[NUM_LINES][25];

FILE* file = fopen("dico.txt", "r");

if (file != NULL)
{
    while (fgets(word[i], 25, file) != NULL){
        ligne[i] = word[i];
        i++;
    }

    // print each ligne of the file text
    for (i = 0; i < 3; i++)
    {
        printf("%s", ligne[i]);
        printf("\n");
    }
}  
return 0;

Upvotes: 1

LaszloLadanyi
LaszloLadanyi

Reputation: 973

The problem is that you always read the next word into "word" and you make all your ligne[i] elements point to the same variable, "word". If you really do know the size of the words and the number of lines you can do:

 int main( int argc, char **argv ) {
     int i=0 ,k;
     char ligne[4][25]; // three char pointer that take each ligne

     FILE* file = fopen("dico.txt" , "r");

     if(file != NULL){
         while ( fgets(ligne[i] , 25 , file) != NULL ) {
             i++;
         }

// print each ligne of the file text

     for( i =0 ; i < 3 ; i++){
         printf("%s" , ligne[i]);
         printf("\n");
         }
     }  return 0; 
}

Note that ligne is declared for 4 rows. The reason is that after the 3rd line you still pass in ligne[4] to fgets, and even though fgets will return with NULL, the pointer you pass in should be valid.

Also note that the code as is is very dangerous. I relies on the file not having more than 3 lines, or more precisely, fgets returning NULL for the 4th call. These are not the same as the number of characters consumed in each call is limited to 24 (25-1) in each call. If that assumption fails then you'll have all sorts of interesting memory errors.

Upvotes: 1

Related Questions