I'm confused in understanding how pointers to char
work.
What is the difference between using char *s = "car";
and s = "India";
?
And what about char **s
?
How will these be stored?
I'm confused in understanding how pointers to char
work.
What is the difference between using char *s = "car";
and s = "India";
?
And what about char **s
?
How will these be stored?
1st case
char* s = "car";
In this case you declaring a char
pointer and at the same time assigning it a string literal, in other words, making it point to the beginning of the string literal.
2nd case
char* s;
//some code;
s = "india";
This is the same as first, the difference is that you are first declaring the pointer, and later assigning it the string literal.
3rd case
char** s;
Is a pointer to a pointer to char
or double pointer to char
, take this sample:
#include <stdio.h>
int main()
{
char* ptr1 = "abc";
char** ptr2;
ptr2 = &ptr1;
printf("%s", *ptr2);
}
Thhis means that ptr2
is pointing to ptr1
pointer to char
(so it's a pointer to pointer to char
), through indirection ptr2
can be used to access the beggining of the string pointed by ptr1
.
Output
abc
Where the string literal is stored varies deppending on the platform, this answer has some details, as does the link I provided for string literal documentation.
String literals are not modifiable (and in fact may be placed in read-only memory such as .rodata). If a program attempts to modify the static array formed by a string literal, the behavior is undefined.
String literals like "car"
and "India"
are stored in arrays of character type such that they are available over the lifetime of the program. Under most circumstances, when an expression of array type appears in the code, it is implicitly converted ("decays") to an expression of pointer type, and the value of the expression is the address of the first element of the array.
So suppose our "car"
string is stored as an array of char
starting at address 0x8000
:
+---+
0x8000: |'c'|
+---+
0x8001: |'a'|
+---+
0x8002: |'r'|
+---+
0x8003: | 0 |
+---+
When you write
char *s = "car";
the expression "car"
is converted from type "4-element array of char
" to "pointer to char
", and the value of the expression is the address of the first element - 0x8000
. So, that 0x8000
address is written to s
1:
+--------+
s: | 0x8000 |
+--------+
Later on, when you write
s = "India";
the address of the first element of the array that stores "India"
is written to s
.
Here's a practical example. I've written a small utility that prints out the addresses and contents of multiple variables. Here's the code:
#include <stdio.h>
#include "dumper.h"
int main( void )
{
char *s = "car";
char *names[] = { "s", "\"car\"", "\"India\"" };
void *addrs[] = { &s, "car", "India" };
size_t sizes[] = { sizeof s, sizeof "car", sizeof "India" };
dumper( names, addrs, sizes, 3, stdout );
s = "India";
dumper( names, addrs, sizes, 3, stdout );
return 0;
}
Here's how it looks on my system - first we look at the strings themselves:
"car" 0x104f2ff71 63 61 72 00 car.
"India" 0x104f2ff88 49 6e 64 69 Indi
0x104f2ff8c 61 00 00 00 a...
The string "car"
is stored starting at address 0x104f2ff71
, and the string "India"
is stored starting at address 0x104f2ff88
.
Now we look at s
:
s 0x7ffeeacd0a10 71 ff f2 04 q...
0x7ffeeacd0a14 01 00 00 00 ....
s
is stored starting at address 0x7ffeeacd0a10
, and it's contents are the address of the string literal "car"
. Since x86 is little-endian, multi-byte values have to be read right-to-left.
After we write
s = "India";
our memory looks like this:
s 0x7ffeeacd0a10 88 ff f2 04 ....
0x7ffeeacd0a14 01 00 00 00 ....
Now s
is storing the address of the array containing "India"
.
what is char **s? How it will be stored?
You can have pointers to pointers:
char **s2 = &s;
s2
just stores the address of the variable s
. Pointers to pointers come up when you're dealing with arrays of pointers, or when you're passing a pointer to a function and you want the function to be able to write a new pointer value.
Different pointer types may have different representations - the only guarantees are:
char *
and void *
have the same representation and alignment;int *
and const int *
are stored the same way);So it's possible for a char **
object to be stored differently from a char *
object. On most modern systems like x86, all pointer types are stored the same way, but there are oddballs out there where that's not the case.
*
operator is simply part of the type; it is not dereferencing anything. We're storing the value to s
, not to what s
points to.
char *s = "car";
and s = "India";
are the same thing except for the fact that char *s = "car";
defines (creates) a new s
variable which didn't exist before, while s = "India";
reuses the existing s
. In both cases s
is a variable pointer to the first character of the string which is created in a non writable part of the data space. i.e. You can change s
to another string (e.g. set it to "India"
or increment it), but you cannot change the pointed memory (e.g. you can't do s[0]='e'
).
char **p;
just defines a pointer to a pointer (to a string), so you could write p=&s;
and if you then wrote *p="Terminator";
s
would now point to a new "terminator"
string.
There is another case that you should compare with the first two, which is char s[20] = "Hello";
In this case, s
is not a variable but a constant pointer to a variable 20 bytes space, in which you have stored "Hello\0"
. In this case, you CANNOT point s
to another string as in s="turlututu";
, but you can change the content of the 20 bytes space, providing you do not overflow outside this space and keep the content properly terminated with a '\0'
(not terminating your string is not a syntax error, but it is a dangerous practice).