更改指针的地址以编辑其值



最近,我们试图使用指向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)的地址被复制到一段堆栈内存中,然后在函数中使用,并在函数退出后释放。

我希望这能澄清问题,有时你很难理解指针。

干杯。

最新更新