3. 两层指针的参数
两层指针也是指针,同样可以表示传入参数、传出参数或者 Value-result 参数,只不过该参数所指的内存空间应该解释成一个指针变量。用两层指针做传出参数的系统函数也很常见,比如 pthread_join(3) 的 void ** 参数。下面看一个简单的例子。
例 24.3. 两层指针做传出参数
/* redirect_ptr.h */
#ifndef REDIRECT_PTR_H
#define REDIRECT_PTR_H
extern void get_a_day(const char **);
#endif
想一想,这里的参数指针是 const char ** ,有 const 限定符,却不是传入参数而是传出参数,为什么?如果是传入参数应该怎么表示?
/* redirect_ptr.c */
#include "redirect_ptr.h"
static const char *msg[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"};
void get_a_day(const char **pp)
{
static int i = 0;
*pp = msg[i%7];
i++;
}
/* main.c */
#include <stdio.h>
#include "redirect_ptr.h"
int main(void)
{
const char *firstday = NULL;
const char *secondday = NULL;
get_a_day(&firstday);
get_a_day(&secondday);
printf("%s\t%s\n", firstday, secondday);
return 0;
}
两层指针作为传出参数还有一种特别的用法,可以在函数中分配内存,调用者通过传出参数取得指向该内存的指针,比如 getaddrinfo(3) 的 struct addrinfo ** 参数。一般来说,实现一个分配内存的函数就要实现一个释放内存的函数,所以 getaddrinfo(3) 有一个对应的 freeaddrinfo(3) 函数。
表 24.4. 通过参数分配内存示例: void alloc_unit(unit_t **pp); void free_unit(unit_t *p);
| 调用者 | 实现者 |
|---|---|
| 分配 pp 所指的指针变量的空间调用 alloc_unit 分配内存读取 pp 所指的指针变量,通过后者使用 alloc_unit 分配的内存调用 free_unit 释放内存 | 规定指针参数的类型 unit_t **alloc_unit 分配 unit_t 的内存并初始化,为 pp 所指的指针变量赋值 free_unit 释放在 alloc_unit 中分配的内存 |
例 24.4. 通过两层指针参数分配内存
/* para_allocator.h */
#ifndef PARA_ALLOCATOR_H
#define PARA_ALLOCATOR_H
typedef struct {
int number;
char *msg;
} unit_t;
extern void alloc_unit(unit_t **);
extern void free_unit(unit_t *);
#endif
/* para_allocator.c */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "para_allocator.h"
void alloc_unit(unit_t **pp)
{
unit_t *p = malloc(sizeof(unit_t));
if(p == NULL) {
printf("out of memory\n");
exit(1);
}
p->number = 3;
p->msg = malloc(20);
strcpy(p->msg, "Hello World!");
*pp = p;
}
void free_unit(unit_t *p)
{
free(p->msg);
free(p);
}
/* main.c */
#include <stdio.h>
#include "para_allocator.h"
int main(void)
{
unit_t *p = NULL;
alloc_unit(&p);
printf("number: %d\nmsg: %s\n", p->number, p->msg);
free_unit(p);
p = NULL;
return 0;
}
思考一下,为什么在 main 函数中不能直接调用 free(p) 释放内存,而要调用 free_unit(p) ?为什么一层指针的函数接口 void alloc_unit(unit_t *p); 不能分配内存,而一定要用两层指针的函数接口?
总结一下,两层指针参数如果是传出的,可以有两种情况:第一种情况,传出的指针指向静态内存(比如上面的例子),或者指向已分配的动态内存(比如指向某个链表的节点);第二种情况是在函数中动态分配内存,然后传出的指针指向这块内存空间,这种情况下调用者应该在使用内存之后调用释放内存的函数,调用者的责任是请求分配和请求释放内存,实现者的责任是完成分配内存和释放内存的操作。由于这两种情况的函数接口相同,应该在文档中说明是哪一种情况。