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

C 为什么有时将指针的指针作为参数传递?,c,pointers,pass-by-reference,pass-by-value,function-declaration,C,Pointers,Pass By Reference,Pass By Value,Function Declaration,我是新来C的,如果我的问题听起来很愚蠢,很抱歉。 我看到一些函数使用“double”指针作为参数,例如: int main(int argc, char **argv) { ... } 我可以理解双指针的需要,比如argv,因为argv是指向参数数组第一个元素的指针,该元素也是指向字符类型的指针。在这种情况下需要双指针。 但对于某些功能,如: int getaddrinfo(const char *host, const char *service, const struct addri

我是新来C的,如果我的问题听起来很愚蠢,很抱歉。 我看到一些函数使用“double”指针作为参数,例如:

int main(int argc, char **argv)
{
   ...
}
我可以理解双指针的需要,比如
argv
,因为
argv
是指向参数数组第一个元素的指针,该元素也是指向字符类型的指针。在这种情况下需要双指针。 但对于某些功能,如:

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); 
}
因此,参数是一个单指针,不需要通过指针,或者对象的地址允许函数更改存储在内存中该位置的值,因此当函数返回时,地址现在包含更新的值。如果函数参数需要接受指针变量,并且要更改指针变量,则必须传递指向该指针的地址,从而要求函数原型是指向指针的指针

解决您的问题可能会说明:
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);
传递对象的指针或地址允许函数更改存储在内存中该位置的值,因此当函数返回时,地址现在包含更新的值。如果函数参数需要接受指针变量,并且要更改指针变量,则必须传递指向该指针的地址,从而要求函数原型是指向指针的指针

解决您的问题可能会说明:
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);

你的代码不正确
ptr
测试的局部范围。指针只是一个表示内存地址的数字。您可能不会期望下面代码中的
test
会影响
number\u main
的值,对吗

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

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

如果您将
char*
内部化为某种虚构类型,您将调用表示内存地址的
number\u,然后您会认为它与本例中的
int
没有什么不同?

您的代码不正确
ptr
测试的局部范围。指针只是一个表示内存地址的数字。您可能不会期望下面代码中的
test
会影响
number\u main
的值,对吗

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

void test(int number_main)
{ 
    number_main = 10;
}
如果您将
char*
内部化为某种虚构的类型,您可以调用
number\u来表示内存\u地址,然后您会认为它与本例中的
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); 
}
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
打电话给我

test( &ptr_main );
因此,在函数中取消对指针
ptr
的引用,我们可以直接访问指向的对象(指针)
ptr\u 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", ( void * )px, *px );
    
    free( px );
    
    return 0;
}
要更改函数
f1
main
中声明的对象
x
,我们需要通过引用将其传递给函数。否则,函数将处理对象值的副本

指针
px
也会出现同样的情况。指针是对象。如果我们想更改函数
f2
main
中声明的指针
px
,我们需要通过引用将其传递给函数。否则,函数将处理对象值的副本

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

此函数

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