Petr Marek
Petr Marek

Reputation: 71

Allocate structure in another function in c

how can I allocate memory for structure in another function than where is structure variable declared?

typedef struct{
    char *IP_req;
} ARGS;

int main(int argc , char *argv[]){
    ARGS *args = NULL;
    mal(argc, argv, &args);
    printf("arg IP:%s\n", &args->IP_req);
    return 0;
}

Function where I want to allocate:

int mal(int argc , char *argv[], ARGS *args){
    args=malloc(sizeof (ARGS));
    args->IP_req = (char*)malloc(sizeof(char) * 200);
    strcpy(args->IP_req,"12.21.51.88");
    printf("arg IP:%s\n", args->IP_req);
    return 0;
}

When I compile this program, I get:
arg IP:12.21.51.88
arg IP:(null)

But I expected (and want):
arg IP:12.21.51.88
arg IP:12.21.51.88

Upvotes: 1

Views: 85

Answers (2)

Eric Postpischil
Eric Postpischil

Reputation: 223254

Finding the Error

This statement in main:

mal(argc, argv, &args);

says to pass the address of args to mal. The type of args is ARGS *, so the type of &args is ARGS **.

This definition of mal:

int mal(int argc , char *argv[], ARGS *args)

says that the args parameter has type ARGS *. Since main is passing an ARGS **, not an ARGS *, this is an error.

If you are using your compiler correctly, it should have warned you about one of the following things:

  • In main, no declaration of mal is visible.
  • In main, the call to mal does not match its declaration.
  • The definition of mal does not match its declaration.

If the compiler did not warn you about at least one of those, then you need to ensure two things are done:

  • Turn on or increase warnings in your compiler. If you are using GCC or Clang via the command line, add -Wall to the command line switches. If you are using another interface or another compiler, refer to its documentation.
  • Put a declaration of mal in a header file and use #include to include that header file in both the source file containing main and the source file containing mal.

Putting the declaration in a header file and including that file in each source file is a better solution than copying the declaration to each source file because it ensure each source file uses the same declaration. And enabling compiler warnings—and paying attention to them—ensure there is a complete chain checking the types—the use of mal in main is connected to its declaration, and its declaration is connected to its definition. This enables to compiler to do all the type checking.

Fixing the Error

One way to fix the error is to make the definition of mal match how you call it in main. To do this, change the definition of mal to make args have type ARGS **:

int mal(int argc , char *argv[], ARGS **args)

Then inside, mal, since the type of args has changed, you need to use *args to refer to the ARGS * that main has passed to it:

*args = malloc(sizeof (ARGS));
(*args)->IP_req = malloc(sizeof(char) * 200);
strcpy((*args)->IP_req,"12.21.51.88");
printf("arg IP:%s\n", (*args)->IP_req);
return 0;

Other Notes

In main, when printing a string with %s, do not pass the address of the array, as in printf("arg IP:%s\n", &args->IP_req);. Pass the address of the first element of the array, using printf("arg IP:%s\n", args->IP_req);. (Although args->IP_req initially refers to the array, it is, in this and most contexts, automatically converted to a pointer to its first element.)

In C (unlike C++), you do not need to cast the result of malloc, so args->IP_req = (char*)malloc(sizeof(char) * 200); can be just args->IP_req = malloc(sizeof(char) * 200);.

When calculating sizes to pass to malloc, it is better to use sizeof in this way:

*args = malloc(size **args);
args->IP_req = malloc(200 * sizeof *args->IP_req);

This way, the size of the object being allocated is automatically used—if later edits to the code change the type where args or args->IP_req is declared, these expressions automatically use the new size. It would be necessary to change the type in two or more places (one at the declaration and one in each malloc).

Upvotes: 1

Adrian Mole
Adrian Mole

Reputation: 51864

As pointed out in the comments by @PaulOgilvie, the last argument to mal should be a pointer to a pointer:

int mal(int argc , char *argv[], ARGS **args) { // **args poits to the pointer to be allocated
    *args = malloc(sizeof (ARGS)); // And all other 'args' herein should be dereferenced
    (*args)->IP_req = (char*)malloc(sizeof(char) * 200);
    strcpy((*args)->IP_req,"12.21.51.88");
    printf("arg IP:%s\n", (*args)->IP_req);
    return 0;
}

Your call in main: mal(argc, argv, &args); is correct.

Upvotes: 1

Related Questions