C++,访问在其他方法中声明的非全局变量

C++, Accessing a non-global variable declared inside other method

本文关键字:声明 全局变量 方法 访问 其他 C++      更新时间:2023-10-16

此代码获取函数返回的值,创建并将其放入名为变量"b"的新地址空间

    int main()
{
    int b;
    b = topkek();
    std::cout << &b;

};
int topkek()
 {
    int kek = 2;
    return kek;
 };

现在我明白了,因为变量kek在topkek方法中,所以我不能从main()方法访问它。使用C++和指针,我发现了如何在方法终止后访问方法内部声明的变量,看看下面的代码。

int main()
{
    int * a;
    a = topkek();  //a is now pointing at kek
    std::cout << *a; //outputs 2, the value of kek.
    *a = 3;
    std::cout << *a; //output 3, changed the value of kek.
    std::cin >> *a;

};
int * topkek()
 {
int kek = 2;
    int* b = &kek;  //intializing pointer b to point to kek's address in stack
    return b; //returning pointer to kek
};

这种方法安全吗?编译器会防止kek的地址空间在以后的代码中被覆盖吗?因为它仍然知道它在被使用吗?

这是未定义的行为:一旦函数完成,通过指针或引用访问其中的变量会使程序无效,并可能导致崩溃。

然而,当您"返回"堆栈时访问变量是完全有效的:

void assign(int* ptr) {
    *ptr = 1234;
}
int main() {
    int kek = 5;
    cout << kek << endl;
    assign(&kek);
    cout << kek << endl;
}

请注意assign是如何访问在另一个函数中声明的局部变量的值的。这是合法的,因为访问发生时main尚未完成。

不,它不安全。函数执行完毕后,不再指向int,而只是指向内存中的某个随机位置。它的值可以是任何值,因为它可以在程序的其他地方进行修改。

绝对不安全。将导致未定义的行为。

当"创建"一个局部变量时,编译器会在堆栈上给变量一些空间[1]。只要您在该函数内,该空间就可用于变量。当函数返回时,空间被释放,可供其他函数使用。因此,第二个代码中b的地址将返回一个指向内存的指针,该指针将在返回完成后释放。

试着添加这样的东西:

int foo()
{
     int x = 42;
     cout << "x = " << x << endl;
     return x;
}

并在调用topkek之后调用foo,可以肯定的是,kek中的值(或由kek指向的值)将发生变化。

[1] 对于学究们来说:是的,C++标准没有规定需要一个堆栈,也没有规定如何使用局部变量,等等。但总的来说,在当今几乎所有可用的编译器中,这就是它的工作方式。

这将是安全的:

int * topkek()
{
    static int kek = 2;
    int* b = &kek;  //intializing pointer b to point to kek's address in stack
    return b; //returning pointer to kek
};

当退出函数范围时,本地分配的自动类型将自动解除分配。然后返回的指针将指向已释放的内存。访问此内存将导致undefined behaviour

int* topkek() {
    int kek = 2; // Create a local int kek
    int* b = &kek;  // Declare pointer to kek
    return b; // Return pointer to local variable. <-- Never do this!
}; // kek is destroyed and the returned pointer points to deallocated memory.

这是未定义的行为。从函数返回后,kek不再存在,指针返回涅盘,指向kek曾经所在的位置。访问它会产生未定义的行为。未定义的行为意味着,任何都可能发生。你确实可以得到kek中曾经的值,或者你的应用程序崩溃,或者你得到一些垃圾值,或者编译器认为可以在网上给你点一个披萨,再加上额外的奶酪。

这是undefined behaviorkek是一个局部变量,一旦退出topkek,它所在的内存将被释放。它可能看起来是有效的,但由于它是未定义的,任何事情都可能导致,它可以在任何时候中断,你不能依赖结果。

首先,正如其他人所指出的,这肯定是不安全的。但根据您的使用情况,我认为您实际上可能正在尝试定义一个对象。例如,这段代码可能就是您想要的:

struct topkek{
    int kek;
    int *operator()() {
        kek = 2;
        return &kek;
    }
};
int main()
{
    topkek mykek;
    int *a = mykek(); // sets mykek.kek to 2, returns pointer to kek
    std::cout << *a;
    *a = 3;
    std::cout << *a;
    std::cin >> *a;
};

这将使您能够以完全安全的方式干净地访问底层kek变量。当然,您可以将任何想要的代码放入operator()方法中。