多级指针的一个用法是:传递指针参数,如:int GetBinData(char ** data,int &len); 这样定义接口的初衷是,在调用函数之前不知道获得的数据的大小,因而无法准确的开辟合适大小的内存。于是希望在函数内部执行内存的开辟操作,并将开辟的内存地址和大小通过参数返回给调用者(当然我们也可以通过函数返回值来得到新分配的地址)。这里存在一个理解上的误区,我们可能认为传递的一个是一级指针而不是二级。这是错误的,当把某个级别的指针作为同级的指针参数进行传递时,实际执行的是按值传递。当函数返回后该指针仍是指向传递前的地址(就算是该指针的值指向了一个新地址:通过new,但是这个地址不会被带回),亦即原来实参的地址,而不是会待会函数内部所开辟的内存的地址。
如下:
char *buf=0; //buf是一个指针
int len=0;
int rsl=GetBinData(&buf,len); //&buf 是变量buf的地址,其即是一个二级指针
于是函数内部得到了buf的地址,在开辟内存后将新的地址赋予buf:
int GetBinData(char ** data,int &len)
{
//'....
* data=new char[datasize]; //data=0x00186512
//......
}
如果参数使用的是一级指针,data从实参buf得到的地址将是0,这是buf的值,因而这是一个传值过程。而当使用二级指针时,data从实参得到的是buf的地址(一个非0值),此时对buf(*data)的赋值将覆盖原值0。亦即buf得到了在函数内部开辟的内存的地址。另一种理解方式是,使用参数返回函数内部的值必须传递地址(或引用)(可以理解为在内存的地址上进行操作,就像是操作全局变量,因为内存地址是固定的),而buf的地址就是char**(buf的本身已经是char*)。
通过参数分配内存需要两层的指针,而通过返回值分配内存就只需要返回一层的指针:
动态分配内存并返回指针
/* 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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "ret_allocator.h"
unit_t *alloc_unit(void)
{
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!");
return p;
}
void free_unit(unit_t *p)
{
free(p->msg);
free(p);
}
/* main.c */
#include <stdio.h>
#include "ret_allocator.h"
int main(void)
{
unit_t *p = alloc_unit();
printf("number: %d\nmsg: %s\n", p->number, p->msg);
free_unit(p);
p = NULL;
return 0;
}