LyZeN77
LyZeN77

Reputation: 9

Confusion about the way C handles strings

Why wouldn't

   char *name = "asd";
   printf("%p\n%p", (void *)&name, (void *)&name[0]);

give the same output as

char name[] = "asd";
printf("%p\n%p", (void *)&name, (void *)&name[0]);

I've read that C takes strings as a pointer to their first char, till it reaches the '\0' but the code above doesn't like it, so it is confusing for a C beginner.

Upvotes: 0

Views: 89

Answers (1)

Steve Summit
Steve Summit

Reputation: 47923

First, let's give your two variables different names and contents, so we can clearly tell them apart.

char *namep = "asd";
char namea[] = "zxc";

These result in data structures which might look like this:

       +-------+
namep: |   *   |
       +---|---+
           |
          /
         |
         V
       +---+---+---+----+
       | a | s | d | \0 |
       +---+---+---+----+

       +---+---+---+----+
namea: | z | x | c | \0 |
       +---+---+---+----+

Now let's look at your two printf calls:

printf("%p\n%p", (void *)&namep, (void *)&namep[0]);

Now, &namep gives you the address of the namep pointer.
But &namep[0] gives you the address of the first character in the pointed-to string (a). If you had printed

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

you would have seen the same thing.

printf("%p\n%p", (void *)&namea, (void *)&namea[0]);

Here, &namea gives you the address of the array.
And &namea[0] gives you the address of its first character (z) — which is the same place. And in fact, due to the special handling (the "decay" of arrays into pointers), if you had said

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

you would also have seen the same thing.

You asked:

I've read that C takes strings as a pointer to their first char, till it reaches the '\0'.

That's correct.

Suppose you wrote the code

char *p;
for(p = namep; *p != '\0'; p++)
    putchar(*p);

This would print your namep string, asd. There's no mystery here. namep was already a pointer, pointing at the first character of the string, so this scrap of code takes its own pointer p, which starts pointing where namep points, and prints the pointed-to characters until it gets to the terminating \0.

What's perhaps more surprising is that you can do exactly the same thing with namea:

char *p;
for(p = namea; *p != '\0'; p++)
    putchar(*p);

This works, too, printing zxc, and if you don't believe me, I encourage you to type it into your C compiler and try it.

Now, you may be asking, if p is a pointer and namea is an array, how can the loop initialization p = namea work? And this, again, is due to the "decay" of arrays to pointers. Again, when you try to use namea's value like this, what you get — the value that gets assigned to p — is automatically a pointer to namea's first element. And of course that's just what you want. p starts there, and prints characters 'til it finds a \0, thus printing zxc.

Upvotes: 5

Related Questions