当我第二次调用该函数时,为什么指针“a”指向正确的位置
因为在第二个函数调用“cr”期间if块中的语句不会被执行所以指针“a”如何记住它的先前位置,即使它不是静态变量
代码:
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
typedef struct heavy{
int data;
struct heavy *nxt;
}ode;
void cr(ode**);
void prin(ode*);
int main()
{
ode*head=NULL;
cr(&head);cr(&head);
prin(head);
getch();
return 0;
}
void cr(ode**p)
{
ode*temp,*a;
temp=*p;
if(temp==NULL)
{
a=(ode*)malloc(sizeof(ode));
a->data=1;
a->nxt=(ode*)malloc(sizeof(ode));
*p=a;
a=a->nxt;
a->nxt=NULL;
}else{
a->data=2;
a->nxt=NULL;
}
}
void prin(ode*head)
{
if(head==NULL)
printf("list is empty");
while(head!=NULL)
{
printf("%d",head->data);
head=head->nxt;
}
}
答案 0 :(得分:0)
如果您没有为局部变量分配任何值(在这种情况下我们正在谈论a
),程序将以不可预测的方式运行,因此我们说 undefined行为。这意味着您的程序只是偶然地正常运行,并且您应该始终在使用变量之前记住分配值。
特别是在这种情况下,我可以猜到每次运行它时它的工作原理,并且它与函数调用在C中的工作方式有关。让我解释一下。
当我们调用一个函数时,堆栈中的一个新框架(图层)(内存中的一个位置,其中局部变量和其他&#34;本地-ish&#34;存储的东西)。正如您所说的那样,堆栈按层次组织。让我公开一个例子。
如果在一个名为George()的特定函数中,我声明并使用了2个局部变量
int George(){
int a;
int b;
a = 5;
return 0;
}
编译器将知道需要2个变量的空间,因此当我调用该函数时,它将为这两个局部变量保留空间。新的堆栈框架将类似于:
| 'a': ____ | <-- 4 bytes space for variable a
| 'b': ____ | <-- 4 bytes space for variable b
|-----------|
(虽然记住这不是堆栈的真实表现,但它足以解释发生了什么)
为变量值保留的空格 NOT 设置为默认值,它们包含之前在内存中的内容(现在我们无法做出任何猜测)。
当我从另一个函数(即main
)调用此函数时,具有该形状的堆栈帧将被添加(push
)到堆栈中:
int main(){
int hello = 7;
int hey;
hey = George(); // Here we make the function call
return 0;
}
然后堆栈将是:
STACK:
| 'a': ____ | <- 'George' stack frame, containing
| 'b': ____ | local variables of George
|--------------|
| 'hello': 7 | <- 'main' stack frame, containing
| 'hey': ____ | local variables of main
|--------------|
在George的第3行之后,就在返回之前,堆栈将是:
STACK:
| 'a': 5 | <- Variable a has been set to 5
| 'b': ____ |
|--------------|
| 'hello': 7 |
| 'hey': ____ |
|--------------|
然后会有return
。这里,堆栈是pop
&#39; d,这意味着删除了一个帧(我们将在main
函数&#34;域&#34;中返回,因此我们丢弃了George的局部变量)。
STACK:
| 'hello': 7 | <- 'main' stack frame, with hey replaced with
| 'hey': 0 | George return value (0)
|--------------|
一切正常,但是我们现在弹出的内存并没有设置为0或其他默认值。它保持这样,直到其他程序覆盖它。这意味着,虽然我们不再使用这些价值观,但他们仍然可能 。
在这种状态下,如果我们再次打电话给乔治,我们将再次推动我们的筹码:
STACK:
| 'a': ____ | <- 'a' address is in the same position
| 'b': ____ | where there was the 'a' in the previous
|--------------| function call to Giorgio
| 'hello': 7 |
| 'hey': ____ |
|--------------|
在此状态下,如果我们没有为a
分配任何值,它(可能)将包含a
在之前的函数调用中所具有的值,因为&#39 ;新&#39; a
与“之前”的地址相同。 a
,因为调用的函数是相同的,并且之间没有其他函数调用可以覆盖以前的值。如果我们这样做,在我们为新的局部变量a
分配任何值之前,它包含5
。
运行
时,程序也会发生同样的情况cr(&head);
cr(&head);
两次,一次在另一次之前。您的局部变量a
的值可能保持不变。
无论如何,除了解释之外,永远不要在你的代码中使用这种行为。这是一种非常糟糕的编程方式,结果通常是不可预测的。
我希望我的解释不是太糟糕。