指针可以存在于其范围之外

时间:2017-09-13 17:01:45

标签: c pointers linked-list

  1. 当我第二次调用该函数时,为什么指针“a”指向正确的位置

  2. 因为在第二个函数调用“cr”期间if块中的语句不会被执行所以指针“a”如何记住它的先前位置,即使它不是静态变量

  3. 代码:

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

1 个答案:

答案 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的值可能保持不变。

无论如何,除了解释之外,永远不要在你的代码中使用这种行为。这是一种非常糟糕的编程方式,结果通常是不可预测的。

我希望我的解释不是太糟糕。