C / Getting line string from text file and storing them in array/pointer

Viewed 238

I want to get all lines from the text file and store them in my char** pointer (array of strings). The problem is that when I try to set indices for pointer's strings, the program assigns the last scanned sentence for all indices.

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

#define MAX_LINE 10000


int main()
{   
    FILE *fp = NULL;
    char line[MAX_LINE];
    char** lines = (char**) malloc(10000*200*sizeof(char));

    int count = 0;

    fp = fopen("test.txt","r");

    while(fgets(line,10000,fp)) {    
      lines[count] = line; 
      count++;
    } 

    fclose(fp);

    for(int i =0; i<2000;i++){
      printf("%s",lines[i]);
    }

    return 0;
}

lets assume test.txt is like this:

Alice was beginning to get very tired of sitting by her sister on the
bank, and of having nothing to do: once or twice she had peeped into the
book her sister was reading, but it had no pictures or conversations in
it, and what is the use of a book, thought Alice without pictures or
conversations?

When I print like this, every time I get the last sentence (in this case conversations? ) in my text file. However, I want to set every scanned sentence from the text file to the different index in my char**. For example, I want to set like this:

lines[0] gives "Alice was beginning to get very tired of sitting by her sister on the"
lines[1] gives "bank, and of having nothing to do: once or twice she had peeped into the"
and so on.
2 Answers

You can't copy characters from one string buffer to another simply by assigning a pointer (all that does is to make the destination point to the source, as you have noticed).

Instead, you must actually copy the characters, using the strcpy function. So, instead of:

    lines[count] = line; // Just makes each pointer point to the same buffer

use:

    strcpy(lines[count], line); // Copies the CURRENT contents of "line"

You also have a severe problem in the way you are using your char** lines buffer. If you want an array of 200 lines, each with a maximum length of 10000 characters, you should allocate them as follows:

char** lines = malloc(200 * sizeof(char*)); // Make 200 pointers
// Now allocate 10000 chars to each of these pointers:
for (int i = 0; i < 200; ++i) lines[i] = malloc(10000 * sizeof(char));

Note: The 200 buffers will be uninitialized (contain random data) so, in your print loop, you should only use those you have copied real data to, using the count variable as the loop limit:

for(int i = 0; i < count; i++) {
     printf("%s", lines[i]);
}

Also, don't forget to free the memory allocated when you're done:

for (int i = 0; i < 200; ++i) free(lines[i]); // Free each line buffer...
free(lines); // ... then free the array of pointers itself

strdup resolve the issue, free resources as said by Adrian when finished.

int main()
{   
   FILE *fp = NULL;
   char line[MAX_LINE];
   char** lines = (char**) malloc(10000*200*sizeof(char));

   int count = 0;

   fp = fopen("test.txt","r");

   while(fgets(line,10000,fp)) {    
      lines[count] = strdup(line);
      count++;
   } 

   fclose(fp);

   for(int i =0; i<count;i++){
      printf("%s",lines[i]);
   }

   for (int i = 0; i < count; ++i) free(lines[i]);
   free(lines);

   return 0;
}

If you are looking for better performance look at my repo (https://github.com/PatrizioColomba/strvect)

Related