tags:

views:

40

answers:

3

How can I allocate memory for a struct pointer and assign value to it's member in a subfunction?

The following code will compile but not execute:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct _struct {char *str;};
void allocate_and_initialize(struct _struct *s)
{
    s = calloc(sizeof(struct _struct), 1);
    s->str = calloc(sizeof(char), 12);
    strcpy(s->str, "hello world");
}
int main(void)
{
    struct _struct *s;
    allocate_and_initialize(s);
    printf("%s\n", s->str);

    return 0;
}
+2  A: 

You are passing s by value. The value of s is unchanged in main after the call to allocate_and_initialize

To fix this you must somehow ensure that the s in main points to the memory chunk allocated by the function. This can be done by passing the address of s to the function:

// s is now pointer to a pointer to struct.
void allocate_and_initialize(struct _struct **s)
{
        *s = calloc(sizeof(struct _struct), 1); 
        (*s)->str = calloc(sizeof(char), 12);
        strcpy((*s)->str, "hello world");                                                                                                                                                                      
}
int main(void)
{
        struct _struct *s = NULL;  // good practice to make it null ptr.
        allocate_and_initialize(&s); // pass address of s.
        printf("%s\n", s->str);

        return 0;
}

Alternatively you can return the address of the chunk allocated in the function back and assign it to s in main as suggested in other answer.

codaddict
In other words: you want a pointer to a pointer.
Daniel
Why add more indirection when you could just return a value?
Philip Potter
+1  A: 

In your example:

void allocate_and_initialize(struct _struct *s)
{
    s = calloc(sizeof(struct _struct), 1);
    s->str = calloc(sizeof(char), 12);
    strcpy(s->str, "hello world");
}

Assigning to s here doesn't change s in the caller. Why not return it instead?

struct _struct *allocate_and_initialize(void) {
    struct _struct *s;
    s = calloc(sizeof *s, 1);
    s->str = calloc(1, 12); /* sizeof(char) is always 1 */
    strcpy(s->str, "hello world");
    return s;
}

and use it thus:

struct _struct *s;
s = allocate_and_initialize();
/* use s... */
free(s); /* don't forget to free the memory when you're done */
Philip Potter
Thanks for the suggestion, Philip!In my actual code the subfunction allocates multiple stucts and returns the number of alloceted structs. So the return value is no longer available.
ClosedID
@0penid then I would say you need to rethink your design. If the multiple structs are all related, they should be in one big struct. If they are not, they shouldn't be initialised by one big function, but by individual initialiser functions.
Philip Potter
+1  A: 

you must change your code like that:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    struct _struct {char *str;};
    void allocate_and_initialize(struct _struct **s)
    {
        *s = (_struct*)calloc(sizeof(struct _struct), 1);
        (*s)->str = (char*)calloc(sizeof(char), 12);
        strcpy((*s)->str, "hello world");
    }
    int main(void)
    {
        struct _struct *s;
        allocate_and_initialize(&s);
        printf("%s\n", s->str);

        return 0;
    }

The reason is, that you change the adress of the pointer, but not the "content" of the pointer. So, if you code in c, you have to use a "double" pointer. If you code in c++ you can use a reference.

itsme
Thanks, itsyou :)
ClosedID