Problems with function that returns a pointer to array of strings

P

paktsardines

Hi all

I am trying to write a function that reads a file into a dynamically
allocated 2d array of char, something like the following prototype:

char ** read_file(char * filename)

Ideally I would like it to behave like the following perl:

sub read_file {
my $filename=shift(@_)
my @lines;
open(FILE, "<$filename") || die ("Cannot open $filename\n");
@lines=<FILE>;
close(FILE);
return @lines;
}

so far I have something like:

void main(void) {
char ** file_lines = readfile("test.txt");

printf("%s\n",*file_lines[0]);

}


And the function:

char ** read_file(char * filename) {
FILE *fptr;
char *line = malloc(LINE_MAX * sizeof(char));
char **lines = 0;
int linelength = 0;
int i = 0;

// Try to open the file
if ((fptr=fopen(filename,"r"))!=NULL) {
while (fgets(line,LINE_MAX,fptr)!=NULL) {
linelength=strlen(line);
line[linelength]='\0';
if ((lines= realloc(lines, (i *linelength +1) *
sizeof(char *)))==NULL) {
printf("Cannot allocate memory\n");
exit(1);
}
lines=line;
i++;
}
}

else {
printf("Cannot open %s for reading.\n",filename);
exit(1);
}
free (line);
return lines;
}

The program currently seems to get through the function okay, but
then seg faults when printing the first line.

Thanks for any pointers, (boom boom :)

Pakt.
 
I

Ian Collins

Hi all

I am trying to write a function that reads a file into a dynamically
allocated 2d array of char, something like the following prototype:

char ** read_file(char * filename)

And the function:

char ** read_file(char * filename) {
FILE *fptr;
char *line = malloc(LINE_MAX * sizeof(char));
char **lines = 0;
int linelength = 0;
int i = 0;

// Try to open the file
if ((fptr=fopen(filename,"r"))!=NULL) {
while (fgets(line,LINE_MAX,fptr)!=NULL) {
linelength=strlen(line);
line[linelength]='\0';
if ((lines= realloc(lines, (i *linelength +1) *
sizeof(char *)))==NULL) {

Why are you allocating (i *linelength +1) char pointers? If lines is an
array of char*, you only want 1+i.
 
P

paktsardines

Why are you allocating (i *linelength +1) char pointers? If lines is an
array of char*, you only want 1+i.

Thank you Ian, I've now modified the while loop to look like:

while (fgets(line,LINE_MAX,fptr)!=NULL) {
linelength=strlen(line);
line[linelength]='\0';

if ((lines= realloc(lines, (i+1) * sizeof(char *)))==NULL) {
printf("Cannot allocate memory\n");
exit(1);
}

lines=malloc(linelength* sizeof(char) + 1);
strcpy(lines,line);
i++;
}


Can you please confirm that this is now correct?


(... it still seg faults when it tries to print)
 
J

Justin Spahr-Summers

The program currently seems to get through the function okay, but
then seg faults when printing the first line.

file_lines is declared as a pointer to a pointer to a char object.
printf("%s\n",*file_lines[0]);

By executing this code, you first retrieve a pointer to a char object
(through file_lines[0]), but then you dereference this pointer to
receive a single char object. This means that printf() is expecting
the memory address of a string, but you are passing a character, which
is extremely likely to be an invalid memory address (much less the one
you want) on your system. The problem here can be corrected by
removing the unary * operator.
 
I

Ian Collins

Hi all

I am trying to write a function that reads a file into a dynamically
allocated 2d array of char, something like the following prototype:

so far I have something like:

void main(void) {

I didn't spot this the first time, main should return int.
char ** file_lines = readfile("test.txt");

printf("%s\n",*file_lines[0]);
or this, should be

printf("%s\n",file_lines[0]);
}


And the function:

char ** read_file(char * filename) {
FILE *fptr;
char *line = malloc(LINE_MAX * sizeof(char));

Or this, sizeof(char) is 1 by definition.
 
I

Ian Collins

Why are you allocating (i *linelength +1) char pointers? If lines is an
array of char*, you only want 1+i.
Thank you Ian, I've now modified the while loop to look like:

while (fgets(line,LINE_MAX,fptr)!=NULL) {
linelength=strlen(line);
line[linelength]='\0';

You might want this to be

line[linelength-1]='\0';

if you don't want the end of line character in your string.
if ((lines= realloc(lines, (i+1) * sizeof(char *)))==NULL) {
printf("Cannot allocate memory\n");
exit(1);
}

lines=malloc(linelength* sizeof(char) + 1);
strcpy(lines,line);
i++;
}


Can you please confirm that this is now correct?
That should be OK.

(... it still seg faults when it tries to print)

See other post.
 
K

Kenneth Brody

char ** read_file(char * filename) {
FILE *fptr;
char *line = malloc(LINE_MAX * sizeof(char));
char **lines = 0;
int linelength = 0;
int i = 0; [...]
linelength=strlen(line);
line[linelength]='\0';

This is basically a no-op, as line[strlength] is, by definition,
already '\0'.

[...]
lines=line; [...]
free (line);
return lines;
}

The program currently seems to get through the function okay, but
then seg faults when printing the first line.

[...]

You have pointed every line to the same address, pointed to by
line. (Note that you do not check that line's malloc succeeded.)
You then free() that buffer.

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top