首页 > 解决方案 > 为什么编译器在将要初始化的指针可能未初始化并且指针不会更新时发出警告?

问题描述

    char *s, *p = s;
    size_t len = 0;

    while (str[len++]);

    s = malloc(sizeof(*s) * (len + 1));

How come here:char *s, *p = s;给出警告,但稍后s将被初始化malloc

chl/string.c:9:15: warning: ‘s’ may be used uninitialized in this function [-Wmaybe-uninitialized]
    9 |     char *s, *p = s;
                      ^

因为是一个指向 s 的指针,当它指向什么时候分配内存时,它p不会被更新吗?pss

为什么我必须这样做:

    char *s, *p;
    size_t len = 0;

    while (str[len++]);

    s = malloc(sizeof(*s) * (len + 1));
    p = s;

我认为指针可以更改为它指向的内容,那么为什么不p将其更新为指针呢?或者如果我看到这个错误,为什么我不能这样做*p = s,因为s很快就会被初始化,并且p会指向s,所以也不会p更新?

标签: cpointersmemory

解决方案


Let's break this down a little.

What you have essentially is this:

char *s;
char *p = s;
s = malloc(...);

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

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;
}

推荐阅读