3

my original problem is that I want to write a function that can return me two values. I know that I can do it by passing the address of the two arguments to the function, and directly calculate their values inside that function. But when doing experiment, something weird happens. The value I got inside the function cannot survive to the main function:

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

void build(char *ch){
   ch = malloc(30*sizeof(char));
   strcpy(ch, "I am a good guy");
}

void main(){
   char *cm;
   build(cm);
   printf("%s\n", cm);
}

The above program just prints out some garbage. So I want to know what's wrong here. Eventually, I want something like this parse(char **argv, char **cmd1, char **cmd2), which can parse out two commands for me from the original command argv. That would be great if anybody can explain a little bit. Thanks a lot.

3
  • char **ch... ... *ch = malloc... ... strcpy(*ch... ... build(&cm) ... Commented Jan 25, 2014 at 7:05
  • You need of Pointer to pointer Commented Jan 25, 2014 at 7:10
  • Think of it this way; if a function takes an argument n and said function wants to assign a new value to n (n = ...) then a level of indirection is required, i.e., you need a pointer to n (typeof_n*). All function arguments in C are passed by value, i.e., a copy is made. So, since you pass in a char*, you need a pointer to one of those, i.e., a char**. Then you can write *n = malloc(size);. Also, sizeof char is defined to be 1, so no need for that in your malloc call. Commented Jan 25, 2014 at 7:12

3 Answers 3

5

build() take the pointer ch by value, i.e. a copy of the pointer is passed to the function. So any modifications you make to that value are lost when the function exits. Since you want your modification to the pointer to be visible in the caller's context, you need to pass a pointer to pointer.

void build(char **ch){
   *ch = malloc(30*sizeof(char));
   strcpy(*ch, "I am a good guy");
}

Also, you don't need to pass pointers to a function because you need to return multiple values. Another option is to create a struct that contains the values you wish to return as members, and then return an instance of said struct. I'd recommend this approach over the first if the values are related and it makes sense to package them together.


Here's a re-listing of your code after fixing bugs:

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

void build(char **ch){
   *ch = malloc(30 * sizeof(char));
   strcpy(*ch, "I am a good guy");
}

int main() {     // main must return int
   char *cm;
   build(&cm);   // pass pointer to pointer
   printf("%s\n", cm);
   free(cm);     // free allocated memory
   return 0;     // main's return value, not required C99 onward
}
Sign up to request clarification or add additional context in comments.

2 Comments

Might help to point out the usage: build(&cm);
// main must return void I believe you mean // main must return int
1

If you want to malloc inside the function, you need to pass the address to the outside pointer since ch inside the function is only a local variable, and changing it doesn't affect the outside cm variable

void build(char **ch){
   *ch = malloc(30*sizeof(char));
   strcpy(*ch, "I am a good guy");
}

void main(){
   char *cm;
   build(&cm);
   printf("%s\n", cm);
}

But better don't malloc inside the function, instead just write what you want to the area pointed to by the pointer. This is the common way when you need to provide a buffer to get data in C. In this way users will have the choice to allocate memory their own, or just use a local buffer and don't need to free memory after that like you've just forgotten in your example

void build(char *ch){
   strcpy(ch, "I am a good guy");
}

void main(){
   char *cm1;
   cm1 = malloc(30*sizeof(char));
   build(cm1);
   printf("%s\n", cm1);

   char cm2[30];
   build(cm2);

   printf("%s\n", cm2);   
   free(cm1);           // don't forget this
}

2 Comments

wow, thanks a lot. This is really a clean way. But could you detail why here we can just pass cm1 and cm2 by value, not by address? thanks.
as I said, we want to deal with the data, not the pointer, so we pass the address to the buffer/data instead allowing the function to modify the pointer. Callers often declare a local array instead of calling malloc because it's faster and automatically end its life after the scope ends, diminish the chance to forget freeing memory like your case. You see, memcpy or strcpy is also an example of this. It accepts the pointer to data, not the pointer's address
0

This is because in C, you cannot reassign the memory address of the pointer because it is passed by value.

If you really want to do this, you must pass the address of the pointer into the build function.

See: Passing pointer argument by reference under C?

4 Comments

"you cannot reassign the value of the memory address of where the pointer is pointing to, because it is passed by value." - Sure you can. You cannot however assign a new value to the pointer itself and expect it to be visible to the caller. You can assign a new value to what the pointer refers to because you already have the necessary level of indirection.
I suppose I worded this wrong; I meant you cannot make the pointer point to a different memory address since it is passed by value. Of course you can change the value, that's the whole point of using a pointer (pun intended)
That would be correct. Edit that bit and I'll remove my downvote.
Done. (Plus this extra comment because the comment above isn't long enough to post...)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.