最近,我们试图使用指向void的指针,将其地址的副本传递给类的实例,以便实例将其分配到与其包含的OpenCV Mat相同的内存空间,该内存空间包含在GPU和CPU共享的内存堆栈中,以便使用OpenCV+CUDA计算它。
然而,在这样做的时候,我们遇到了一个我们不太理解的问题。当将指针的地址传递给对象时,我们试图编辑该地址,以便指针托管在另一个空间上。虽然一旦副本超出范围,指针的值就会恢复原样(我会添加一个代码片段,因为它甚至很难解释)。但是,如果我们访问了传递给函数的指针地址的内容,并对其进行编辑,则会编辑原始指针。
我的假设是,当我们将指针的地址传递给函数时,会生成该内存地址值的副本,如果编辑了指向指针的指针,则其内容不会受到干扰,而在另一个函数中,我们访问了内容并直接编辑了它,因此,在正确编辑内容的同时,副本不会受到干扰并超出范围。
以下是我尝试两种方法的代码片段:
// Example program
#include <iostream>
#include <string>
void change_value(int **p, int *addr)
{
*p = addr;
}
void change_direction(int **p, int *addr)
{
std::cout << "p value: " << p << std::endl;
std::cout << "p contains: " << *p << std::endl;
std::cout << "p contains contains: " << **p << std::endl;
p = &addr;
std::cout << "p value: " << p << std::endl;
std::cout << "p contains: " << *p << std::endl;
std::cout << "p contains contains: " << **p << std::endl;
}
int main()
{
int a = 1, b = 2, c = 3;
int *ptr = &a;
std::cout << "ptr direction: " << &ptr << std::endl;
std::cout << "ptr value: " << ptr << std::endl;
std::cout << "ptr contains: " << *ptr << std::endl;
std::cout << std::endl;
change_value(&ptr, &b);
std::cout << "change_value" << std::endl;
std::cout << "ptr direction: " << &ptr << std::endl;
std::cout << "ptr value: " << ptr << std::endl;
std::cout << "ptr contains: " << *ptr << std::endl;
std::cout << std::endl;
change_direction(&ptr, &c);
std::cout << std::endl;
std::cout << "change_direction" << std::endl;
std::cout << "ptr direction: " << &ptr << std::endl;
std::cout << "ptr value: " << ptr << std::endl;
std::cout << "ptr contains: " << *ptr << std::endl;
}
这是我们得到的输出。我们可以看到,当ptr在change_value函数上编辑时,由于我们访问p的内容并对其进行编辑,因此它在change_direction上不会发生更改,因为当我们编辑p的地址时,它就停止指向ptr。
ptr direction: 0x710a27e3fe18
ptr value: 0x710a27e3fe0c
ptr contains: 1
change_value
ptr direction: 0x710a27e3fe18
ptr value: 0x710a27e3fe10
ptr contains: 2
p value: 0x710a27e3fe18
p contains: 0x710a27e3fe10
p contains contains: 2
p value: 0x710a27e3fdd8
p contains: 0x710a27e3fe14
p contains contains: 3
change_direction
ptr direction: 0x710a27e3fe18
ptr value: 0x710a27e3fe10
ptr contains: 2
如果有人能对所发生的事情做出更好的解释,我将不胜感激。
干杯。
不确定我是否理解这个问题,但如果是:
void change_direction(int **p, int *addr)
{
// ...
p = &addr;
// ...
}
应该修改传递给函数的参数,但它不正确。
参数是按值传递的,除非通过引用传递。建议传递引用,但如果您喜欢,可以使用指针。但是,您需要修改指针指向的内容,而不是指针。在上述函数中,p
是函数的局部。修改p
的值在函数之外没有任何作用。
你可能想要:
void change_direction(int **p, int *addr)
{
// ...
*p = addr;
// ...
}
或者更确切地说是
void change_direction(int *&p, int *addr)
{
// ...
p = addr; // p is a reference, hence no dereference needed
// ...
}
实际上,您应该更喜欢这里的int*&
,因为nullptr
不是有效的参数(这也是您使用指针而不是引用的唯一原因)。
@463035818_is_not_a_number提供了一个很好的答案,效果很好。但是,充分理解原始代码的作用可能是有价值的。
从一开始就乞讨:
int a = 1, b = 2, c = 3;
int *ptr = &a;
这将初始化堆栈内存中的三块内存,其中包含您给定的int
值(a,b,c
),并为保存a
地址的ptr
变量初始化另一块内存。
然后打印出地址和ptr
的值,这显然不会更改任何值。
接下来是对执行的change_value(int **p, int *addr)
的调用。
*p = addr;
在这种情况下,参数p
在存储器中的某个地方保持到int
的地址的地址,因此*p
是由p指向的地址。将其设置为addr
会将地址p
指向.
因此,在您的特定代码中:
change_value(&ptr,&b);
将ptr
的值设置为b
的地址。
然后是change_direction(int **p, int* addr)
调用(可能应该命名为change_address
),它执行(忽略打印):
p = &addr;
这将参数p
设置为addr
的地址。
但由于在C/C++中,所有函数都是由值调用的(在C中甚至没有任何引用,在C++中,您必须将其指定为@463035818_is_not_a_number),这对调用函数的原始值没有任何作用。
所以呼叫:
change_direction(&ptr,&c)
实际上并没有改变ptr
中的内容。在对函数的调用开始时,ptr
(因此&ptr
)的地址被复制到一段堆栈内存中,然后在函数中使用,并在函数退出后释放。
我希望这能澄清问题,有时你很难理解指针。
干杯。