指向函数局部结构的指针的作用域和生命周期
scope and lifetime of a pointer to struct which is local to a function
在下面的代码中,我将插入最后一个节点。它工作正常。
但我怀疑是因为我最后声明了 Node *;在本地,因此无论何时进行新的调用,都会创建一个新的指针变量,并且在函数终止后,先前的指针变量将从内存中删除。那么为什么 Node * last;是否保留了之前调用的地址,因为每次都会重新创建?
先;是指向链表第一个节点的指针,它是全局声明的。
void insertLast(int x)
{
Node *last;
Node *q=new Node;
q->data=x;
q->next=NULL;
if(first==NULL)
first=last=q;
else
{
last->next=q;
last=q;
}
}
insertLast(2);
insertLast(5);
insertLast(7);
display(first);
output:
2 5 7
更简单的例子,效果相同:
#include <iostream>
void DONT_DO_THIS(bool init){
int x;
if (init) x = 42;
else std::cout << x << "\n";
}
void foo() {
int y = 0;
}
int main() {
DONT_DO_THIS(true);
DONT_DO_THIS(false);
DONT_DO_THIS(false);
foo();
DONT_DO_THIS(false);
}
在你进一步阅读之前,试着找出这段代码的输出是什么。
你决定了吗?
你知道输出是什么吗?
无论您期望此代码打印什么,它都是错误的。该代码具有未定义的行为,可以产生任何输出。使用 gcc 11.1,这是我得到的输出:
42
42
0
在未初始化的情况下从局部变量 x
读取是未定义的行为。你不能那样做!如果无论如何都这样做,一种可能性是下次调用该函数时 42
仍存储在寄存器中,而 x
恰好具有该值。事实上 x
在这种情况下没有任何价值。据说它有一个你无法读取的不确定值。
打开优化时 (-O3
) 这是输出:
0
0
0
编译器很可能意识到代码有 UB 并优化掉了所有无意义的代码。
无论您得到什么输出,任何输出都将符合 C++ 标准,因为该标准没有规定编译具有未定义行为的代码的结果应该是什么。
TL;DR: 始终初始化变量。永远不要读取未初始化的变量。具有未定义行为的代码似乎可以工作,但必须对其进行修复。
在下面的代码中,我将插入最后一个节点。它工作正常。 但我怀疑是因为我最后声明了 Node *;在本地,因此无论何时进行新的调用,都会创建一个新的指针变量,并且在函数终止后,先前的指针变量将从内存中删除。那么为什么 Node * last;是否保留了之前调用的地址,因为每次都会重新创建?
先;是指向链表第一个节点的指针,它是全局声明的。
void insertLast(int x)
{
Node *last;
Node *q=new Node;
q->data=x;
q->next=NULL;
if(first==NULL)
first=last=q;
else
{
last->next=q;
last=q;
}
}
insertLast(2);
insertLast(5);
insertLast(7);
display(first);
output:
2 5 7
更简单的例子,效果相同:
#include <iostream>
void DONT_DO_THIS(bool init){
int x;
if (init) x = 42;
else std::cout << x << "\n";
}
void foo() {
int y = 0;
}
int main() {
DONT_DO_THIS(true);
DONT_DO_THIS(false);
DONT_DO_THIS(false);
foo();
DONT_DO_THIS(false);
}
在你进一步阅读之前,试着找出这段代码的输出是什么。
你决定了吗?
你知道输出是什么吗?
无论您期望此代码打印什么,它都是错误的。该代码具有未定义的行为,可以产生任何输出。使用 gcc 11.1,这是我得到的输出:
42
42
0
在未初始化的情况下从局部变量 x
读取是未定义的行为。你不能那样做!如果无论如何都这样做,一种可能性是下次调用该函数时 42
仍存储在寄存器中,而 x
恰好具有该值。事实上 x
在这种情况下没有任何价值。据说它有一个你无法读取的不确定值。
打开优化时 (-O3
) 这是输出:
0
0
0
编译器很可能意识到代码有 UB 并优化掉了所有无意义的代码。
无论您得到什么输出,任何输出都将符合 C++ 标准,因为该标准没有规定编译具有未定义行为的代码的结果应该是什么。
TL;DR: 始终初始化变量。永远不要读取未初始化的变量。具有未定义行为的代码似乎可以工作,但必须对其进行修复。