Thread: Problems Returning A char**

  1. #1
    Registered User
    Join Date
    Nov 2010
    Posts
    6

    Problems Returning A char**

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    FILE *in;
    char **readFile();
    
    void main()
    {
    	in = fopen("sentences.in", "rt");
    	char **warr = readFile(in);
    	printf("%s\n", warr[0]);
    }
    
    char **readFile(FILE *in)
    {
    	char *word, **warr;
    	int toGen = 0;
    	word = (char*)malloc(25 * sizeof(char));
    	warr = (char**)malloc(25 * sizeof(char*));
    	fscanf(in, "%d", &toGen);
    	for(int i = 0; i < 28; ++i)
    	{
    		fscanf(in, "%s", word);
    		if(i >= 28)
    		{
    			printf("Only %d words can be used in your input file.", 20);
    		}
    		warr[i] = calloc(strlen(word) + 1, sizeof(char));
    		strcpy(warr[i], word);
    		printf("warr[%d]: [%s] Length Of Word: %d\n", i, warr[i], strlen(word));
    	}
    	return warr;
    }
    Having problems with returning warr back into main from readFile.
    Prints perfect in readFile
    Code:
    printf("warr[%d]: [%s] Length Of Word: %d\n", i, warr[i], strlen(word));
    Won't print in main
    Code:
    printf("%s\n", warr[0]);
    Anyone know what I'm doing wrong?

  2. #2
    Registered User
    Join Date
    Jun 2009
    Posts
    486
    The warr in main and the warr in the function are two different variables. Returning the address of a local variable is never a good idea.

    You need to allocate memory for warr in main, and pass is as a parameter into your function, like I told you in your last thread.

  3. #3
    Registered User
    Join Date
    Nov 2010
    Posts
    6
    Ah ok I didn't understand what you meant last time... that fixed it"

    Code:
    void main()
    {
    	in = fopen("sentences.in", "rt");
    	char **warr = (char**)malloc(50 * sizeof(char*));
    	warr = readFile(in, warr);
    	printf("%s\n", warr[0]);
    }
    
    char **readFile(FILE *in, char **warr)
    {

  4. #4
    Registered User
    Join Date
    Jun 2009
    Posts
    486
    also, main should be declared as
    Code:
    int main(void)
    and it should
    Code:
    return 0;
    At the end.

  5. #5
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    You don't need to typecast malloc.

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

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    > Returning the address of a local variable is never a good idea.
    But it isn't returning the address of a local.
    It IS returning the value of a pointer.

    This is returning an array - which as you said is wrong.
    Code:
    char *foo ( ) {
        char myLocalArray[100];
        return myLocalArray;
    }

    > You need to allocate memory for warr in main, and pass is as a parameter into your function
    It is A way of doing it for sure, but if the number of words isn't known in main, you're still stuck.

    Anyway, the program works, with the bugs fixed.
    The killer bug being the array overrun.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h> //!! added
    
    FILE *in;
    char **readFile();
    
    int main()  //!! fixed
    {
        in = fopen("sentences.in", "rt");
        char **warr = readFile(in);
        printf("%s\n", warr[0]);
        return 0;     //!! fixed
    }
    
    char **readFile(FILE *in)
    {
        char *word, **warr;
        int toGen = 0;
        word = malloc(25 * sizeof(char));
        warr = malloc(28 * sizeof(char*));  //!! FIXED !!!!!!
        fscanf(in, "%d", &toGen);
        for(int i = 0; i < 28; ++i)
        {
            fscanf(in, "%s", word);
    /*        if(i >= 28)
            {
                printf("Only %d words can be used in your input file.", 20);
            }*/
            warr[i] = calloc(strlen(word) + 1, sizeof(char));
            strcpy(warr[i], word);
            printf("warr[%d]: [%s] Length Of Word: %d\n", i, warr[i], strlen(word));
        }
        return warr;
    }
    Dajre, start using some symbolic names for the sizes of things.
    Spraying random literal constants all over the place will cause trouble.

    Code:
        int numWords = 28;
        warr = malloc(numWords * sizeof(char*));
        for(int i = 0; i < numWords; ++i)
    would not have dug the hole you fell into.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User
    Join Date
    Jun 2009
    Posts
    486
    I'm pretty sure I have had trouble doing this before, where declaring and mallocing something in a function and then returning that local variable, specifically an array, led to garbage results.

    That said, I have not tested this myself, so I defer to your greater experience, however, I think that the safest route is to declare warr outside the function and pass it in. You can malloc it in the function just fine, as long as you return the pointer, but declare it outside to be safe:

    Code:
    int main()  //!! fixed
    {
        in = fopen("sentences.in", "rt");
        char **warr = readFile(in, warr);
        printf("%s\n", warr[0]);
        return 0;     //!! fixed
    }
    
    char **readFile(FILE *in, char **warr)
    {
        char *word;
        int toGen = 0;
        word = malloc(25 * sizeof(char));
        warr = malloc(28 * sizeof(char*));  //!! FIXED !!!!!!
        fscanf(in, "%d", &toGen);
        for(int i = 0; i < 28; ++i)
        {
            fscanf(in, "%s", word);
    /*        if(i >= 28)
            {
                printf("Only %d words can be used in your input file.", 20);
            }*/
            warr[i] = calloc(strlen(word) + 1, sizeof(char));
            strcpy(warr[i], word);
            printf("warr[%d]: [%s] Length Of Word: %d\n", i, warr[i], strlen(word));
        }
        return warr;
    }
    it is entirely possible that this makes no difference at all, but my gut feeling here is that this is the safer route.

    And incidentally, warr needs to be free'd, and so does word.

  8. #8
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    That's a pretty terrible way to do it. You can't free word, because you've exited the function, and you didn't retain a pointer to it. You've just caused a memory leak. Not only does warr need to be freed, but every pointer in that list of pointers needs freed too.


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

  9. #9
    Registered User
    Join Date
    Jun 2009
    Posts
    486
    Well, the best way to do it would be to get rid of word completley and just use warr in there, which can be freed in main afterwards.

  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
    > where declaring and mallocing something in a function and then returning that local variable, specifically an array, led to garbage results.
    Well you could find a previous example and post it, then perhaps we can clarify the problem for you.

    > That said, I have not tested this myself, so I defer to your greater experience,
    Don't take my word for it - test it yourself.

    > I think that the safest route is to declare warr outside the function and pass it in.
    Which in your example does precisely nothing at all.
    All you did was move the declaration of the variable from being a local variable to being a value parameter (which for all practical purposes is still a local variable).

    > char **warr = readFile(in, warr);
    What is the value of warr being passed into the function at this point? Answer - garbage.

    You could just as easily done
    char **warr = readFile(in, NULL);
    I'm just wondering if you think there is a NULL pointer dereference going on at this point.

    Compiling with gcc, I get
    foo.c: In function ‘main’:
    foo.c:9: warning: ‘warr’ is used uninitialized in this function

    > warr = malloc(28 * sizeof(char*));
    What use was made of the input value of warr? None at all, which is a good thing, because it was garbage.

    Use the debugger, trace both versions through and pay close attention to the warr pointer as you go.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  11. #11
    Registered User hellork's Avatar
    Join Date
    Nov 2010
    Posts
    39
    This is how that code could (sort of) potentially work, even though I think after looking at this that it is fundamentally the wrong way of doing it. Song names can not have spaces in them, are truncated to LENGTH, and limited to LINES. Ugh. I would prefer to read it through fgets() and malloc to the file size and then just split out the variable-length strings on '\n' as needed.

    Nevertheless, this has one feature I like. The function is almost ad hoc polymorphic. Call it with 0 to free the memory before using it on each successive file.

    Limitations: To add to the above complaints, it is not reentrant and can only handle one open file at a time.

    Please excuse all the token pasting. I got glue on my fingers.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #define WIDTH 10
    #define LINES 3
    #define FB(arg) #arg
    #define FMT(arg) "%"FB(arg)"s"
    #define MFMT(arg) "warr[%2d]: [%-"FB(arg)"s] length %d\n"
    char **readFile (char *name);
    /* main */
    int main (int argc, char **argv) {
        int i = 0;
        char **hlist = readFile ("wordlist.in");
        if (hlist) {
            while (hlist[i]) {
                printf ("%s\n",hlist[i++]);
            }
            /* free memory */
            readFile (0);
        } else {
            return 42;
        } return 0;
    }
    /* read file */
    char **readFile (char *name) {
        static char **warr;
        int i;
        FILE *in;
        if (name) {
            if ((in = fopen (name, "r"))) {
                warr=malloc ((LINES+1) * sizeof warr);
                for (i=LINES;i--;) {
                    warr[i]=malloc (WIDTH+1);
                    if (!warr[i]) {
                        perror ("malloc");
                        exit (1);
                }   } for (i=0;i<LINES&&fscanf (in, FMT(WIDTH), warr[i])!=EOF;i++) {
                    printf (MFMT(WIDTH), i, warr[i], (int)strlen(warr[i]));
                } warr[i]=0;fclose(in);
                return warr;
            } else {
                perror ("fopen");
        }   } else {
            for (i=LINES;i--;) {
                free (warr[i]);
            } free (warr);
            printf ("memory freed!\n");
        } return NULL;
    }
    generated from pseudocode with Anchor | freshmeat.net

  12. #12
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    You don't need a static pointer to successfully return a T** from a function. You also have a problem with your malloc line. You are allocating the size of a T**, instead of T*.

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

  13. #13
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    > Call it with 0 to free the memory before using it on each successive file.
    Yeah, that's pretty puke inducing.

    What if I want to store the result of reading TWO files?
    That pretty much means I have to do the whole thing myself - duplicate the results of whatever the first file reads, then manually free all that when I'm done.

    Re-usable code doesn't keep magic hidden static variables lying around.


    > warr[i] = 0;
    What's this supposed to do?

    It looks like a memory leak to me.
    Seeing how you trash some previously allocated warr[i]

    While I'm in a pedantic mood, you should check ALL your malloc calls.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Most Common problems in C
    By Bayint Naung in forum C Programming
    Replies: 18
    Last Post: 06-02-2010, 08:20 PM
  2. No clue how to make a code to solve problems!
    By ctnzn in forum C Programming
    Replies: 8
    Last Post: 10-16-2008, 02:59 AM
  3. Problems passing a file pointer to functions
    By smitchell in forum C Programming
    Replies: 4
    Last Post: 09-30-2008, 02:29 PM
  4. Problems returning char *
    By Necromancer in forum C Programming
    Replies: 10
    Last Post: 01-30-2008, 11:28 AM
  5. Returning references (scope problems?)
    By DarkDragon in forum C++ Programming
    Replies: 3
    Last Post: 12-23-2001, 07:48 PM