2

I am trying to understand char pointer in C more but one thing gets me.

Supposed I would like to pass a char pointer into a function and change the value that pointer represents. A example as followed:

int Foo (char *(&Msg1), char* Msg2, char* Msg3){
    char *MsgT = (char*)malloc(sizeof(char)*60);
    strcpy(MsgT,"Foo - TEST");
    Msg1 = MsgT; // Copy address to pointer
    strcpy(Msg2,MsgT); // Copy string to char array
    strcpy(Msg3,MsgT); // Copy string to char pointer
    return 0;
}

int main() {
    char* Msg1; // Initial char pointer
    char Msg2[10]; // Initial char array
    char* Msg3 = (char*)malloc(sizeof(char) * 10); // Preallocate pointer memory
    Foo(Msg1, Msg2, Msg3);
    printf("Msg1: %s\n",Msg1); // Method 1
    printf("Msg2: %s\n",Msg2); // Method 2
    printf("Msg3: %s\n",Msg3); // Method 3
    free(Msg1);    
    free(Msg3);
    return 0;
}

In the above example, I listed all working methods I know for passing char pointer to function. The one I don't understand is Method 1.

What is the meaning of char *(&Msg1) for the first argument that is passed to the function Foo?

Also, it seems like method 2 and method3 are widely introduced by books and tutorials, and some of them even referring those methods as the most correct ways to pass arrays/pointers. I wonder that Method 1 looks very nice to me, especially when I write my API, users can easily pass a null pointer into function without preallocate memory. The only downside may be potential memory leak if users forget to free the memory block (same as method 3). Is there any reason we should prefer using Method 2 or 3 instead Method 3?

13
  • 1
    Did you see this example somewhere? Instead of char *(&Msg1), char **Msg1 is commonly used. Commented Jul 22, 2014 at 14:39
  • Unfortunately, that's a note I took for long long time ago. I don't even remember where I got this. I understand how **Msg1 work, but they are different, right? Commented Jul 22, 2014 at 14:44
  • 1
    char *(&Msg1) is C++ pass-by-reference. Commented Jul 22, 2014 at 14:48
  • 2
    Learning both C and C++ at the same is not a good idea! They are sufficiently similar that you may think places where they are very different don't matter much. Commented Jul 22, 2014 at 14:48
  • 1
    @StevenChang it wouldn't compile with a c compiler, but compiles fine with C++ compiler, in C it's considered as syntax error, while in C++, it's considered as reference, if you don't know about references, you should read more about them Commented Jul 22, 2014 at 14:50

2 Answers 2

6

int f(char* p) is the usual way in C to pass the pointer p to the function f when p already points to the memory location that you need (usually because there is a character array already allocated there as in your Method 2 or Method 3).

int f(char** p) is the usual way in C to pass the pointer p to the function f when you want f to be able to modify the pointer p for the caller of this function. Your Method 1 is an example of this; you want f to allocate new memory and use p to tell the caller where that memory is.

int f(char*& p) is C++, not C. Since this compiles for you, we know you are using a C++ compiler.

Sign up to request clarification or add additional context in comments.

4 Comments

Now I got it it's different syntax for different compilers. But if using f(char** p), you need to pass &Msg after initialing the pointer, right? It doesn't look like it's same as Method 1. If coding in C++, which way is preferred and why?
You are correct that you would need to pass &Msg to f(char** p), because Msg is of type char*. In C++ I would prefer f(char*& p), partly because you can just pass Msg, but also because & is a way to clearly indicate that you want pass-by-reference semantics, whereas a char** might just be an array of strings in another context.
Thank you.I think your explanation is brief and clear. This is exact I need.
@StevenChang " for different compilers" -- No, for different languages. " If coding in C++, which way is preferred and why?" -- References are preferred. For why, see stackoverflow.com/questions/10781661/…
0

Consider what happens when you take an argument of type int& (reference to int) :

void f(int &x) {
    x++;
}

void g(int x) {
    x++;
}

int main() {
    int i = 5;
    f(i);
    assert(i == 6);
    g(i);
    assert(i == 6);
}

The same behaviour can be achieved by taking a pointer-to-int (int *x), and modifying it through (*x)++. The only difference in doing this is that the caller has to call f(&i), and that the caller can pass an invalid pointer to f. Thus, references are generally safer and should be preferred whenever possible.

Taking an argument of type char* (pointer-to-char) means that both the caller and the function see the same block of memory "through" that pointer. If the function modifies the memory pointed to by the char*, it will persist to the caller:

void f(char* p) {
    (*p) = 'p';
    p = NULL; //no efect outside the function
}

int main() {
    char *s = new char[4];
    strcpy(s, "die");
    char *address = s; //the address which s points to
    f(s);
    assert(strcmp(s, "pie") == 0);
    assert(s == address); //the 'value' of the variable s, meaning the actual addres that is pointed to by it, has not changed
}

Taking an argument of type char*& ( reference-to-(pointer-to-char) ) is much the same as taking int&: If the function modifies the memory pointed to by the pointer, the caller will see it as usual. However, if the function modifies the value of the pointer (its address), the caller will also see it.

void f(char* &p) {
    (*p) = 'p';
    p = NULL;
}

int main() {
    char *s = new char[4];
    strcpy(s, "die");
    char *address = s; //the address which s points to
    f(s);
    assert(strcmp(address, "pie") == 0); //the block that s initially pointed to was modified
    assert(s == NULL); //the 'value' of the variable s, meaning the actual addres that is pointed to by it, was changed to NULL by the function
}

Again, you could take a char** (pointer-to-pointer-to-char), and modify f to use **p = 'p'; *p = NULL, and the caller would have to call f(&s), with the same implications.

Note that you cannot pass arrays by reference, i.e. if s was defined as char s[4], the call f(s) in the second example would generate a compiler error.

Also note that this only works in C++, because C has no references, only pointers.

You would usually take char** or char*& when your function needs to return a pointer to a memory block it allocated. You see char** more often, because this practice is less common in C++ than in C, where references do not exist.

As for whether to use references or pointers, it is a highly-debated topic, as you will notice if you search google for "c++ pointer vs reference arguments".

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.