2
    int main(){
        char *str1="Hi", *str2 = "Bye";
        printf("%u,%u\n",&str1,str1);
        int arr[5]={1,2,3,4,5};
        printf("%u,%u",arr,&arr);
    }

What is happening here? str and &str give different addresses and arr and &arr give same.

My understanding is that arr points to address of first element i.e &arr[0] and &arr will give also the same address but it is address of whole arr[5]. If we increment &arr by 1 then it will point to next element of arr[4]. But problem is that why this process is different in case of string. Please help me to visualize the concept here.

Sanjay Verma
  • 101
  • 13
  • 2
    Does this answer your question? [What are the barriers to understanding pointers and what can be done to overcome them?](https://stackoverflow.com/questions/5727/what-are-the-barriers-to-understanding-pointers-and-what-can-be-done-to-overcome) – znatno Apr 13 '20 at 10:30

5 Answers5

7

In C all string literals are really stored as arrays of (read-only) characters including a null-terminator. As any other array they decay to a pointer to their first element.

For str1 in your code the compiler have generated some code similar to this:

// Compiler-generated array for the string
char global_array_for_Hi[] = { 'H', 'i', '\0' };

int main(void)
{
    char *str1 = global_array_for_Hi;
    ...
}

Your pointer variable str1 is pointing to the first element (the 'H') of this array. When you print the value of str1 that's the value you get.

When you print the value of &str1 you get the location of the variable str1 itself, you get a pointer to str1 of the type char **.

Somewhat graphically it could be seen like

+-------+     +------+     +-----+-----+------+
| &str1 | --> | str1 | --> | 'H' | 'i' | '\0' |
+-------+     +------+     +-----+-----+------+

For arr you have an array, it decays to a pointer to its first element. When you use arr it's the same as &arr[0] (it comes from the fact that arr[i] is exactly equal to *(arr + i)). The type of arr (and &arr[0]) is int *.

When you use &arr you get a pointer to the whole array, and its type is int (*)[5].

The location is same for both &arr[0] and &arr, but their types are very different.


On a related note, the printf format specifier %u is for printing values of the type unsigned int. To print pointers (more specifically values of type void *) you must use the format specifier %p. Mismatching format specifier and argument type leads to undefined behavior.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • if i define str1[]="Hi" then it will behave like array that i mentioned in question? – Sanjay Verma Apr 13 '20 at 10:35
  • I'm new in C. Why you / the compiler declare the char array global? – Michael Schäfer Apr 13 '20 at 10:56
  • @MichaelSchäfer All literal strings are "global" and have a life-time of the full program. See e.g. [this string literal reference](https://en.cppreference.com/w/c/language/string_literal) for details. – Some programmer dude Apr 13 '20 at 11:04
  • @Someprogrammerdude From your link _String literals are not modifiable_. A string literal like `char *str1="Hi"` isn't modifiable. In your example str1 is modifiable. Did you forget a const when declaring the array, or does the compiler handle it in a different way? – Michael Schäfer Apr 13 '20 at 11:54
  • 1
    @MichaelSchäfer The thing is that the string arrays created by the compiler are not `const`. Attempting to modify one will lead to undefined behavior, and they are therefore effectively read-only (as I mentioned) but they aren't `const`. There's no way in standard C to mark an array as "non-modifiable" beyond `const`, but since they're not `const` I omitted that. – Some programmer dude Apr 13 '20 at 13:48
1

1.

char *str1="Hi";
printf("%u,%u\n",&str1,str1);

First you use the wrong conversion specifier, %u for both, str1 and &str1, which invokes undefined behavior. For str1 it shall be %s and for &str1 it shall be %p:

char *str1="Hi";
printf("%p,%s\n",(void*) &str1, str1);

Explanation:

str1 is a pointer to the address of the first element of the string literal "Hi". &str1 is the address of the pointer str1 itself. That is the difference to the version with the array below.


2.

int arr[5]={1,2,3,4,5};
printf("%u,%u",arr,&arr);

Again, the wrong conversion specifiers here. It shall be %d or %i if you want to print the first element of arr as arr is an array of int not unsigned int or %p if you want to print the address of the first element:

int arr[5]={1,2,3,4,5};
printf("%p,%p",(void*) arr, (void*) &arr);

Explanation:

arr (after array-to-pointer decay rule) decays to a pointer to the first element of arr while &arr is actually a pointer to the first element of arr. They actually evaluate to the same.


Note, the cast to void* is necessary to make the code C standard-compliant.

Community
  • 1
  • 1
1

array is not a pointer. It is continuous chunk of memory. That the reason why array && &array have the same address

pointer is a separate object holding the reference. So the pointer - gives you the reference held by the pointer an &pointer gives you the reference to the pointer itself. As the pointer is a separate object you have different addresses

0___________
  • 60,014
  • 4
  • 34
  • 74
1

In this declaration

char *str1="Hi", *str2 = "Bye";

there are declared two local variables str1 and str2 with the automatic storage duration.

They are initialized by addresses of first characters of string literals that have the static storage duration.

So the value of str1 is the address of the first character of the string literal "Hi". The value of the expression &str1 is the address of the local variable str1 itself.

You can imagine it the following way

&str1 ---> str1 ---> "Hi"

Arrays are contiguous extents of memory. So the address of an array itself and the address of its first element are the same. It is the address of the extent of memory occupied by the array.

You can imagine it the following way

        | 1 | 2 | 3 | 4 | 5 |
        ^
        |        
&arr----
        ^
        |
arr-----

Pay attention to that array designators used in expressions with rare exceptions are converted to pointers to their firs elements. So use din the call of printf the expression arr is equivalent to &arr[0].

Regarding to your comment

Vlad I've a doubt regard string constant, Why can't we modify this char *s="HI" but we can modify this char *s[]="HI" I know about second case it is simple array but can you please clear why can't i modify string constant

then according to the C Standard (6.4.5 String literals)

7 It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.

Pay attention to this declaration

char *s[]="HI";

is invalid. There is declared an array of pointers. So to initialize it you have to write

char * s[] = { "HI" };

And you may change the elements of the array by assigning to them other string literals. That is you may change pointers themselves not the string literals pointed to by the pointers.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Vlad I've a doubt regard string constant, Why can't we modify this char *s="HI" but we can modify this char *s[]="HI" I know about second case it is simple array but can you please clear why can't i modify string constant. – Sanjay Verma Apr 13 '20 at 10:59
  • @SanjayVerma See my appended answer. – Vlad from Moscow Apr 13 '20 at 12:44
1

In C, constant string like "Hi, Guys" is stored on shared memory. Consider following example:

str = "Hi, there";

The string in above code is stored contiguously. The variable str points to first character of string, So character 'H' here. So, str gives address of first character which stored on somewhere in memory. &str gives address of variable str itself.

The case in array is different than above. Array is variable(off course, const variable) that contains address of first element(that is &arr[0]) of array. And when you do &arr it will same as &arr[0]. &arr is actually address of whole array which is same as address of first element of array.

Note: print &arr + 5 and &arr[0] +5, you may got some light.

ravivasani75
  • 113
  • 6
  • Yes ravi i know about array how they behave but i was confused with str[] and *str i was thinking they both are working the same but they are different. BTW thanks for the answer. – Sanjay Verma Apr 13 '20 at 10:43