为什么返回后仍然可以访问函数中自动分配的数组?

问题描述 投票:0回答:3

我尝试运行这个简单的代码,并预计它会崩溃:

#include <stdio.h>

void setPtrOnTempData(char **ptr) {
    char str[] = "AAAA";
    *ptr = str;
}

int main() {
    char temp[] = "Paras";
    temp[3] = 'F';

    char *ptr = temp;
    ptr++;
    ptr[3] = 'F';
    printf("%s", ptr);  // prints "arFF"

    setPtrOnTempData(&ptr);

    ptr[0] = 'F';
    printf("%s", ptr);  // prints "FAAA"

    return 0;
}

如果我没记错的话,我这么想的原因是:

  1. 自动分配数组的元素都分配在堆栈中,所以函数返回后我失去了对它的控制。
  2. 数组变量是该数组在堆栈中的基元素的地址,因此作为参数传递的指针的赋值将指向堆栈中丢失的位置。

但结果是我仍然可以访问一些内存,其中分配了数组,并且我仍然能够更改该数组的数据。

为什么会这样,我的观点错在哪里?谢谢!!

UPD:我很抱歉我的不准确,一开始标题中是“静态”而不是“自动”。

arrays c pointers memory stack
3个回答
2
投票

首先,需要澄清的是,

str
中的数组
setPtrOnTempData
不是静态分配的。静态分配的变量,或者更准确地说具有“静态存储持续时间”的变量(即使用 static 关键字或在文件范围内)具有完整的程序生命周期。您拥有的是一个具有
自动存储持续时间
的变量,其生命周期在 setPtrOnTempData 返回时结束。
当您访问生命周期已结束的变量的内存时(正如您在此处所做的那样),它会导致代码中出现

未定义的行为

如果行为未定义,则无法保证您的代码会做什么。它可能会崩溃,可能会表现出奇怪的行为,或者(如您的情况)它可能看起来工作正常。此外,未定义行为的表现方式可能会随着代码看似无关的更改而改变,例如添加未使用的变量或调用

printf

进行调试。

仅仅因为您的代码

可能

崩溃并不意味着它将会


1
投票

您正在 setPtrOnTempData 函数中创建一个本地数组 str[]。但这个数组的作用域仅在函数内。因此,当您分配 *ptr = str 时,您将本地数组 str 的地址分配给 ptr,该地址指向 main 中的 ptr。但是当它返回时被释放时 它可能看起来有效,但它访问无效内存,导致这种奇怪的情况。


0
投票

void setPtrOnTempData(char **ptr) { /*ADDED>>>*/ static /*<<<ADDED*/ char str[] = "AAAA"; *ptr = str; // ✓ } //... setPtrOnTempData(&ptr); ptr[0] = 'F'; //✓ //...

一个 
static

对象具有

static
生命周期,即使无法通过名称访问它(
 超出范围),您也可以通过指针访问它。
<=>但是您在代码中缺少

static

关键字,如果没有它,您将访问生命周期已结束的变量,这是未定义的行为。

    

© www.soinside.com 2019 - 2024. All rights reserved.