【问题标题】:Why do we need to pass an address value to an argument that accepts double pointers?为什么我们需要将地址值传递给接受双指针的参数?
【发布时间】:2021-05-23 09:08:11
【问题描述】:
#include <stdlib.h>
int malloc2(int **a) {
  *a = malloc(sizeof (int));
return 0;

}
int main() {
  int* b = NULL;
  malloc2(&b);
}

如果一个参数只接受双指针,它怎么能接受地址值呢?

【问题讨论】:

  • 一个指针持有一个地址值,这就是它的定义。

标签: c pointers pass-by-reference pass-by-value


【解决方案1】:

该函数接受单个 int ** 参数,即 pointer-to-pointer-to-int。

main 中的变量 b 的类型为 int *,即 pointer-to-int。如果你随后获取b 的地址,你现在有一个pointer-to-pointer-to-int,即int **,它与函数的参数相匹配。

【讨论】:

  • 我不得不问,这应该是直观的吗?在您回答之前,我试图想象在函数中粘贴一个地址以试图理解它。现在它有点道理,但它还没有完全点击。我们如何准确地插入指向参数的指针的地址?
  • @FilipTomic 你可以获取any变量的地址,不管它是否是指针类型。如果变量的类型为int,则其地址的类型为int *。如果变量的类型为int *,则其地址的类型为int **。
【解决方案2】:

如果不通过指向它的指针引用传递指针b,则函数将处理指针值的副本

在函数内更改副本不会影响原始指针。

因此函数会产生内存泄漏。

要更改原始指针b,该函数需要直接访问指针。可以通过解引用指向指针(对象)b的指针来实现。

比较这两个演示程序。

#include <stdio.h>

void f( int *p )
{
    ++p;
    printf( "Within the function f p = %p\n", ( void * )p );
}

int main(void) 
{
    int x = 10;
    int *p = &x;
    
    printf( "Before calling f p = %p\n", ( void * )p );
    
    f( p );
    
    printf( "After  calling f p = %p\n", ( void * )p );

    return 0;
}

程序输出是

Before calling f p = 0x7ffc3a940cbc
Within the function f p = 0x7ffc3a940cc0
After  calling f p = 0x7ffc3a940cbc

如您所见,在 main 中声明的指针 p 在调用函数 f 后没有改变。

还有另一个程序

#include <stdio.h>

void f( int **p )
{
    ++*p;
    printf( "Within the function f p = %p\n", ( void * )p );
}

int main(void) 
{
    int x = 10;
    int *p = &x;
    
    printf( "Before calling f p = %p\n", ( void * )p );
    
    f( &p );
    
    printf( "After  calling f p = %p\n", ( void * )p );

    return 0;
}

程序输出是

Before calling f p = 0x7ffe011131ec
Within the function f p = 0x7ffe011131f0
After  calling f p = 0x7ffe011131f0

现在您可以看到,在调用函数 f 后,main 中声明的指针 p 发生了变化,因为它是通过指向它的指针通过引用传递给函数的。取消对指针的引用,函数可以直接访问 main 中声明的指针 p。

如果一个参数只接受双指针,它怎么能接受一个 地址值

每个值都根据其类型进行解释。此表达式&amp;b 的值具有int ** 类型。并且函数参数也有int **的类型。

您可以想象函数定义及其调用方式如下

int main() {
  int* b = NULL;
  malloc2(&b);
}
//...
int malloc2( /* int **a */ ) {
  int **a = &b; 
  *a = malloc(sizeof (int));
return 0;
}

即函数参数a被表达式&amp;b的值初始化。

或者更简单的例子

int main( void )
{
    int x = 10;
    int *b = &x;
    int **a = &b;
}

【讨论】:

  • 我对这篇文章的表述很糟糕,因为它是一个由两部分组成的问题,我还想了解为什么我们传递一个地址(在这种情况下为 &amp;p),这对我来说不是很直观这样做充当函数接受的双指针
  • @FilipTomic 再读一遍我的答案。演示程序都写得很清楚。您问题中的函数试图更改 main 中声明的原始指针。所以指针应该通过引用传递。否则该函数将处理指针值的副本并更改副本而不是原始指针,
  • 我知道 C 是一种按值传递的语言,您的帖子为克服这一点做了什么,但我无法理解直接传递地址的想法。 C如何将其视为双指针?如果我们刚刚传递的那个地址是一个指向其他东西的指针,而不是另一个指向另一个地址的指针,那么根据定义,它不能是双指针,对吧?这只是一个单指针,所以我想知道 C 如何接受它作为双指针参数
  • @FilipTomic 根据定义,表达式 &b 的类型为 int **。并且函数参数的类型为 int **。所以函数参数由表达式的值初始化。
  • @FilipTomic 每个值都由其类型解释。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-07
  • 1970-01-01
  • 2020-07-02
  • 2011-03-14
  • 2021-06-02
相关资源
最近更新 更多