user2736738
user2736738

Reputation: 30926

how passing char* to a function works?

I have tried this code!I can't understand how it works.

     int main()
     {
         char *s1;
         s1=malloc(sizeof(char)*20);
         strcpy(s1,"main");
         printf("%s\n",s1);
         func(s1);
         printf("After call %s\n",s1);
         return 0;
      }
      void func(char *s2)
      {
         //free(s2);<--------------(this is what I'm talking about)
         s2=malloc(sizeof(char)*25);
         strcpy(s2,"func");
         printf("fun---%s\n",s2);
      }

Output:

     main
     fun---func
     After call main

But if in func() I add the commented line output is

Outout:

     main
     fun---func 
     After call main

I want to know how the whole thing works. I mean s1 is char*. After allocating it points to a chunk of memory. In C everything is pass by value. So when we pass it there will another variable created in the local scope of (stack) main that holds the address of the chunked memory (i.e., s1 contains this same value).

Is this the correct idea? If not please clear the concept. In Windows it gave the result as I have told you. But in Linux it was somehow reflecting the change.

What am I missing?

Upvotes: 2

Views: 3750

Answers (3)

paxdiablo
paxdiablo

Reputation: 881553

You're (mostly) correct.

Freeing s2 (and hence s1) in the function then using s1 on return to main() is what's known as undefined behaviour.

You shouldn't do it because the standard mandates that pretty much anything is allowed to happen and, here's the rub, that "anything" includes the possibility that it will work.

Why it's working is almost certainly because no-one else has allocated that memory block again and overwritten the data in it, so it still contains what was originally in there.

If, in your main() between the call to func() and the printing of s1, you inserted:

char *s3 = malloc(10000);
strcpy (s3, "Yoohoo, I'v changed");

then you may well find that printing s1 will give you a different result.

Or, since it's UB, maybe not :-)

It's advisable to avoid undefined behaviour even if it seems to work. Changing your compiler, or compiler flags, or order of the code, or even compiling on a blue moon, may change how your code works in unexpected ways.


If you want to pass back a pointer allocated in a function (other than by just using return), you can use double indirection:

void allocStr (char **pStr) {
    free (*pStr);
    *pStr = malloc (1000);
}
:
char *xyzzy = NULL;
allocStr (&xyzzy);

This is how you do pass-by-reference in C.

Upvotes: 5

Some programmer dude
Some programmer dude

Reputation: 409176

(This doesn't answer your question, but it's to much to put in a comment.)

To make it work without undefined behavior you need to pass the pointer by reference (or rather, since it's not possible in C you have to emulate pass by reference semantics). This can be done by passing a pointer to the pointer, then you can change it in the function.

Something like

void func(char **s2);  // Pointer to pointer

int main(void)
{
    char *s1 = malloc(20);  // No need for `sizeof` as `sizeof(char)` is always 1
    strcpy(s1, "main");
    func(&s1);  // Note use of `&` address-of operator
}

void func(char **s2)
{
    free(*s2);  // Note use of dereference operator `*`
    *s2 = malloc(20);
    strcpy(*s2, "func");
}

Upvotes: 3

Donald
Donald

Reputation: 19

The whole thing works exactly as you said. The reason you didn't get garbage on the second run when dereferencing a stale pointer (s2 pointing to freed memory) is, that the system just hadn't reused the memory yet.

Upvotes: 0

Related Questions