如果函数接口有指针参数,既可以把指针所指向的数据传给函数使用,也可以由函数填充指针所指的内存空间,传回给调用者使用,例如strcpy的函数原型为
int select(int nfds, fd_set *readfds,fd_set *writefds,
fd_set *exceptfds, struct timeval*timeout);
传入参数示例:
假如我们实现一个函数,其参数通过地址来传入一个值,其原型如下:
调用者 | 实现者 |
1、分配p所指的内存空间; 2、在p所指的内存空间中保存数据; 3、调用函数; 4、由于有const限定符,调用者可以确信p所指的内存空间不会被改变。 | 1、规定指针参数的类型unit_t *; 2、读取p所指的内存空间。 |
传出参数示例:
假如我们实现一个函数,其参数通过地址传出一个值,其原型如下:
void func(unit_t *p);
其调用者与实现者之间的协议如下:
调用者 | 实现者 |
1、分配p所指的内存空间 2、调用函数 3、读取p所指的内存空间 | 1、规定指针参数的类型unit_t * 2、在p所指的内存空间中保存数据
|
Value-result参数示例:
void func(unit_t *p);
其调用者与实现者之间的协议如下:
调用者 | 实现者 |
1、分配p所指的内存空间 2、在p所指的内存空间保存数据 3、调用函数 4、读取p所指的内存空间 | 1、规定指针参数的类型unit_t * 2、读取p所指的内存空间 3、改写p所指的内存空间 |
注意:由于传出参数和Value-result参数的函数接口完全相同,应该在文档中说明是哪种参数。
很多系统函数对于指针参数是NULL的情况有特殊规定:如果传入参数是NULL表示取缺省值,例如pthread_create的pthread_attr_t*参数,也可能表示不做特别处理,例如free的参数;如果传出参数是NULL表示调用者不需要传出值,例如time的参数。这些特殊规定应该在文档中写清楚。
下面是一个传出参数的完整例子:
/* populator.h */
#ifndef POPULATOR_H
#define POPULATOR_H
typedef struct {
int number;
char msg[20];
} unit_t;
extern void set_unit(unit_t *);
#endif
/* populator.c */
#include
#include 'populator.h'
void set_unit(unit_t *p)
{
if (p == NULL)
return; /* ignore NULL parameter */
p->number = 3;
strcpy(p->msg, 'Hello World!');
}
/* main.c */
#include
#include 'populator.h'
int main(void)
{
unit_t u;
set_unit(&u);
printf('number: %d
msg: %s
', u.number, u.msg);
return 0;
}
二级指针的参数:
二级指针也是指针,同样可以表示传入参数、传出参数或者Value-result参数,只不过该参数所指的内存空间应该解释成一个指针变量。用两层指针做传出参数的系统函数也很常见,比如pthread_join的void**参数。下面看一个简单的例子。
二级指针做传出参数
/* redirect_ptr.h */
#ifndef REDIRECT_PTR_H
#define REDIRECT_PTR_H
extern void get_a_day(const char **);
#endif
这里的参数指针是constchar**,有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
#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 %s
', firstday, secondday);
return 0;
}
通过参数分配内存示例:
其调用者与实现者之间的协议如下:
调用者 | 实现者 |
1、分配pp所指的指针变量的空间; 2、调用alloc_unit分配内存; 3、读取pp所指的指针变量,通过后者使用alloc_unit分配的内存; 4、调用free_unit释放内存。 | 1、规定指针参数的类型unit_t **; 2、alloc_unit分配unit_t的内存并初始化,为pp所指的指针变量赋值; 3、free_unit释放在alloc_unit中分配的内存 |
下面是一个通过二级指针参数分配内存的例子
/* 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
#include
#include
#include 'para_allocator.h'
void alloc_unit(unit_t **pp)
{
unit_t *p = malloc(sizeof(unit_t));
if(p == NULL) {
printf('out of memory
');
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
#include 'para_allocator.h'
int main(void)
{
unit_t *p = NULL;
alloc_unit(&p);
printf('number: %d
msg: %s
', p->number, p->msg);
free_unit(p);
p = NULL;
return 0;
}
二级指针参数如果是传出的,可以有两种情况:
第一种情况,传出的指针指向静态内存,或者指向已分配的动态内存;
第二种情况是在函数中动态分配内存,然后传出的指针指向这块内存空间,这种情况下调用者应该在使用内存之后调用释放内存的函数,调用者的责任是请求分配和请求释放内存,实现者的责任是完成分配内存和释放内存的操作。由于这两种情况的函数接口相同,我们在撰写文档或添加注释时应该说明是哪一种情况。
返回值是指针的情况
返回值显然是传出的而不是传入的,如果返回值传出的是指针,和通过参数传出指针的情况类似,也分为两种情况:
第一种是传出指向静态内存或已分配的动态内存的指针;
第二种是在函数中动态分配内存并传出指向这块内存的指针,这种情况通常还要实现一个释放内存的函数,所以有和malloc对应的free。由于这两种情况的函数接口相同,应该在文档中说明是哪一种情况。
返回指向已分配内存的指针示例:
unit_t *func(void);
其调用者与实现者之间的协议如下:
调用者 | 实现者 |
1、调用函数 2、将返回值保存下来以备后用 | 1、规定返回值指针的类型unit_t * 2、返回一个指针 |
下面的例子演示返回指向已分配内存的指针
/* ret_ptr.h */
#ifndef RET_PTR_H
#define RET_PTR_H
extern char *get_a_day(int idx);
#endif
/* ret_ptr.c */
#include
#include 'ret_ptr.h'
static const char *msg[] = {'Sunday','Monday', 'Tuesday', 'Wednesday',
'Thursday','Friday', 'Saturday'};
char *get_a_day(int idx)
{
return msg[idx];
}
/* main.c */
#include
#include 'ret_ptr.h'
int main(void)
{
printf('%s %s
', get_a_day(0));
return 0;
}
动态分配内存并返回指针示例:
其调用者与实现者之间的协议如下:
调用者 | 实现者 |
1、调用alloc_unit分配内存; 2、将返回值保存下来以备后用; 3、调用free_unit释放内存。
| 1、规定返回值指针的类型unit_t *; 2、alloc_unit分配内存并返回指向该内存的指针; 3、free_unit释放由alloc_unit分配的内存。
|
以下是一个完整动态分配内存并返回指针的例子
/* ret_allocator.h */
#ifndef RET_ALLOCATOR_H
#define RET_ALLOCATOR_H
typedef struct {
int number;
char *msg;
} unit_t;
extern unit_t *alloc_unit(void);
extern void free_unit(unit_t *);
#endif
/* ret_allocator.c */
#include
#include
#include
#include 'ret_allocator.h'
unit_t *alloc_unit(void)
{
unit_t *p = malloc(sizeof(unit_t));
if(p == NULL) {
printf('out of memory
');
exit(1);
}
p->number = 3;
p->msg = malloc(20);
strcpy(p->msg, 'Hello world!');
return p;
}
void free_unit(unit_t *p)
{
free(p->msg);
free(p);
}
/* main.c */
#include
#include 'ret_allocator.h'
int main(void)
{
unit_t *p = alloc_unit();
printf('number: %d
msg: %s
', p->number, p->msg);
free_unit(p);
p = NULL;
return 0;
}
文章为作者独立观点,不代表 股票程序化软件自动交易接口观点