You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何数组前后元素指向超作用域局部结构体时出现混乱?

栈上结构体变量超出作用域后的行为疑问

我在测试声明结构体变量和用malloc分配结构体两种方式的访问特性,知道栈上声明的结构体变量只在作用域内有效,超出后会被销毁。我写了下面的程序:

#include<stdio.h>
#include <stdlib.h>

typedef struct Edge {
    int edgeNum;
    struct Edge* next;
}Edge;

typedef struct Vertex {
    int vertexNum;
    Edge* next;
}Vertex;

void addEdge(Vertex* v, int edgeNum) {
    Edge* currentEdge;
    Edge newEdge;
    
        newEdge.edgeNum = edgeNum;
        if (v->next == NULL) {
            v->next = &newEdge;
    
        } else {
            currentEdge = v->next;
            while (currentEdge->next != NULL) currentEdge = currentEdge->next;
            
            currentEdge->next = &newEdge;  //this part doesnt represent a real graph
        }
        newEdge.next = NULL;
}
    
    

int main()
{
    int IG[7][14] = { {1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1},
                      {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                      {0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1},
                      {0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
                      {0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1},
                      {0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1},
                      {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0} };
    
    int i, j;
    
    Vertex v[7];
    Edge *new_edge;
    Edge *current;
    
    for(i=0; i < 7; i++){
        
        /* Set order number to each list */
        v[i].vertexNum = i+1;
        /* Initialize the edge list with NULL */
        v[i].next = NULL;
        
        for(j=0; j < 14; j++){
            if( IG[i][j] == 1 ){
                addEdge(&v[i],j+1);
                if (i>0)
                printf(" line %d: %d and line%d: %d\n",i-1,v[i-1].next->edgeNum, i, v[i].next->edgeNum);
            }
            
        }
        
                    
    }
       

    return 0;
}

我遍历矩阵每一行,遇到值为1的元素就创建一个Edge结构体关联对应顶点。我知道这么做有问题,因为结构体超出作用域会被销毁,但实际结果和预期不符——我原本以为循环结束后v[]数组的每个元素都应该指向NULL,因为结构体已经被销毁。

但实际情况是,后续创建的结构体似乎覆盖了前面元素的指向。循环结束后遍历数组,所有元素都指向最后一个元素对应的结构体:比如矩阵第二行唯一的1在2x1位置,对应的edgeNum应该是1,但实际变成了13(矩阵最后一行最后一个1的位置),其他行也都是这个情况。

希望有人解释我的预测错误在哪里,感谢。


问题原因解析

你的核心误解是栈上变量销毁后,指向它的指针会自动变成NULL——这完全是错误的。栈上变量超出作用域后,系统只是标记这块内存区域可以被后续栈操作复用,并不会主动把之前的指针置为NULL,也不会清空内存里的数据。

具体到你的代码:

  • addEdge函数里的newEdge是栈上局部变量,每次调用addEdge时,它都会被分配在栈的同一位置(因为函数调用栈的结构是固定的,每次进入函数都会在栈顶分配同样大小的空间)。
  • 你把&newEdge赋值给v->next或者链表节点的next指针,本质上是让这些指针指向栈上的同一个固定地址。
  • 每次调用addEdge时,都会覆盖这个地址上的edgeNum值,最后一次调用时把它设为13,所以所有指针指向的内存区域里的edgeNum都是13。
  • 当函数返回后,这块内存并没有被清空,只是变成了“可用”状态,所以你的指针依然能访问到这块内存里的最后一次写入的值,而不是变成NULL。

简单说:指针本身不会因为指向的内存失效而自动变为NULL,失效的栈内存会被后续操作覆盖,导致你看到的所有指针都指向最后一次写入的数据。

正确的做法是用malloc动态分配Edge结构体,这样内存会在堆上,不会随函数返回而失效,直到你用free释放。

内容的提问来源于stack exchange,提问作者Nathan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 14:17:40