1

I have this code:

char first_word[MAX_LENGTH + 1] = "test";
printf("Word to input: %s\n", first_word);
printf("Word to input: %p\n", first_word);

It prints successfully for both (prints the string "test" and then an address).

In my code, I eventually do this:

char *arr_of_strings[MAX_LENGTH + 1];
arr_of_strings[0] = first_word;

and it properly sets arr_of_strings[0] to whatever first_word is (which in this case is a pointer because *arr_of_strings is an array of pointers, right?). But now when I do

printf("arr at 0 is: %s\n", arr_of_strings[0]);

It prints a string again, can I can also print an address like so:

printf("arr at 0 is: %p\n", arr_of_strings[0]);

So when does c use first_word as a string and when does it use it as a pointer?

SilentDev
  • 20,997
  • 28
  • 111
  • 214
  • 1
    It's strange that your code already answers your question. Every `first_word` is a pointer to the first character of the string. You're confusing the `first_word` in the `printf` line but `%s` already tells the compiler that associated variable holds the pointer to the first character of the string, not the string itself. So, it is the same for `arr_of_strings[0]`: when used with `%p`, it prints its pointer value; when used with `%s`, it prints the pointed string. – ssd Aug 15 '17 at 02:23
  • 4
    `first_word` is an array of `char`. that type is `char[MAX_LENGTH+1]`. When evaluated as an expression, pointer to first element(`&first_word[0]`). C-String is a sequence of characters ending with a NUL character. Therefore, whether the pointer points is C-String depends on whether it is a sequence of characters to be terminated with NUL. – BLUEPIXY Aug 15 '17 at 02:23

2 Answers2

3

The correct answer is an identifier for an array of characters.

  • It's not a string, because a string isn't even a type in C. A string in C is defined as a sequence of characters including one 0 / '\0' character at the end (indicating the end). So, first_word can hold a string, but you can't say it is a string. It can hold any sequence of char, not just strings.

  • It's not a pointer, although it evaluates to a pointer in most contexts. Except when used with sizeof, _Alignof or &, the identifier of an array is evaluated as a pointer to it's first element. So, first_word will have the type char * (a pointer type) in many contexts, you could e.g. assign it to a pointer like char *foo = first_word. Still, evaluating to a pointer doesn't mean it is a pointer. The operators sizeof, _Alignof and & evaluate to very different results when used on an array vs. used on a pointer.


Regarding your question about printf: %s in printf requires a pointer to char (char *) to be passed and expects that pointer to point to a string. I hope you understand what that means after reading the explanation above.

1

Speaking in terms of exact variable lengths and addresses:

Case 1:

char str1[] = "test";

allocates a 5 bytes memory space, say from 0x0050 to 0x0054, and str1 is the address of the first character of the string; that is, 0x0050 in this case.

When it is used in printf with a %s format specifier, the compiler knowing the str1 is an array of characters, directly sends the address of str1 to the printf function and it prints the string.

When it is used in printf with a %p format specifier, the compiler assumes that the coder is interested in the address of the string; again sends the address of str1 to the printf function and this time, it prints the address of the string.

Case 2:

char *str2 = "test";

allocates a 5 bytes memory space, say from 0x0050 to 0x0054. This time however, str2 is a pointer stored in another address, say 0x0030; and it's value is 0x0050, pointing the first character of the string.

When it is used in printf with a %s format specifier, the compiler knowing the str2 is a pointer to an array of characters, sends the value stored in str2 to the printf function; not the address of str2.

When it is used in printf with a %p format specifier, the compiler assumes that the coder is interested in the address of the string; again sends the value stored in str2 to the printf function.

Case 3:

char *arrStr[4];
arrStr[0] = str1;

Here, the behavior of the compiler resembles the Case 2 above.

When it is used in printf with a %s format specifier, the compiler knowing the arrStr[0] is a pointer to an array of characters, sends the value stored in arrStr[0] to the printf function (and in fact, this is the address of str1); not the address of arrStr[0].

When it is used in printf with a %p format specifier, the compiler assumes that the coder is interested in the address of the string; again sends the value stored in arrStr[0] to the printf function.

So, if you're interested in the address of the arrStr[0] (not the value that it is pointing to), you should use &arrStr[0] with a %p format specifier.

ssd
  • 2,340
  • 5
  • 19
  • 37
  • `&arrStr[0]` is exactly the same as just `arrStr` without any operator, see my answer. (take these steps to see: `&arrStr[0]` -> `&(*(arrStr+0))` -> `&*arrStr`) –  Aug 16 '17 at 09:37