最近在基于redis的c客户端hiredis做扩展的时候, 其中一个函数需要接受一个const char **的二级指针作为参数:
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
这个函数主要是用于 需要传递多个string值的场景,类似于 lpush, del key1 key2..., zadd key score1 member1 score2 member2...这类命令, 其中 argc是传递参数的个数, argv主要用于传递的string的value, 而argvlen 是每个string的size, 这里不讲解这个函数的具体用法,主要谈下如何构造这样一样二级指针,也算对c/c++基础内容的一个回顾。
我们都知道, 指针是c/c++中一种非常有用的数据类型, 用于存储一个数据的地址。一个指针有三种状态: 保存一个特定对象的地址; 指向某一个特定对象后边的某一个对象; 0值。 另外, 我们在定义一个指针的时候, 一定要记得初始化: int *p = 0。 指针有一级指针和多级指针之分, 一级指针比较简单,也比较好理解。而多级指针,就需要花点心思了,特别是c/c++这类需要手动管理内存的语言,使用的时候,更是要谨慎。
当我们在使用这个函数执行redis命令的时候, 所传递的string的个数通常是不确定的;所以这里就没法使用数组了(我们知道, 一维数组可以作为一级指针使用, 二维数组可以使用二级指针使用), 得使用动态内存分配了,代码实例:
int getCommandArgv(const vector<string> &vecArgs, char **&argv) { int argsLen = vecArgs.size(); char **arrArgv = new char*[argsLen]; vector<string>::const_iterator it = vecArgs.begin(); for (; it != vecArgs.end(); it++) { string tmpArgs = (*it); arrArgv[i] = new char[tmpArgs.size()]; memcpy(arrArgv[i], tmpArgs.c_str(), tmpArgs.size()); i++; }
for (int i = 0; i < argc; i++) {
if (argv[i] != NULL) {
delete [] argv[i];
argv[i] = NULL;
}
}
delete [] argv;
argv = NULL;
return 0; }
如代码所示,展示了如何把一个保存string的vector如何存储到一个char ** 的二级指针中。在给二级指针分配内容的时候, 不仅要给这个二级指针分配内存,同时,也要给它里边的每一个元素分配内存; 但最后一定不要忘了释放内存哦, 释放的时候, 需要先释放其中每一个元素指向的内存空间, 最后在释放这个二级指针指向的内存空间。
最后, 讲一下指针和const限定符。 根据《c++ primer》 里边描述的, 有 1: 指向const对象的指针, 2: const指针, 前者是指针指代的内容为const, 内容不可改变, 但指针本身的值可以改变; 后者为const指针, 指代的内容可以改变, 指针本身的值不可改变。