Problems with function that returns a pointer to array of strings

Discussion in 'C Programming' started by paktsardines@gmail.com, Jul 31, 2007.

  1. Guest

    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.
     
    , Jul 31, 2007
    #1
    1. Advertising

  2. Ian Collins Guest

    wrote:
    > 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.

    --
    Ian Collins.
     
    Ian Collins, Jul 31, 2007
    #2
    1. Advertising

  3. Guest


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


    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)
     
    , Jul 31, 2007
    #3
  4. On Jul 30, 10:34 pm, wrote:
    > 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.
     
    Justin Spahr-Summers, Jul 31, 2007
    #4
  5. Ian Collins Guest

    wrote:
    > 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.

    --
    Ian Collins.
     
    Ian Collins, Jul 31, 2007
    #5
  6. Ian Collins Guest

    wrote:
    >> 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.

    --
    Ian Collins.
     
    Ian Collins, Jul 31, 2007
    #6
  7. Guest

    Thank you Ian and Justin, it now works a treat.
     
    , Jul 31, 2007
    #7
  8. wrote:
    [...]
    > 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:>
     
    Kenneth Brody, Jul 31, 2007
    #8
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Boris Sargos
    Replies:
    3
    Views:
    392
    John Harrison
    Apr 23, 2004
  2. Replies:
    12
    Views:
    1,045
    Keith Thompson
    Sep 17, 2005
  3. sqweek
    Replies:
    2
    Views:
    415
    Charles Rapp
    Jan 13, 2006
  4. , India

    pointer to an array vs pointer to pointer

    , India, Sep 20, 2011, in forum: C Programming
    Replies:
    5
    Views:
    465
    James Kuyper
    Sep 23, 2011
  5. Srijayanth Sridhar
    Replies:
    19
    Views:
    640
    David A. Black
    Jul 2, 2008
Loading...

Share This Page