The external array srclns should keep each read line from a text file. But reading it's content afterwards seems like read lines are empty strings. What am I missing in the code below?
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#define MAXSRC 20
char *srclns[MAXSRC]; /* source lines */
size_t read_lines(char *path)
{
FILE *stream;
ssize_t read;
char *lnptr;
size_t n;
size_t count;
stream = fopen(path, "r");
lnptr = NULL;
n = 0;
count = 0;
if (!stream) {
fprintf(stderr, "Can't open source '%s'\n", path);
exit(EXIT_FAILURE);
}
while ((read = getline(&lnptr, &n, stream)) != -1) {
srclns[count++] = lnptr;
}
free(lnptr);
fclose(stream);
return count;
}
int main()
{
size_t n = read_lines("foo.txt");
for (size_t i = 0; i<n; i++)
printf("%zu %s\n", i, srclns[i]);
exit(EXIT_SUCCESS);
}
This prints only the line numbers with seemingly empty strings afterwards:
0
1
2
3
4
5
So from what I can see not only does your program not work but it might have memory leaks. This is due to the behavior of getline which uses dynamic allocation.
Let's take a closer look at what your program does, in particular the while ((read = getline(&lnptr, &n, stream)) != -1)
loop:
getline will work with &lnptr
which is of type char**
.
NULL
it will allocate enough memory on heap (dynamic) to store the line that is being read.NULL
then it is expected to point on a buffer of size n
getline
so there is a big enough buffer available. Upon reallocation, n
is updated to the new buffer size. And in certain cases reallocation will imply that lnptr
has to be modified and will be. (This might happen if there is not enough consecutive memory free riIght after the current buffer. In that case the memory will be allocated somewhere else on heap. If this is of interest to you I suggest you research is because dynamic memory allocation is a rather complex topic, else just know the pointer might change, that's enough for now).Now here are the issues with your program (at least this is what I can infer from the information I have. I might be wrong but this seems the most plausible interpretation):
lnptr
is NULL
. Thus getline allocates memory on heap and stores the line, and update lnptr
to point on the newly allocated buffer.srclns[0]
srclns[count]
.srclns
points to.How to fix it:
You could explicitly handle dynamic allocation with malloc
and/or calloc
but that seem a bit complicated and, as shown before, getline
can handle it for you. My suggestion is as follow:
srclns
to NULL
for(int i = 0; i < MAXSRC; ++i)
{
srclns[i] = NULL;
}
srclns
in each iteration. Each call to getline
will see an NULL
pointer, thus allocating memory and updating the cell of srclns
to point on it. Bonus with this implementation your certain of never going out of bounds of srclns
:
for(int i = 0; i < MAXSRC; ++i)
{
n = 0
if(getline(&srclns[i], &n, stream) == -1)
{
break; // We get out if we reached OEF
}
}
printf
for(int i = 0; i < MAXSRC; ++i)
{
if(srclns[i] != NULL)
{
free(srclns[i]);
}
}