指向结构的指针作为函数的参数有什么用?
What is the use of a pointer to pointer to struct as an arguments of a function?
问题的原因是似乎没有理由使用像“struct **pointer”这样的双重间接寻址。
为了理解指向结构的指针作为函数参数的功能,我准备了一个示例。目的是查看函数对结构所做的更改是否超出了函数的范围,或者它们是否只在函数内部产生影响。这是按值或按引用传递参数的常见问题。
#include <stdio.h>
/* A simple structure is defined to see the effect that the functions
* have on it. */
typedef struct est
{
int val1;
int val2;
} est_t;
/* These three functions simply assign the values val1 and val2 to the
* structure. Each of these functions uses a different way of passing
* the parameter to the function referring to the structure. There are
* more comments below, in the definition of each function. */
void foo(int, int, est_t);
void bar(int, int, est_t*);
void baz(int, int, est_t**);
/* This is a function to print the values of a structure and make the
* code cleaner. It also contains a parameter about a structure! */
void print_est(est_t*);
int main (int argc, char *argv[])
{
est_t a;
foo(10, 11, a);
print_est(&a);
bar(20, 21, &a);
print_est(&a);
est_t *p = &a;
baz(30, 31, &p);
print_est(&a);
return 0;
}
void foo(int v1, int v2, est_t ve)
{
/* In this case the structure is "directly put" into the function.
* As the structure already is inside the function, the values of each
* element are assigned with the ". " */
ve.val1 = v1;
ve.val2 = v2;
/* With these printf you can see what is happening within the
* function. */
printf("[foo] val1 = %d\n", ve.val1);
printf("[foo] val2 = %d\n", ve.val2);
}
void bar(int v1, int v2, est_t *ve)
{
/* In this case the structure is passed into the function using a
* pointer. */
ve->val1 = v1;
ve->val2 = v2;
printf("\n[bar] val1 = %d\n", ve->val1);
printf("[bar] val2 = %d\n", ve->val2);
}
void baz(int v1, int v2, est_t **pp)
{
/* In this case the structure is passed into the function using a
* pointer to a pointer to a struct. */
(*pp)->val1 = v1;
(*pp)->val2 = v2;
printf("\n[baz] val1 = %d\n", (*pp)->val1);
printf("[baz] val2 = %d\n", (*pp)->val2);
}
void print_est(est_t *addr)
{
printf("[main] val1 = %d\n", addr->val1);
printf("[main] val2 = %d\n", addr->val2);
}
这是您 运行 程序时的输出。
foo(10, 11, a);
[foo] val1 = 10
[foo] val2 = 11
[main] val1 = -1238356256
[main] val2 = 32764
您可以看到在函数内分配的值并没有保留在函数外
让我们看看 bar 和 baz 的输出。
bar(20, 21, &a);
[bar] val1 = 20
[bar] val2 = 21
[main] val1 = 20
[main] val2 = 21
est_t *p = &a;
baz(30, 31, &p);
[baz] val1 = 30
[baz] val2 = 31
[main] val1 = 30
[main] val2 = 31
他们好像也是这样。我的意思是在这两种情况下,值都保留在函数之外。
Foo和bar是典型的by-value和by-reference,即使更改不是永久性的,从节省资源的角度来看,通过引用传递结构的想法也很有趣。参见 advantage of passing pointer to a struct as argument?
但正如 bar 和 baz 所做的一样,是否有任何理由使用双指针将参数传递给函数?
is there any reason to use a double pointer to pass arguments to a function
是的。只要您想更改传递的参数,就可以使用指针。所以如果你想改变一个指针,那么你需要一个指向指针的指针。
简单示例:
void foo(struct bar **ptr)
{
*ptr = malloc(10 * sizeof **ptr);
for(int i=0; i<10; i++)
(**ptr)->x = i;
}
函数接受类型 T **
的参数(对于任何类型 T
)通常有两个原因:
- 参数对应一个指针数组;
- 该函数用于更新指针值。
作为第一个例子,假设我们有这样的代码
int main( void )
{
char *strs[] = { "foo", "bar", "bletch", "blurga", NULL };
func( strs );
...
}
strs
是一个指针数组,但是由于通常的衰减规则,func
接收到的是指向指针的指针:
void func( char **s )
{
...
}
或者,您的函数旨在更新指针值。假设我们已经动态分配了一个 struct
类型的数组,我们需要用 realloc
扩展并初始化扩展内存。为了使它更清晰一些,我们将其放在一个单独的函数中:
void extend( struct s **ptr, size_t *size )
{
struct s *tmp = realloc( *ptr, *size * 2 );
if ( tmp )
{
for ( size_t i = *size; i < *size * 2; i++ )
init ( &tmp[i] );
*ptr = tmp;
*size *= 2;
}
}
问题的原因是似乎没有理由使用像“struct **pointer”这样的双重间接寻址。
为了理解指向结构的指针作为函数参数的功能,我准备了一个示例。目的是查看函数对结构所做的更改是否超出了函数的范围,或者它们是否只在函数内部产生影响。这是按值或按引用传递参数的常见问题。
#include <stdio.h>
/* A simple structure is defined to see the effect that the functions
* have on it. */
typedef struct est
{
int val1;
int val2;
} est_t;
/* These three functions simply assign the values val1 and val2 to the
* structure. Each of these functions uses a different way of passing
* the parameter to the function referring to the structure. There are
* more comments below, in the definition of each function. */
void foo(int, int, est_t);
void bar(int, int, est_t*);
void baz(int, int, est_t**);
/* This is a function to print the values of a structure and make the
* code cleaner. It also contains a parameter about a structure! */
void print_est(est_t*);
int main (int argc, char *argv[])
{
est_t a;
foo(10, 11, a);
print_est(&a);
bar(20, 21, &a);
print_est(&a);
est_t *p = &a;
baz(30, 31, &p);
print_est(&a);
return 0;
}
void foo(int v1, int v2, est_t ve)
{
/* In this case the structure is "directly put" into the function.
* As the structure already is inside the function, the values of each
* element are assigned with the ". " */
ve.val1 = v1;
ve.val2 = v2;
/* With these printf you can see what is happening within the
* function. */
printf("[foo] val1 = %d\n", ve.val1);
printf("[foo] val2 = %d\n", ve.val2);
}
void bar(int v1, int v2, est_t *ve)
{
/* In this case the structure is passed into the function using a
* pointer. */
ve->val1 = v1;
ve->val2 = v2;
printf("\n[bar] val1 = %d\n", ve->val1);
printf("[bar] val2 = %d\n", ve->val2);
}
void baz(int v1, int v2, est_t **pp)
{
/* In this case the structure is passed into the function using a
* pointer to a pointer to a struct. */
(*pp)->val1 = v1;
(*pp)->val2 = v2;
printf("\n[baz] val1 = %d\n", (*pp)->val1);
printf("[baz] val2 = %d\n", (*pp)->val2);
}
void print_est(est_t *addr)
{
printf("[main] val1 = %d\n", addr->val1);
printf("[main] val2 = %d\n", addr->val2);
}
这是您 运行 程序时的输出。
foo(10, 11, a);
[foo] val1 = 10
[foo] val2 = 11
[main] val1 = -1238356256
[main] val2 = 32764
您可以看到在函数内分配的值并没有保留在函数外
让我们看看 bar 和 baz 的输出。
bar(20, 21, &a);
[bar] val1 = 20
[bar] val2 = 21
[main] val1 = 20
[main] val2 = 21
est_t *p = &a;
baz(30, 31, &p);
[baz] val1 = 30
[baz] val2 = 31
[main] val1 = 30
[main] val2 = 31
他们好像也是这样。我的意思是在这两种情况下,值都保留在函数之外。
Foo和bar是典型的by-value和by-reference,即使更改不是永久性的,从节省资源的角度来看,通过引用传递结构的想法也很有趣。参见 advantage of passing pointer to a struct as argument?
但正如 bar 和 baz 所做的一样,是否有任何理由使用双指针将参数传递给函数?
is there any reason to use a double pointer to pass arguments to a function
是的。只要您想更改传递的参数,就可以使用指针。所以如果你想改变一个指针,那么你需要一个指向指针的指针。
简单示例:
void foo(struct bar **ptr)
{
*ptr = malloc(10 * sizeof **ptr);
for(int i=0; i<10; i++)
(**ptr)->x = i;
}
函数接受类型 T **
的参数(对于任何类型 T
)通常有两个原因:
- 参数对应一个指针数组;
- 该函数用于更新指针值。
作为第一个例子,假设我们有这样的代码
int main( void )
{
char *strs[] = { "foo", "bar", "bletch", "blurga", NULL };
func( strs );
...
}
strs
是一个指针数组,但是由于通常的衰减规则,func
接收到的是指向指针的指针:
void func( char **s )
{
...
}
或者,您的函数旨在更新指针值。假设我们已经动态分配了一个 struct
类型的数组,我们需要用 realloc
扩展并初始化扩展内存。为了使它更清晰一些,我们将其放在一个单独的函数中:
void extend( struct s **ptr, size_t *size )
{
struct s *tmp = realloc( *ptr, *size * 2 );
if ( tmp )
{
for ( size_t i = *size; i < *size * 2; i++ )
init ( &tmp[i] );
*ptr = tmp;
*size *= 2;
}
}