【问题标题】:Why is the compiler giving a warning that a pointer may be uninitialized when it's going to be initialized and won't the pointer update?为什么编译器在将要初始化的指针可能未初始化并且指针不会更新时发出警告?
【发布时间】:2020-12-24 02:50:44
【问题描述】:
    char *s, *p = s;
    size_t len = 0;

    while (str[len++]);

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

这里怎么来的: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;
                      ^

由于p是一个指向s的指针,当s被分配内存时,p指向s时不会更新吗?

为什么我必须这样做:

    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 不会更新也是?

【问题讨论】:

  • *p = s 将 s 的当前值放入 p 中。 s 未定义。
  • p 没有指向s。那将需要 char **p = &s; 。赋值x = y;y 的值复制到x,它不会使x 引用y 的位置或任何东西
  • 但是指针指向的值不能改变吗?就像*s 是未定义的,但现在自从我分配了malloc,指针发生了变化,现在指向了malloc。
  • p 不指向 s。如果你这样做了a = b,如果你稍后更改 b,a 不会更改。
  • @JackMurrow 看看你是如何在那里写的 &a*b ,这与你问题中的代码不同。如果你尝试int a = 3; int b = a; a = 5; printf("%d\n", b);,你会得到3

标签: c pointers memory


【解决方案1】:

让我们稍微分解一下。

你所拥有的基本上是这样的:

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

您提议当s 被初始化(通过malloc 的返回值)时,p 的值也应该更新。

但是,正如您所发现的,情况并非如此。最初,当您执行char *s 时,s 可以指向任何东西。它尚未初始化。

随后,当您执行char *p = s; 时,您会将s当前 值分配给p——这可能是任何东西

如果您更改s 的值,则不会自动更改p 的值。它们是不同的变量。它们都是指针——但这并不意味着它们应该指向同一个东西,因为它们是从另一个初始化的。

这两个指针之间没有内在联系,即使您将一个分配给另一个。关键是,即使它们在某个时间点确实指向同一事物,您也可以在将来更改其中一个指向的内容,而不会影响另一个。

它实际上与分配给非指针变量并断言它应该自动更新没有什么不同,例如

int i;
int j;
i = j;
j = 5;
printf("%d\n", i); // Prints rubbish
printf("%d\n", j); // Prints 5

这里,j 被初始化,printf 符合预期。同时,i 是从j 的垃圾值初始化的——该值恰好位于内存中j 的位置(可能是任何东西)。然而,我怀疑有人会建议 i 在这种情况下“自动”更新。

更新:

以下更新是针对此后续评论的回应:

这就是我认为它会更新的原因.. char *s = malloc(100);字符 *p = s;看到这个,对吧?例如 p[0] = 'e' 也会改变 s[0],所以我认为如果通过索引分配 p 的元素也会 按索引更改 s 的元素,会有更改/更新,对吗? p[0] = 'e' 怎么会同时改变 s 和 p 的元素,即使 p 刚刚分配了 malloc 的当前值?它们是不同的指针 但是指向同一个内存块,这就是为什么!我说的对吗?

在本例中,ps 再次指向同一个内存。当您分配p[0] = 'e' 时,您 更改ps - 实际上您更改了p 指向的值。而且,由于ps 指向同一个内存,因此您所做的更改将通过ps 可见——当您取消引用时。下面是一个深入的示例 - 我建议编译并运行它以查看打印的内容,并阅读解释每一步发生了什么的 cmets。

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

【讨论】:

  • 这就是我认为它会更新的原因。char *s = malloc(100); char *p = s; 看到这个,对吧?例如p[0] = 'e' 也会改变s[0],所以我想既然如果通过索引分配p 的元素也会通过索引改变s 的元素,就会有更改/更新,对吧?为什么p[0] = 'e' 改变了sp 的元素,即使p 刚刚分配了malloc 的current 值?它们是不同的指针,但指向同一个内存块 (malloc),这就是原因!我对吗?所以p 并没有指向 s,而是指向mallocs?
  • 查看我的更新以响应此后续评论。
【解决方案2】:

哦不,p 没有指向 s。

您的陈述:

char *p = s;

它的意思是“将指针 s 的值复制到指针 p 中”,所以无论存储在 s 中的地址是什么(未初始化),它都会是存储在 p 中的值。

一旦 s 被分配了 malloc 的值,p 将保持初始值并且 s 将不同。

【讨论】:

    猜你喜欢
    • 2021-05-11
    • 2012-08-23
    • 1970-01-01
    • 2021-06-23
    • 2012-07-18
    • 2013-02-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多