Thread: returning a pointer

  1. #1
    Registered User
    Join Date
    Aug 2001
    Posts
    202

    returning a pointer

    Hi everybody, I've got a bit of a dilemna that I've been trying to solve. I've got a two dimensional array in one function which I need to pass to a calling function. My first instinct was to do this as a return, but aside from the fact that I'm having no success, my research has indicated that this is a bad thing to do. Does anyone out there have any advice for how to move the array to a different function?

    Thanks so much,

    starX
    www.axisoftime.com

  2. #2
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >Does anyone out there have any advice for how to move the array to a different function?
    Is the array local to that function? If so then it would be easiest to wrap the array in a struct and return that. Here is a simple example:
    Code:
    #include <stdio.h>
    #include <string.h>
    
    struct td_array
    {
      char array[10][10];
    };
    
    static struct td_array func ( void )
    {
      struct td_array temp;
      memset ( temp.array, '*', sizeof temp.array );
      return temp;
    }
    
    static void print ( struct td_array tda )
    {
      int i, j;
      for ( i = 0; i < 10; i++ ) {
        for ( j = 0; j < 10; j++ )
          putchar ( tda.array[i][j] );
        putchar ( '\n' );
      }
    }
    
    int main ( void )
    {
      struct td_array a = {0};
      print ( a );
      a = func();
      print ( a );
      return 0;
    }
    -Prelude
    My best code is written with the delete key.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    The easiest (and quickest) way is to declare the array in the calling function, and pass this (as a pointer) to the called function to fill with data as appropriate.

    Code:
    void foo ( int arr[][20] ) {
      // fill in arr as a normal 2D array, being indexed as
      // arr[row][col]
    }
    
    int main ( ) {
      int myarr[10][20];
      foo ( myarr );
      return 0;
    }

  4. #4
    Registered User
    Join Date
    Aug 2001
    Posts
    202
    Thanks for the suggestion, but after playing around with it, I get the idea that it's not going to work because the array is, as you said, local to a function, and is initialized only after a certain value is determined (by another function). I therefore cannot make a global struct definition.

    I'm posting my code so that you can get a better idea of what I'm trying to do specifically. Thanks again for your help.

    starX
    www.axisoftime.com

  5. #5
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Code:
    void *fp, *empty;
    char string[80], *sp, *first_pos, *second_pos, *third_pos, *fourth_pos;
    char *qNumber, *qFile, *qLevel, *qTime;
    int diff, length, length2, i; 
    char *qsht = "qsheet.sht";
    Ug. That's horrible. A huge mass of globals! You generally should avoid globals whenever possible. Poor design.

    Code:
          fgets(string, 81, fp);
          if(feof(fp)) { break; }
    You should test your read for EOF instead of using feof. EOF is the preferred test. Actually, just test the return value of your fgets call.

    After all, that's the whole point of having return values...

    Additionally, you don't EVER want to make fgets use the full buffer. Pass fgets the exact number the buffer contains, or a number LESS than the buffer. Never ever pass it a number larger than the buffer size. fgets is a safe function. There is no need in going out of your way to intentionally break it.

    if( fgets( string, 80, fp ) == EOF ) break;

    Code:
      rewind(fp);
      close(fp);
    There is no point in rewinding your file if you're just closing it anyway.

    Code:
           qNumber = strtok(string, ":");
           qFile = strtok(NULL, ":");
           qLevel = strtok(NULL, ":");
           qTime = strtok(NULL, ":");
    There are much better ways to do things than to use strtok. strtok is a lousy function, IMO.

    Code:
      char* mySheet[4][numOfLines];
    This is a two dimensional array of POINTERS. It has NO MEMORY ALLOCATED for it. (It does, but only pointer space.)

    Furthermore, unless your compiler uses C99, your declaration of this array is not valid C code. Sure, it may work on your compiler, but it isn't portable. You may not care about portability; but there are much better ways to do this. malloc is your friend.

    Additionally, you actually need to malloc some space and copy your strings into them.

    I'll stop for now.

    Quzah.
    Hope is the first step on the road to disappointment.

  6. #6
    Registered User
    Join Date
    Aug 2001
    Posts
    202

    There are much better ways to do things than to use strtok. strtok is a lousy function, IMO.
    care to name some? If there is a better way to tokenize a string, I would love to know what it is.

    starX
    www.axisoftime.com

  7. #7
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    >>>f( fgets( string, 80, fp ) == EOF ) break;
    A minor slip up here fgets() will return NULL, not EOF at the end of a file (or upon error).

    >>>care to name some? If there is a better way to tokenize a string, I would love to know what it is.
    To save me trying to decipher your code, give me a specific example of the input string and what you want done with it. Then I (or someone else) will show you one or more ways to get the desired result.
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

  8. #8
    Registered User
    Join Date
    Aug 2001
    Posts
    202
    field1:field2:field3:field4

    Each field consisting of one or more characters that needs to be split up in such a way so that they can be extracted and converted into different types of data (field 1 is an int, field 2 is a string, and fields 3 and 4 are doubles) for manipulation in a differeent part of the program.

    thanks,

    starX
    www.axisoftime.com

  9. #9
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    The problem with strtok is that it modifys the string passed to it as an argument. This is generally considered bad form. Yeah, it's a standard function, but so is gets...

    Write your own function. It takes a few more lines of code, but it's a better solution.
    Code:
    char *mystrtok( char *s, char start, char end )
    {
        char *retstr = NULL, *sptr, *eptr;
        int len;
    
        if( s != NULL )
        {
            if((sptr = strchr( s, start )) != NULL )
            {
                eptr = strchr( sptr, end );
                len = 1 + (eptr==NULL ? strlen( sptr ):eptr-sptr);
                retstr = malloc( len );
                strncpy( retstr, sptr, len-1 );
                retstr[len-1] = '\0';
            }
        }
        return retstr;
    }
    I think that'll do the trick. I just tossed it together, but it looks right to me. I'm tired though, so it may not do what you want. Compile it and find out.

    Quzah.
    Hope is the first step on the road to disappointment.

  10. #10
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    My shot at this
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    // an array of 4 pointers to char
    typedef char *foo[4];
    
    int getSheetSize ( char *qsht ) {
        char  buff[BUFSIZ];
        int   numOfLines = 0;
        FILE *fp;
    
        fp = fopen(qsht, "r");
        if ( fp == NULL ) {
            printf("open failed\n");
        } else {
            while ( fgets(buff,BUFSIZ,fp) != NULL ) numOfLines++;
            fclose( fp );
        }
        return numOfLines;
    } 
    
    char *dupString ( char *s ) {
        char    *res = NULL;
        if ( s != NULL ) {
            res = malloc( strlen(s) + 1 );
            if ( res != NULL ) strcpy( res, s );
        }
        return res;
    }
    
    foo *splitter ( char *qsht, int numOfLines ) {
        foo    *mySheet = NULL;
        int     i;
        char    buff[BUFSIZ];
        FILE   *fp;
    
        fp = fopen( qsht, "r" );
        if ( fp != NULL ) {
            mySheet = malloc( numOfLines * sizeof(foo) );
            if ( mySheet != NULL ) {
                for ( i = 0 ; i < numOfLines ; i++ ) {
                    fgets( buff, BUFSIZ, fp );
                    mySheet[i][0] = strdup( strtok(buff, ":") );
                    mySheet[i][1] = strdup( strtok(NULL, ":") );
                    mySheet[i][2] = strdup( strtok(NULL, ":") );
                    mySheet[i][3] = strdup( strtok(NULL, ":\n") );  // also removes \n
                }
            }
            fclose( fp );
        }
        return mySheet;
    }
    
    int main ( void ) {
        char *qsht = "qsheet.sht";
        int   size = getSheetSize( qsht );
        foo  *mySheet = splitter( qsht, size );
        int   j;
    
        for ( j = 0 ; j < size ; j++ ) {
            printf( "%s | %s | %s | %s\n",
                mySheet[j][0], mySheet[j][1], 
                mySheet[j][2], mySheet[j][3]);
        }
        return 0;
    }

  11. #11
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Originally posted by Hammer
    >>>f( fgets( string, 80, fp ) == EOF ) break;
    A minor slip up here fgets() will return NULL, not EOF at the end of a file (or upon error).
    Yeah. I was looking at fgetc/fgets on the same page, while on the phone, typing all that up.

    Quzah.
    Hope is the first step on the road to disappointment.

  12. #12
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    >>>while on the phone....
    That damn phone again Quzah
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

  13. #13
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Originally posted by Hammer
    >>>while on the phone....
    That damn phone again Quzah
    Ya know, I have to pay the bills some how...

    Quzah.
    Hope is the first step on the road to disappointment.

  14. #14
    Registered User
    Join Date
    Aug 2001
    Posts
    202
    Thanks for the help everyone, but there are a few things I don't completely understand.

    The first is why do I have to duplicate the string using strdup() before I tokenize it (as per salem's example)?

    The second is when I malloc for mySheet ( mySheet = malloc( numOfLines * sizeof(foo) );) what does this data structure look like? I get that I've created an instance of an array of 4 pointers to char, but how does this look when I malloc it. Yes, I do have an irrational fear of allocating memory :#

    Thanks again,

    starX
    www.axisoftime.com

  15. #15
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    The reason you have to duplicate it is because you read into a buffer, and then read into the buffer, and then read into the buffer and then...

    See the problem? If I read to a variable X, and then read again to X, the first value is lost. So, unless you make a copy of it, you just end up overwriting your data over and over and over.

    Additionally, the contents of the buffer, since it isn't static, is lost when the function returns. So unless you make a duplicate of it by dynamicly allocating some memory and returning a pointer to it, you lose everything you've done in the function.

    And finally, I think Salem got mixed up:

    Code:
    char *dupString ( char *s ) {
        char    *res = NULL;
        if ( s != NULL ) {
            res = malloc( strlen(s) + 1 );
            if ( res != NULL ) strcpy( res, s );
        }
        return res;
    }
    
    ....
    
    mySheet[i][0] = strdup( strtok(buff, ":") );
                    mySheet[i][1] = strdup( strtok(NULL, ":") );
                    mySheet[i][2] = strdup( strtok(NULL, ":") );
    There's no point in having 'dupString' if you don't use it. Maybe Salem was on the phone like I was earlier.

    Quzah.
    Hope is the first step on the road to disappointment.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 07-11-2008, 07:39 AM
  2. towers of hanoi problem
    By aik_21 in forum C Programming
    Replies: 1
    Last Post: 10-02-2004, 01:34 PM
  3. Quick question about SIGSEGV
    By Cikotic in forum C Programming
    Replies: 30
    Last Post: 07-01-2004, 07:48 PM
  4. Another Linked List plee
    By Dragoncaster131 in forum C Programming
    Replies: 3
    Last Post: 05-15-2004, 05:40 PM
  5. returning pointer to string between exe and dll
    By evilpope in forum C Programming
    Replies: 2
    Last Post: 05-15-2003, 12:16 PM