最近在基於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指針, 指代的內容可以改變, 指針本身的值不可改變。