I am trying to save each line of a text file into an array. They way I am doing it and works fine so far is this :
char *lines[40];
char line[50];
int i = 0 ;
char* eof ;
while( (eof = fgets(line, 50, in)) != NULL )
{
lines[i] = strdup(eof); /*Fills the array with line of the txt file one by one*/
i++;
}
My text file has 40 lines , which I am accessing with a for loop
for( j = 0; j <= 39 ; j++)
{ /*Do something to each line*/}.
So far so good. My problem is that i define the size of the array lines for the a text file that has 40 lines. I tried to count the lines and then define the size but I am getting segmentation fault.
My approach:
int count=1 ; char c ;
for (c = getc(in); c != EOF; c = getc(in))
if (c == '\n') // Increment count if this character is newline
count = count + 1;
printf("\nNUMBER OF LINES = %d \n",count);
char* lines[count];
Any ideas ?
There are many ways to approach this problem. Either declare a static 2D array or char (e.g.
char lines[40][50] = {{""}};
) or declare a pointer to array of type char [50], which is probably the easiest for dynamic allocation. With that approach you only need a single allocation. With constantMAXL = 40
andMAXC = 50
, you simply need:Reading each line with
fgets
is a simple task of:When you are done, all you need to do is
free (lines);
Putting the pieces together, you can do something like:note: you will also want to check to see if the whole line was read by
fgets
each time. (say you had a long line of more than 38 chars in the file). You do this by checking whether*p
is'\n'
before overwriting with the nul-terminating character. (e.g.if (*p != '\n') { int c; while ((c = getchar()) != '\n' && c != EOF) {} }
). That insures the next read withfgets
will begin with the next line, instead of the remaining characters in the current line.To include the check you could do something similar to the following (note: I changed the read loop counter from
i
ton
to eliminate the need for assigningn = i;
following the read loop).It is up to you whether you discard or keep the remainder of lines that exceed the length of your array. However, it is a good idea to always check. (the lines of text in my example input below are limited to 17-chars so there was no possibility of a long line, but you generally cannot guarantee the line length.
Example Input
Example Use/Output
Now include a the length check in code and add a long line to the input, e.g.:
Rerun the program and you can confirm you have now protected against long lines in the file mucking up your sequential read of lines from the file.
Dynamically Reallocating
lines
If you have an unknown number of lines in your file and you reach your initial allocation of
40
inlines
, then all you need do to keep reading additional lines isrealloc
storage forlines
. For example:Now it doesn't matter how many lines are in your file, you will simply keep reallocating
lines
until your entire files is read, or you run out of memory. (note: currently the code reallocates twice the current memory forlines
on each reallocation. You are free to add as much or as little as you like. For example, you could allocatemaxl + 40
to simply allocate40
more lines each time.Edit In Response To Comment Inquiry
If you do want to use a fixed increase in the number of
lines
rather than scaling by some factor, you must allocate for a fixed number of additionallines
(the increase timessizeof *lines
), you can't simple add40
bytes, e.g.Recall,
lines
is a pointer-to-array ofchar[50]
, so for each additional line you want to allocate, you must allocate storage for 50-char (e.g.sizeof *lines
), so the fixed increase by 40 lines will berealloc (lines, (maxl + 40) * sizeof *lines);
, then you must accurately update your max-lines-allocated count (maxl
) to reflect the increase of40
lines, e.g.maxl += 40;
.Example Input
Example Use/Output
Look it over and let me know if you have any questions.
As an aside, I tested the exact code you show above to get line count (by counting newline characters), on a file containing more than 1000 lines, and with some lines 4000 char long. The problem is not there. The seg fault is therefore likely due to the way you are allocating memory for each line buffer. You may be attempting to write a long line to a short buffer. (maybe I missed it in your post, but could not find where you addressed line length?)
Two things useful when allocating memory for storing strings in a file are number of lines, and the maximum line length in the file. These can be used to create the array of
char
arrays.You can get both line count and longest line by looping on
fgets(...)
: (a variation on your theme, essentially lettingfgets
find the newlines)