为什么有时将指针指针作为参数传递?

问题描述

我是C语言的新手,很抱歉,我的问题听起来很蠢。 我看到一些函数将“双”指针作为参数,例如:

int main(int argc,char **argv)
{
   ...
}

我可以理解需要使用argv这样的双指针,因为argv是指向实参数组的第一个元素的指针,该元素也是一个char类型的指针。在这种情况下,需要双指针。 但是对于某些功能,例如:

int getaddrinfo(const char *host,const char *service,const struct addrinfo *hints,struct addrinfo **result);

我不明白为什么需要双点,因为不涉及数组元素,而且我认为getaddrinfo在内部调用malloc,因此使用双指针可能是一个原因,但是我们可以拥有这样的东西:

int main() 
{
   char *ptr_main;
   test(ptr_main);
   free(ptr_main);
}

void test(char *ptr)
{ 
    ptr = malloc(10); 
}

因此参数是单个指针char * ptr,不需要char **ptr吗?

解决方法

传递指针或对象的地址可以使函数更改存储在内存中该位置的,因此,当函数返回时,地址现在包含更新的值。如果某个函数参数需要接受一个指针变量,并且要更改该指针变量,则必须传递该指针的地址,因此要求函数原型为指向指针的指针。

解决您的问题可能说明:getaddrinfo问题:我不明白为什么需要双倍点,因为不涉及数组元素

此结构的用法通常是:

struct addrinfo *result;//pointer variable
getaddrinfo("hostname","servicename",NULL,&result);
//                                           |_Passing address of a pointer variable.
//                                             thus requiring prototype to accommodate

因此,如前所述,对于要接收更新的结构信息的函数,它需要发送指针变量的地址,要求它是双指针:

int getaddrinfo(const char *host,...,struct addrinfo **result);
,

您的代码不正确。 ptrtest的范围内。指针只是代表内存地址的数字。您可能不会期望下面的代码中的test影响number_main的值,对吧?

int main() 
{
   int number_main;
   test(number_main);
   printf("%d\n",number_main);
}

void test(int number_main)
{ 
    number_main = 10;
}

如果您将char *内部化为某种虚构类型,将其称为number_that_represents_memory_address,也许会有所帮助,那么在这种情况下,您认为它与int没有什么不同?

,

此功能

void test(char *ptr)
{ 
    ptr = malloc(10); 
}

应在main中使用之前声明,并处理main中传递的参数值的副本

char *ptr_main;
test(ptr_main);

您可以通过以下方式想象函数调用和函数定义

char *ptr_main;
test(ptr_main);

//...

void test( /* char *ptr */ )
{ 
    char *ptr = ptr_main;
    ptr = malloc(10); 
}

因此您可以在函数中看到更改的是局部变量ptr。未在main中初始化且值不确定的参数ptr_main保持不变。

要更改原始指针ptr_main,您必须通过引用将其传递给函数。

在C语言中,通过引用传递机制是通过将对象间接地通过指向它的指针传递来实现的。

根据C标准(6.2.5类型)

-指针类型可以从函数类型或对象派生 类型,称为引用类型。 指针类型描述了一个对象 其值提供对所引用实体的引用 类型。有时,从引用类型T派生的指针类型是 称为“ T的指针”。从一个指针类型的构造 引用的类型称为“指针类型派生”。指针类型 是完整的对象类型。

所以函数定义应该像

void test( char **ptr )
{ 
    *ptr = malloc(10); 
}

test( &ptr_main );

因此,在函数中取消对指针ptr的引用后,我们可以直接访问指向的对象(指针)ptr_main,而指向(被引用的)对象现在在函数中已更改>

为清楚起见,请考虑以下演示程序。

#include <stdio.h>
#include <stdlib.h>

void f1( int *px )
{
    *px = 10;
}

void f2( int **ppx )
{
    *ppx = malloc( sizeof( int ) );
    **ppx = 20;
}

int main(void) 
{
    int x = 0;
    
    printf( "Before calling f1 x = %d\n",x );
    
    f1( &x );
    
    printf( "After  calling f1 x = %d\n",x );
    
    int *px = &x;
    
    printf( "Before calling f2 px = %p and *px = %d\n",( void * )px,*px );

    f2( &px );
    
    printf( "After  calling f2 px = %p and *px = %d\n",*px );
    
    free( px );
    
    return 0;
}

程序输出看起来像

Before calling f1 x = 0
After  calling f1 x = 10
Before calling f2 px = 0x7ffe79dd572c and *px = 10
After  calling f2 px = 0x55db88f5d270 and *px = 20

要更改函数xmain中声明的对象f1,我们需要通过引用将其传递给函数。否则,该函数将处理该对象的值的副本。

指针px也会发生相同的情况。指针是对象。如果要更改函数pxmain中声明的指针f2,则需要通过引用将其传递给函数。否则,该函数将处理该对象的值的副本。

从程序输出中可以看到,函数f2确实改变了main中声明的指针px的值。