Don't get stuck on the fact that it's being passed an address. strlen()
always takes an address. It's argument is a const char *
, the address of a string. All of these calls pass the exact same address:
strlen(baz);
strlen(&bar[0]);
strlen(bar);
baz
is assigned &bar[0]
, so the first and second are equivalent. An array decays to a pointer to its first element (array == &array[0]
), so the second and third are equivalent.
I mean how can we find length of an address, which is just a number?
Let's say that bar == &bar[0] == baz == (char *) 0xb96eb740
as per your example. strlen()
will first check if memory location 0xb96eb740 contains \0
. If not, it will then check 0xb96eb741. Then 0xb96eb742. Then 0xb96eb743. It will continue checking each location sequentially until it finds \0
.
I know that's true. But why does strlen(baz)
return 0?
As the linked Q&A explains, the behavior is indeterminate because the contents of the bar[128]
array are uninitialized. There could be anything in that array. The only cell we know the value of is bar[127]
, which is set to \0
. All the others are uninitialized.
That means that any one of them, or all of them, or none of them, could contain a \0
character. It could change from run to run, from call to call even. Every time you call foo()
you could get a different result. That's entirely possible. The result will vary based on what data happens to be on the stack before foo()
is called.
When I run this code, this gives 0
every time and the correct answers are 0
and 127
(I still don't get why?).
It could return any value between 0 and 127. Due to the indeterminate behavior you mustn't read too much into what the program happens to return when you run it. The output could be different if you run the program again, if you cal a different set of functions before foo()
, if you run a different program beforehand, if you change compilers, if you run it a different day of the week, if you use a different operating system, etc., etc., etc.