C++ 此函数如何更改堆栈上声明的变量的值?

C++ 此函数如何更改堆栈上声明的变量的值?,c++,memory,segmentation-fault,memory-address,vulkan,C++,Memory,Segmentation Fault,Memory Address,Vulkan,我目前正在学习使用Vulkan API编程。这就是API中的典型调用的方式。如果你对它不熟悉,不要太在意它的意思 pickPhysicalDevices(){ uint32_t deviceCount = 0; vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); } 基本上,vkEnumeratePhysicalDevices函数返回系统可用的物理设备的计数,并将该值放入deviceCount。我的问

我目前正在学习使用Vulkan API编程。这就是API中的典型调用的方式。如果你对它不熟悉,不要太在意它的意思

pickPhysicalDevices(){
    uint32_t deviceCount = 0;
    vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
}

基本上,vkEnumeratePhysicalDevices函数返回系统可用的物理设备的计数,并将该值放入deviceCount。我的问题是,既然我在pickPhysicalDevices()函数堆栈上声明了deviceCount,为什么vkEnumeratePhysicalDevices没有导致分段错误?

简短的回答是因为
pickPhysicalDevices
通过提供指针显式地允许
vkEnumeratePhysicalDevices
修改
deviceCount
变量

C++提供了多种让函数在另一个函数的上下文中修改值的方法——通过传递指针或引用

传递的内容(指针或引用)取决于所调用函数的声明。如果函数采用
uint32&
(带与符号),则传递一个不带与符号的变量,函数将接收一个引用。如果函数采用
uint32*
(带星号),则使用运算符
&
的地址传递指向变量的指针

一旦进入接受指针的函数,就可以编写
*pointer=…
,为指针所指向的变量指定一个新值。另一方面,引用不需要星号

在一个简单的程序中尝试以下两种方法:

void by_ref(uint32_t& ref) {
    ref = 123; // No asterisk
}
void by_ptr(uint32_t* ptr) {
    *ptr = 456; // Note the asterisk
}
int main() {
    uint32_t a, b;
    by_ref(a);
    by_ptr(&b);
    cout << a << " " << b << endl;
}
void by_ref(uint32_t&ref){
ref=123;//无星号
}
按ptr作废(uint32*ptr){
*ptr=456;//注意星号
}
int main(){
uint32_t a,b;
参考文献(a);
通过ptr&b;

cout参数deviceCount的地址被推送到vkEnumeratePhysicalDevices的堆栈帧中


因此,当您在vkEnumeratePhysicalDevices中更改deviceCount的值时,它实际上是在更改vkEnumeratePhysicalDevices自己的堆栈帧。

您不能返回局部变量的地址,因为函数返回其局部变量后超出了范围。不过,将其作为参数传递是可以的,因为父函数s变量在子函数的持续时间内都在范围内。

C也是如此吗?我大部分都接受过C语言的低级教育,如果我没记错的话,这通常是不允许的,但可能我错了。@KhalidAkash C没有引用,但我所说的指针在C语言中也是完全正确的。事实上,C++指针的行为与C指针的行为完全相同。对,我理解引用部分。我想混淆的是,我不确定另一个函数如何能够更改非动态分配的内存部分。但根据另一个答案,子函数确实可以访问其父函数堆栈,或者类似的东西?我是从根本上讲,访问自己堆栈之外的任何内容(如果不在堆栈中)都是一个大禁忌。父级的@KhalidAkash堆栈被认为是子级的“内部”,因为子级的堆栈框架高于其所有父级的框架(因此称为“堆栈”)。一旦子级退出,其帧将被解除分配,并且该帧的任何内存都是禁止使用的。程序可以更改属于它的内存的任何部分(例外情况下-内存中可以有“仅执行”部分(可以执行,但不能读/写)、“仅读”但是在任何情况下,堆栈总是在变化,并且是本地作用域变量所在的位置。调用者和被调用者都在同一个线程上,并且对堆栈内存具有相同的访问权限。那么,当您从vkEnumeratePhysicalDevices返回时,堆栈会弹出,对吗?因为param deviceCount是一个地址,当您更改要更改地址指向的内存的值。当您从vkEnumeratePhysicalDevices返回时,堆栈会弹出,但内存仍然在那里,以便您可以从pickPhysicalDevices的堆栈中获取值。很抱歉,有点迂腐…函数的
vkEnumeratePhysicalDevice
和参数(指向
vkEnumeratePhysicalDevice
)的指针位于同一堆栈上(每个线程有一个堆栈)。它们位于两个不同的堆栈帧中,在内存中相邻。@Steve,我说的堆栈是指堆栈帧。每个函数在堆栈上都有自己的堆栈帧。因此vkEnumeratePhysicalDevices正在更改不同堆栈中的值(因为它有那个内存地址),但这不会导致seg错误吗,因为我认为函数只允许更改它们自己堆栈中的变量值?“param deviceCount的地址被推送到vkEnumeratePhysicalDevices的堆栈中。”,这句话是不是意味着vkEnumeratePhysicalDevice的作用域就是pickPhysicalDevices的作用域,听起来不对。@Steve你说得对,我说的是stackframe。