Reputation: 37
I am looking to create an array of pointers to strings read from a file in C. However when I try to print out the strings copied to stdout
, the last line of the file is always left out.
The program also sometimes experiences a segmentation fault
which I haven't been able to completely eliminated. It happens about 2 out of 5 times.
Here is my input.c
code:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "input.h"
#define MAXLINES 5000
void writelines(char *arr[], int l);
char *read_lines[MAXLINES];
void get_input(const char *fp) {
FILE *contents;
char *line;
char *temp;
size_t len;
ssize_t read;
int i;
i = 0;
contents = fopen(fp, "r");
if (contents == NULL)
exit(EXIT_FAILURE);
while ((read = getline(&line, &len, contents)) != -1) {
if ((temp = (char *) malloc(strlen(line) + 1)) == NULL) {
printf("Could not allocate required memory.");
exit(EXIT_FAILURE);
}
else {
line[strlen(line) - 1] = '\0';
strcpy(temp, line);
read_lines[i++] = temp;
}
}
fclose(contents);
free(line);
free(temp);
writelines(read_lines, i);
exit(EXIT_SUCCESS);
}
void writelines(char *arr[], int l) {
int i;
for (i = 0; i < l; i++) {
printf("%s\n", arr[i]);
}
}
My main.c
file is:
#include <stdio.h>
#include "input.h"
int main(int argc, char *argv[]) {
if (argc == 1)
printf("Please provide a valid source code file.\n");
else
get_input(*(++argv));
return 0;
}
I compile using gcc main.c input.c -Wall
with no warnings or errors.
Using gdb
I can confirm that the process runs normally.
When it experiences a segmentation fault, the back trace shows a call to strlen
that apparently fails.
Upvotes: 1
Views: 49
Reputation: 140168
from the documentation:
If *lineptr is NULL, then getline() will allocate a buffer for storing the line, which should be freed by the user program. (In this case, the value in *n is ignored.)
but in your case you're passing an uninitialized value to getline
the first time, so getline
thinks it can write to that illegal location and this is undefined behaviour (which explains the "It happens about 2 out of 5 times" thing)
The first fix should be to initialize line
:
char *line = NULL;
then, why are you creating a copy of line
, and you're not freeing line
(memory leak) and you're not resetting it to NULL
. So next time getline
reuses the previous buffer, which may not be long enough to hold the next line.
The fix is just to store the line:
read_lines[i++] = line;
then set line = NULL
so getline
allocates the proper len for next line. And drop the malloc
code, it's useless.
fixed part (you don't need to pass pointer on len
it is ignored):
line = NULL;
while ((read = getline(&line, NULL, contents)) != -1) {
read_lines[i++] = line;
line[strcspn(line, "\n")] = 0; // strip off linefeed if there's one
line = NULL;
}
(linefeed strip adapted from Removing trailing newline character from fgets() input)
Upvotes: 1