淺談C語言中的多級指針
最近看《UNIX系統(tǒng)編程》,感覺能把C語言用到這個水平,才能算是登堂入室。
一般來說,我們會把指針跟數(shù)組聯(lián)系起來理解,比如*p就是一個一維數(shù)組,**p是兩維數(shù)組等,而一般而言,見到兩維的指針也算是難得了,更高維的只怕看一會就會暈掉。《UNIX系統(tǒng)編程》中有個關(guān)于參數(shù)列表的例子,感覺對指針運用的已經(jīng)到出神入化的境地,所以貼出來大家參考一下。
指向指針的多級指針
在C語言的入口main函數(shù)中,有一個**argv參數(shù),指明命令行參數(shù),一般寫法是這樣:
C代碼
- int main(int argc, char **argv){
- /*
- * code here.
- */
- }
- int main(int argc, char **argv){
- /*
- * code here.
- */
- }
這個**argv,是一個指向指針的指針,用來將命令行參數(shù)保存下來,比如,輸入一條命令:
prog -c -v 200
**argv中的內(nèi)容即為 prog, -c, -v, 200. 因為prog, -c等的長度不等,就需要一個指針來引用他們,而prog后邊接幾個參數(shù)也是不定的,所以有需要有一個指針來引用,所以就是這里的二維指針了。畫一個table可能看起來比較清晰一些:
prog |
-c |
-v |
200 |
再考慮這樣一種情況,shell程序,對于你會輸多少行命令也是不知道的,那它就需要再多一個指針來引用你會有多少個命令輸入。這就是我們今天要看的(***ptr)了。
指向"指針的指針"的多級指針
書中的例子是這樣,先看下函數(shù)的原型:
C代碼
- int makeargv(const char *s, const char *delimiters, char ***argvp);
- int makeargv(const char *s, const char *delimiters, char ***argvp);
函數(shù)接受三個參數(shù),第一個是要分析的串,第二個是界定符序列,第三個是生成的"指針的指針"(即二維數(shù)組)的指針。實現(xiàn)比較簡單,主要是看其中關(guān)于指針的用法:
C代碼
- /*
- * author : juntao.qiu
- */
- int makeargv(const char *s, const char *delimiters, char ***argvp){
- int error;
- int i;
- int numtokens;
- const char *snew;
- char *t;
- if((s == NULL) || (delimiters == NULL) || (argvp == NULL)){
- error = EINVAL;
- return -1;
- }
- *argvp = NULL;
- ssnew = s + strspn(s, delimiters);
- if((t = malloc(strlen(snew)+1)) == NULL)
- return -1;
- strcpy(t, snew);
- numtokens = 0;
- if(strtok(t, delimiters) != NULL)
- for(numtokens = 1; strtok(NULL, delimiters)!= NULL; numtokens++);
- if((*argvp = malloc((numtokens+1)*sizeof(char *))) == NULL){
- error = errno;
- free(t);
- errno = error;
- return -1;
- }
- if(numtokens == 0){
- free(t);
- }else{
- strcpy(t, snew);
- **argvp = strtok(t, delimiters);//注意此處的指針操作
- for(i = 1;i < numtokens;i++)
- *((*argvp)+i) = strtok(NULL, delimiters);//注意此處的指針操作
- }
- *((*argvp)+numtokens) = NULL;
- return numtokens;
- }
- /*
- * author : juntao.qiu
- */
- int makeargv(const char *s, const char *delimiters, char ***argvp){
- int error;
- int i;
- int numtokens;
- const char *snew;
- char *t;
- if((s == NULL) || (delimiters == NULL) || (argvp == NULL)){
- error = EINVAL;
- return -1;
- }
- *argvp = NULL;
- ssnew = s + strspn(s, delimiters);
- if((t = malloc(strlen(snew)+1)) == NULL)
- return -1;
- strcpy(t, snew);
- numtokens = 0;
- if(strtok(t, delimiters) != NULL)
- for(numtokens = 1; strtok(NULL, delimiters)!= NULL; numtokens++);
- if((*argvp = malloc((numtokens+1)*sizeof(char *))) == NULL){
- error = errno;
- free(t);
- errno = error;
- return -1;
- }
- if(numtokens == 0){
- free(t);
- }else{
- strcpy(t, snew);
- **argvp = strtok(t, delimiters);//注意此處的指針操作
- for(i = 1;i < numtokens;i++)
- *((*argvp)+i) = strtok(NULL, delimiters);//注意此處的指針操作
- }
- *((*argvp)+numtokens) = NULL;
- return numtokens;
- }
程序的主體比較簡單,就是按照傳入的s,按照界定符delimiters對其進行分割,分割完成后將其放在一個二維數(shù)組中,第一維表示最后數(shù)組,第二維表示第一個數(shù)組中每一個元素的值。
測試
好了,我們測試一下其運行情況:
C代碼
- int main(int argc, char **argv){
- char delim[] = " \t";
- int i;
- char **argvp;
- int numtokens;
- char *test = "mine -c 10 2.0";
- if((numtokens = makeargv(test, delim, &argvp)) == -1){
- fprintf(stderr, "failed to parse the string you given:%s\n", test);
- return 1;
- }
- printf("argument contains :\n");
- for(i = 0;i < numtokens;i++)
- printf("%d:%s\n", i, argvp[i]);
- return 0;
- }
- int main(int argc, char **argv){
- char delim[] = " \t";
- int i;
- char **argvp;
- int numtokens;
- char *test = "mine -c 10 2.0";
- if((numtokens = makeargv(test, delim, &argvp)) == -1){
- fprintf(stderr, "failed to parse the string you given:%s\n", test);
- return 1;
- }
- printf("argument contains :\n");
- for(i = 0;i < numtokens;i++)
- printf("%d:%s\n", i, argvp[i]);
- return 0;
- }
運行結(jié)果如下:
- C:\development\cpl\usp>ls
- Makefile a.exe makeargv.c nbproject
- C:\development\cpl\usp>a
- argument contains :
- 0:mine
- 1:-c
- 2:10
- 3:2.0
個人感覺,能把指多級指針用到這種熟練程度,才算是對C掌握了。《UNIX系統(tǒng)編程》中的代碼非常優(yōu)雅,從大二一直讀到畢業(yè),畢業(yè)后得空還在讀。我會盡量陸續(xù)把體會貼出來,以供參考。
【編輯推薦】