char *s, *p = s;
size_t len = 0;
while (str[len++]);
s = malloc(sizeof(*s) * (len + 1));
Run Code Online (Sandbox Code Playgroud)
How come here: char *s, *p = s;
gives warning, but s
is going to be initialized with malloc
later.
chl/string.c:9:15: warning: ‘s’ may be used uninitialized in this function [-Wmaybe-uninitialized]
9 | char *s, *p = s;
^
Run Code Online (Sandbox Code Playgroud)
Since p
is a pointer, pointing to s, won't p
be updated as well when it points to s
when s
will be memory allocated?
Why would I have to do this instead:
chl/string.c:9:15: warning: ‘s’ may be used uninitialized in this function [-Wmaybe-uninitialized]
9 | char *s, *p = s;
^
Run Code Online (Sandbox Code Playgroud)
I thought pointers can change to what it points to, so why isn't p
being updated as a pointer? Or if I'm seeing this wrong, why can't I just do *p = s
, because s
soon is going to be initialized, and p
will point to s
, so won't p
update too?
Let's break this down a little.
What you have essentially is this:
char *s;
char *p = s;
s = malloc(...);
Run Code Online (Sandbox Code Playgroud)
You're proposing that when s
gets initialized (by malloc
's return value), the value of p
should also update.
But, as you've discovered this is not the case. Initially, when you do char *s
, s
can point to anything. It is not yet initialized.
Subsequently, when you do char *p = s;
, you are assigning the current value of s
to p
-- which could be anything.
If you change the value of s
, that doesn't automatically change the value of p
. They are distinct variables. They are both pointers - but that doesn't mean they should point to the same thing just because one was initialized from the other.
There is no intrinsic link between these two pointers, even if you assign one to the other. The point is, even if they do point to the same thing at one point in time, you can change what one points to in the future without affecting the other.
Its actually no different from assigning to a non-pointer variable and asserting that it should be updated automatically, e.g.
int i;
int j;
i = j;
j = 5;
printf("%d\n", i); // Prints rubbish
printf("%d\n", j); // Prints 5
Run Code Online (Sandbox Code Playgroud)
Here, j
is initialized and the printf
is as expected. Meanwhile, i
was initialized from j
's rubbish value -- the value that happened to be lying in memory at j
's location (and that could be anything). Yet, I doubt anyone would suggest that i
should "automatically" update in this case.
UPDATE:
The following update is in response to this followup comment made:
Here's why I thought it would update.. char *s = malloc(100); char *p = s; see this, right? p[0] = 'e' for example will also change s[0], so I thought that since if assigning the element of p by index would also change the element of s by index, there would be change/update, right? How come p[0] = 'e' changes the element of both s and p, even though p just assigned the current value of malloc? They are different pointers but point to the same memory block, that's why! Am I right?
In this example, p
and s
again point to the same memory. When you do the assignment p[0] = 'e'
, you are NOT changing p
or s
-- you are in fact changing the value pointed to by p
. And, since p
and s
point to the same memory, the change you've made will be visible through both p
and s
-- when you dereference either. Below is an in-depth example - I recommend compiling it and running it to see what gets printed, and read the comments which explain what is happening at each step.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
// this initializes s to point to some block of memory, e.g. address 0x560890f49260 when I run it locally
// it can store 100 bytes (chars) of data
char *s = malloc(100);
// this initializes p to point to the same block of memory as s => 0x560890f49260
char *p = s;
// this prints out the value of p and s
// they are of type 'pointer', so use %p
// this shows their address as being the same
printf("This is where p points to: %p\n", p);
printf("This is where s points to: %p\n", s);
// this sets the 1st byte at the location pointed to by p
// the thing we're changing is at address 0x560890f49260
// this "array" notation is just syntactic sugar for dereferencing a pointer - see below
p[0] = 'e';
// but p and s are unchanged
printf("This is where p points to: %p\n", p);
printf("This is where s points to: %p\n", s);
// this also changes the 1st byte (same as *p = 'e' and p[0] = 'e')
// here we're using the dereferencing syntax explictly
*(p + 0) = 'e';
// and p and s are still the same
printf("This is where p points to: %p\n", p);
printf("This is where s points to: %p\n", s);
// this changes the 2nd byte (same as p[1] = 'f')
// the thing we're changing is at address 0x560890f49261 - i.e. the next byte
*(p + 1) = 'f';
// and p and s still haven't changed
printf("This is where p points to: %p\n", p);
printf("This is where s points to: %p\n", s);
// this prints the 1st and 2nd byte pointed to by p and s
// they show the same thing in both cases - since p and s point to the same thing
printf("First byte pointed to by p: %c\n", p[0]);
printf("First byte pointed to by s: %c\n", s[0]);
printf("Second byte pointed to by p: %c\n", p[1]);
printf("Second byte pointed to by s: %c\n", s[1]);
// now p is pointing to something new, e.g. address 0x5617ba3ef6e0 when I run it locally
p = malloc(100);
// we see that p **HAS** changed, but s has **NOT** changed
// they are now pointing to different things
printf("This is where p points to: %p (new location!)\n", p);
printf("This is where s points to: %p (old location!)\n", s);
// this sets the 1st byte pointed to by p to be 'g'
p[0] = 'g';
// we can see that the 1st byte pointed to by p is 'g'
printf("First byte pointed to by p: %c\n", p[0]);
// while the first byte pointed to be s is unaffected
// since p and s point to different things
printf("First byte pointed to by s: %c\n", s[0]);
// always free your memory
free(p);
free(s);
return 0;
}
Run Code Online (Sandbox Code Playgroud)