4

In C, why is it that I'm able to pass character arrays to functions that take a char * as an argument, but I cannot pass the address of an array to functions that take a char **?

UPDATE: Interestingly, changing the argument type to char* qux[12] doesn't change the compiler warning at all

For example:

#include <stdio.h>

void foo(char* qux) { puts(qux); }
void bar(char** qux) { puts(*qux); }
void baz(char* qux[12]) { puts(*qux); }

int main() {
    char str[12] = "Hello there";

    foo(str);
    bar(&str); // Compiler warning
    baz(&str); // Same compiler warning

    return 0;
}

In the second case, I get a compiler warning:

warning: incompatible pointer types passing 'char (*)[12]' to
         parameter of type 'char **' [-Wincompatible-pointer-types]

What's going on here?

sleighty
  • 895
  • 9
  • 29

2 Answers2

5

Arrays naturally decays to pointers to their first element. So in the call foo(str) it's really the same as foo(&str[0]). This is of type char * so it's all okay.

Now the second call, the one to bar, is a different matter. When you use &str you don't get a pointer to the arrays first element, you get a pointer to the array itself. And as the compiler noted, this is of type char (*)[12], which is very different from (and incompatible with) char **.

Lastly, when you declare baz you say that the argument is of type char *[12], that is you have an array or 12 pointers to char, not that you have a pointer to an array of 12 char. Furthermore, due to the array decay to pointer thing, char *[12] is actually the same as char **.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Oh I guess I didn't know about array decay, that's interesting. Is there a way to make that argument be a pointer to an array of 12 `char` instead of the other way around? – sleighty Apr 27 '18 at 05:03
  • try this way. `char *qux1 = NULL; qux1=qux; bar(&qux1);` – ntshetty Apr 27 '18 at 05:05
  • 2
    @BrunoEly I just told it to you, and it's also part of the error message: "... passing 'char (*)[12]' to...". Use e.g. `char (*qux)[12]` and you have a pointer to an array of 12 `char`. However, passing pointers to arrays like that is often not needed, passing a simple `char *` pointing to the first element is the common use-case. – Some programmer dude Apr 27 '18 at 05:05
  • @Someprogrammerdude got it! Yeah that's how I usually do it, I just couldn't figure out what that error message meant and it's been bugging me for a while. Thanks for the explanation – sleighty Apr 27 '18 at 05:08
  • "Furthermore, due to the array decay to pointer thing, char *[12] is actually the same as char **." An array is not the same as a pointer. An expression of array type is implicitly converted to a pointer to its first element in many contexts, but not all. – newacct May 01 '18 at 17:07
2

In C, char * represents a pointer to a contiguous sequence of characters. A contiguous sequence of characters with a null termination is what we call a string in C.

char ** is a pointer to a contiguous sequence of strings, and since each string is a contiguous sequence of characters terminated by a null ('\0') character, char ** represents a contiguous sequence to a contiguous sequence of null terminated characters.

Your declaration:

 char str[12] = "Hello there";

Declares str to be an array of characters of length 12, and it is initialized to the 12 characters {'H','e','l','l','o',' ','t','h','e','r','e','\0'}. This is compatible with the parameter in foo(), but not with bar and baz both of which expect a contiguous sequence of pointers to strings. That is why those two give you a compiler warning because the parameter is incompatible with the arguments passed in.

Stargateur
  • 24,473
  • 8
  • 65
  • 91
ScottK
  • 1,526
  • 1
  • 16
  • 23