Thread: realloc() problems

  1. #1
    Registered User
    Join Date
    Oct 2005
    Posts
    12

    realloc() problems

    Okay, I'm trying to learn how to dynamically allocate memory, and I figure the best way to do it is to try to make something with it and learn as I go.

    Code:
    //main.c
    
    #include <stdio.h>
    #include <stdlib.h>
    #include "parser.h"
    
    int main(void)
    {
    	//...
    	Room forest;
    	//...
    	initializeVerbs(&forest, 4, "get", "drop", "take", "use");
    	//...
    	return 0;
    }
    
    //parser.h --------------
    
    #ifndef PARSER_H
    #define PARSER_H
    
    typedef struct Room
    {
    	short unsigned nVerbs;
    	short unsigned nNouns;
    	char *verbs;
    	char *nouns;
    } Room;
    
    void initializeVerbs(struct Room *room, unsigned int nargs, const char *arg, ...);
    //...
    
    #endif
    
    //parser.c ---------------
    
    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    #include <stdarg.h>
    #include <stdlib.h>
    #include "parser.h"
    
    void initializeVerbs(Room *room, unsigned int nArgs, const char *arg, ...)
    {
    	unsigned count;
    	unsigned length = 0;
    	va_list ap;
    	char *stuff;
    	printf("Step 1.\n");
    	room->nVerbs = nArgs;
    	printf("Step 2.\n");
    	va_start(ap, arg);
    	for(count = 1; count < nArgs; count++)
    	{
    		length += (strlen(arg) + 1);
    		printf("sizeof(verbs): %i\n", sizeof(room->verbs));
    		printf("length = %i\n", length);
    		realloc(room->verbs, length); /*problem*/
    		room->verbs[length] = arg; /*Causes problems.*/
    		arg = va_arg(ap, const char *);
    	}
    	printf("Length: %i\n", length);
    }
    Okay, what I'm trying to do is this. I want the user to be able to initialize as many verbs as he wants, and I want them all in one char pointer. nVerbs holds how many there are, so I can search through them later by going past the null terminator.

    However...I have no idea what I'm doing. Please help.

    Thanks

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    You don't want a single character pointer for this. If you do, you'll end up with a single string, like so:
    Code:
    "jump run dance drink puke passout"
    I suspect you really want this:
    Code:
    "jump"
    "run"
    "drink"
    "puke"
    "passout"
    , so you can do:
    Code:
    if( strcmp( action, room->verb[x] ) == 0 )
        printf("You %s!\n", room->verb[x] );
    And get fun output like:
    Code:
    You drink!
    At any rate, you want a pointer to a pointer. Then you realloc the number of pointers you need, which preserves all of the pointers to the verbes you currently have...

    Also, you'll likely want to malloc up a new copy of each verb, and use something like strcpy to copy the passed argument into space allocated for your verb list.


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

  3. #3
    Registered User
    Join Date
    Oct 2005
    Posts
    12
    Still having troubles. I changed

    Code:
    char *verbs;
    to
    Code:
    char **verbs;
    and made these changes...
    Code:
    void initializeVerbs(Room *room, unsigned int nArgs, const char *arg, ...)
    {
    	unsigned short size = 0;
    	char *temp;
    	va_list ap;
    	printf("Step 1.\n");
    	room->nVerbs = nArgs;
    	printf("Step 2.\n");
    	va_start(ap, arg);
    	for( ; nArgs; --nArgs)
    	{
    		printf("sizeof(verbs): %i\n", sizeof(room->verbs));
    		temp = (char *)malloc(sizeof(arg));
    		realloc(room->verbs, ++size);
    		strcpy(room->verbs[size], temp);
    		arg = va_arg(ap, const char *);
    	}
    }
    Still getting evil errors. Thanks for all the help so far, though.

  4. #4
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    First, figure out how many verbs you have. Allocate that many pointers, and if you like, for an easy way to find out when you're at the end of the verb list, one more, which is always set to NULL. Then, allocate space for each pointer, except for the optional NULL one, for each verb that goes there. Then copy each verb to its spot in the list of verbs.


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

  5. #5
    Registered User
    Join Date
    Aug 2005
    Posts
    1,267
    Code:
    temp = (char *)malloc(sizeof(arg));
    malloc() will only allocate 4 bytes on 32-bit compilers because sizeof(any pointer) is always 4. sizeof operator does not return the length of the string.

  6. #6
    Registered User
    Join Date
    Oct 2005
    Posts
    12
    Yes! I got it to work. Thanks, both of you.

    Here's my current code:

    Code:
    void initializeVerbs(Room *room, unsigned int nArgs, const char *arg, ...)
    {
    	unsigned short size = 0;
    	char *temp;
    	va_list ap;
    	room->nVerbs = nArgs;
    	va_start(ap, arg);
    	room->verbs = (char **)malloc(sizeof(char *) * nArgs);
    	for( ; nArgs; --nArgs, ++size)
    	{
    		temp = (char *)malloc(strlen(arg) + 1);
    		strcpy(temp, arg);
    		room->verbs[size] = temp;
    		arg = va_arg(ap, const char *);
    	}
    }
    Now, this works. But I'm curious if there's a better way. Is it more efficient to implement the additional NULL pointer at the end in exchange for the nVerbs counter?

  7. #7
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    The reason I suggest the use of an extra NULL at the end is because then you can do simple things like this:
    Code:
    for( x = 0; room->verbs[ x ]; x++ )
        printf("verb: %s\n", room->verbs[ x ] );
    And just run through the whole list of verbs. It'll hit the NULL, see it's at the end of the list, and stop the loop. It's another way around storing how many verbs you have. However, if you're already storing the verb count some place, you don't need to do this.


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

  8. #8
    Registered User
    Join Date
    Oct 2005
    Posts
    12
    Thanks so much!

    But now I am lost ONCE AGAIN! (Woot.)

    I know I have to free() these allocations once I'm done with them. If I'm going to have an indefinite number of structures, each with its own set of verbs, how can I accomplish this?

  9. #9
    Registered User
    Join Date
    Aug 2005
    Posts
    1,267
    you could allocate 1 more pointer than necessary and set the last one to NULL
    Code:
    room->verbs = (char **)malloc( sizeof(char**) * (nArgs+1)));
    
    room->verbs[nArgs] = NULL;
    Then when its time to free all that stuff, loop until the NULL pointer is reached
    Code:
    int i;
    
    for(i = 0; room->verbs[i] != NULL; i++)
       free(room->verbs[i]);
    free(room->verbs);
    Last edited by Ancient Dragon; 10-26-2005 at 01:52 PM.

  10. #10
    Registered User
    Join Date
    Oct 2005
    Posts
    12
    Yes, but...we're going to have somewhere in the neighborhood of 200 rooms. I don't want us to have to call a "myRoomFree()" function 200 times before the end of the program. It's annoying and widely open to bugs due to minor changes.

    Basically, I'm looking for a C version of a desconstructor.

  11. #11
    Registered User
    Join Date
    Aug 2005
    Posts
    1,267
    another way is to allocate just one huge block of memory
    Code:
    char* memory = malloc( MaxNumRooms * MaxNumVerbs * MaxVerbLength );
    Now, write your own allocation function that divvies up memory from that memory pool. When you want to free it, you only have one object to free. There will probably be some wasted memory here, but that's the down side of simplicity.

  12. #12
    Registered User
    Join Date
    Oct 2005
    Posts
    12
    Those Max values are exactly what I'm trying to avoid. See, if I just wanted to take the easy way out, I'd just have pointer arrays with, say, 100 characters each to hold the verbs. That's easy, and there's no memory deallocation to take care of.

    But I don't WANT to do that. I'd really like to learn how to manage my memory. That's all this is to me: a learning experience. If I take the easy way out, I've gained nothing.

    So, thanks, but I'd really like to learn how to free() effectively.

  13. #13
    Registered User
    Join Date
    Aug 2005
    Posts
    1,267
    C language doesn't have a very efficient memory manager -- that's one reason c++ invented destructors. If you are looking for a substitute for c++ descructors, then you will be looking for a very very long time, because there isn't one.

  14. #14
    Ultraviolence Connoisseur
    Join Date
    Mar 2004
    Posts
    555
    Quote Originally Posted by DMH
    Yes, but...we're going to have somewhere in the neighborhood of 200 rooms. I don't want us to have to call a "myRoomFree()" function 200 times before the end of the program. It's annoying and widely open to bugs due to minor changes.

    Basically, I'm looking for a C version of a desconstructor.
    You could always just not free the memory...... :P At the end of the program it will all get unallocated anyways (depending on your OS that is....)

  15. #15
    Registered User
    Join Date
    Oct 2005
    Posts
    12
    Is that universal enough that I can count on it?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. did i understood right this explantion of realloc..
    By transgalactic2 in forum C Programming
    Replies: 3
    Last Post: 10-24-2008, 07:26 AM
  2. using realloc
    By bobthebullet990 in forum C Programming
    Replies: 14
    Last Post: 12-06-2005, 05:00 PM
  3. Realloc problems with sturcture array inside structure
    By daveyand in forum C Programming
    Replies: 2
    Last Post: 03-29-2004, 06:48 AM
  4. realloc problems
    By Benzakhar in forum C++ Programming
    Replies: 2
    Last Post: 12-31-2003, 12:31 PM
  5. Realloc inappropriate for aligned blocks - Alternatives?
    By zeckensack in forum C Programming
    Replies: 2
    Last Post: 03-20-2002, 02:10 PM