简体   繁体   中英

Confusion about Printing string arrays in C

This is probably a beginner question but it has been confusing me. I understand that in c an array is itself a pointer to the first element of the array. So consider the following example

char *words[LENGTH];
words[0] = "zero";
words[1] = "one";
words[2] = "two";
printf("%s\n",*words);

What ends up printing is zero . However, my understanding is that words is a pointer to the first element of the words array which is a char pointer => words is a pointer to a pointer to a char. Therefore *words would be a pointer to char. Therefore I would expect a memory address to be printed here and not an actual string. What am I misunderstanding here?

I understand that in c an array is itself a pointer to the first element of the array.

This is not correct - under most circumstances, an expression of type "N-element array of T " will be converted to an expression of type "pointer to T ", but an array object itself is not a pointer. No storage is set aside for a pointer as part of an array object.

The string literal "zero" has type "5-element array of char ", while both "one" and "two" have types "4-element array of char " (because strings are terminated with a zero-valued character, you need N+1 elements to store an N-character string).

Each string literal is an array expression, but since these expressions are not operands of the sizeof or unary & operators, and since they arent being used to initialize a character array, each expression is converted to a pointer expression, and the value of each expression is the address of the first element of the array.

Therefore I would expect a memory address to be printed here and not an actual string. What am I misunderstanding here?

The %s conversion specifer tells printf to print the sequence of characters beginning at the specified address until it sees a string terminator - that's why you see zero as the output and not an address. To print a pointer value, you'd use the %p conversion specifier like so:

printf( "%p\n", (void *) *words );

Your understanding of what you have done up to the printf is spot on - as you've written it, *words is in fact a pointer to a char. The %s format specifier is for printing strings, so it assumes that whatever pointer you pass it is actually an array of chars that ends with a '\\0' char - the format c uses for storing strings. With that information, printf knows that it should just print all of the characters in the array until it finds that '\\0' - which is exactly what it has done in this case. If you do want to print the address of that pointer, the correct format specifier is (as mentioned in Stargateur's answer) %p .

As @Stargateur replied you need to both use the %p flag and use the (void *). Please note that it will show you the starting address of the first string ('zero') and the next code will go over all the strings and print their address (think of the 3 strings as a 2D (two dimensions) strings array having different lengths.

#include <stdio.h>
#define LENGTH 3

int main(void)
{
    char *words[LENGTH];
    words[0] = "zero";
    words[1] = "one";
    words[2] = "two";

    int len = 0;
    while(len<(int)LENGTH)
    {
        printf("%s\n", words[len]);
        printf("%p\n", (void *)words[len]);
        len++;
    }
    printf("\n%p\n", (void *)*words); // prints the first address only (the 'zero' address)

    return 0;
}

You are close in fact you are right, c-string are a pointer that contain the address of the first char of the string. The c-string is not the bytes but the address. And printf flag %s expect the address of these bytes. So you indeed give an address to printf() but you ask to printf() to show the value of the c-string. So "zero". Your only error is that you didn't read the manual of printf() .

If you want the address try:

printf("%p\n", (void *)*words);

char *words[LENGTH]; defines an array of char*, ie char**. *words equals to words[0] which refers to "zero".

It is not safe to create such char* array. For example, the following code compiles OK, but its behavior is undefined.

char *words[1];
words[0] = "zero";
words[1] = "one";
words[2] = "two";
printf("%s\n", words[2]);

The context in which * (not * as in multiplication) matters, when used in declearation as in char *words[LENGTH] word becomes array of pointers to char.

as far as pointers are concern * is Value at address operator , it gives Value stored at particular address, while & is the address operator , gives address of variable.

printf("%s\n",*words) // prints value at address to which word points 

while

printf("%p\n",words) // prints address to which word points

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM