C言語のマルチレベルポインタについて

68803 ワード

最近『UNIXシステムプログラミング』を見て、C言語をこのレベルで使えるようになった気がします.
一般的には、ポインタを配列に結びつけて理解します.例えば、*pは1次元配列であり、*pは2次元配列であるなどですが、一般的には、2次元のポインタを見るのも難しいです.もっと高い次元のものは、見ると気絶するのではないかと心配しています.「UNIXシステムプログラミング」にはパラメータリストの例がありますが、ポインタの使い方にうっとりしているような気がしますので、参考にしてみてください.
ポインタを指すマルチレベルポインタ
C言語のエントリmain関数には、コマンドラインパラメータを示す**argvパラメータがあります.一般的な書き方は次のとおりです.
Cコード
int main(int argc, char **argv){     
    /*    
     * code here.    
     */    
}    
 
int main(int argc, char **argv){  
    /*  
     * code here.  
     */ 
}  
この**argvは、コマンドラインパラメータを保存するためのポインタです.たとえば、コマンドを入力します.
prog -c -v 200
**argvの内容はprog,-c,-v,200である.Prog,-cなどの長さが等しくないため,1つのポインタで参照する必要があり,progの後にいくつかのパラメータが続くのも不定であるため,1つのポインタで参照する必要があるので,ここの2次元ポインタである.tableを描くと、よりはっきり見えるかもしれません.
prog
-c
-v
200
このような状況を考えてみると、shellプログラムは、あなたがどれだけのコマンドに負けるか分からないので、どれだけのコマンド入力があるかを参照するためにもう1つのポインタが必要です.これが私たちが今日見る(**ptr)です.
「ポインタのポインタ」へのマルチレベルポインタ
本の例はこうです.まず関数の原型を見てみましょう.
Cコード

  
  
  
  
  1. int makeargv(const char *s, const char *delimiters, char ***argvp);    
  2. int makeargv(const char *s, const char *delimiters, char ***argvp);  

関数は、3つのパラメータを受け入れます.1つ目は分析する列で、2つ目は定義子シーケンスで、3つ目は生成された「ポインタのポインタ」(すなわち2次元配列)のポインタです.実装は比較的簡単で、主にポインタの使い方を見ています.
Cコード

  
  
  
  
  1. /*    
  2.  * author : juntao.qiu    
  3.  */    
  4. int makeargv(const char *s, const char *delimiters, char ***argvp){     
  5.     int error;     
  6.     int i;     
  7.     int numtokens;     
  8.     const char *snew;     
  9.     char *t;     
  10.     
  11.     if((s == NULL) || (delimiters == NULL) || (argvp == NULL)){     
  12.         error = EINVAL;     
  13.         return -1;     
  14.     }     
  15.     
  16.     *argvp = NULL;     
  17.     ssnew = s + strspn(s, delimiters);     
  18.     if((t = malloc(strlen(snew)+1)) == NULL)     
  19.         return -1;     
  20.     
  21.     strcpy(t, snew);     
  22.     numtokens = 0;     
  23.     
  24.     if(strtok(t, delimiters) != NULL)     
  25.         for(numtokens = 1; strtok(NULL, delimiters)!= NULL; numtokens++);     
  26.     
  27.     if((*argvp = malloc((numtokens+1)*sizeof(char *))) == NULL){     
  28.         error = errno;     
  29.         free(t);     
  30.         errno = error;     
  31.         return -1;     
  32.     }     
  33.     
  34.     if(numtokens == 0){     
  35.         free(t);     
  36.     }else{     
  37.         strcpy(t, snew);     
  38.         **argvp = strtok(t, delimiters);//      
  39.         for(i = 1;i < numtokens;i++)     
  40.             *((*argvp)+i) = strtok(NULL, delimiters);//      
  41.     }     
  42.              
  43.     *((*argvp)+numtokens) = NULL;     
  44.     
  45.     return numtokens;     
  46. }    
  47.  
  48. /*  
  49.  * author : juntao.qiu  
  50.  */  
  51. int makeargv(const char *s, const char *delimiters, char ***argvp){  
  52.     int error;  
  53.     int i;  
  54.     int numtokens;  
  55.     const char *snew;  
  56.     char *t;  
  57.  
  58.     if((s == NULL) || (delimiters == NULL) || (argvp == NULL)){  
  59.         error = EINVAL;  
  60.         return -1;  
  61.     }  
  62.  
  63.     *argvp = NULL;  
  64.     ssnew = s + strspn(s, delimiters);  
  65.     if((t = malloc(strlen(snew)+1)) == NULL)  
  66.         return -1;  
  67.  
  68.     strcpy(t, snew);  
  69.     numtokens = 0;  
  70.  
  71.     if(strtok(t, delimiters) != NULL)  
  72.         for(numtokens = 1; strtok(NULL, delimiters)!= NULL; numtokens++);  
  73.  
  74.     if((*argvp = malloc((numtokens+1)*sizeof(char *))) == NULL){  
  75.         error = errno;  
  76.         free(t);  
  77.         errno = error;  
  78.         return -1;  
  79.     }  
  80.  
  81.     if(numtokens == 0){  
  82.         free(t);  
  83.     }else{  
  84.         strcpy(t, snew);  
  85.         **argvp = strtok(t, delimiters);//  
  86.         for(i = 1;i < numtokens;i++)  
  87.             *((*argvp)+i) = strtok(NULL, delimiters);//  
  88.     }  
  89.           
  90.     *((*argvp)+numtokens) = NULL;  
  91.  
  92.     return numtokens;  
  93. }  

プログラムの本体は比較的簡単で、入力されたsに従って、定義子delimitersに従って分割し、分割が完了したら1つの2次元配列に配置し、1次元は最後の配列を表し、2次元は1つの配列の各要素の値を表す.
テスト
では、実行状況をテストします.
Cコード

  
  
  
  
  1. int main(int argc, char **argv){     
  2.     char delim[] = " \t";     
  3.     int i;     
  4.     char **argvp;     
  5.     int numtokens;     
  6.     char *test = "mine -c 10 2.0";     
  7.     
  8.     if((numtokens = makeargv(test, delim, &argvp)) == -1){     
  9.         fprintf(stderr, "failed to parse the string you given:%s
    ", test);     
  10.         return 1;     
  11.     }     
  12.     printf("argument contains :
    ");     
  13.     for(i = 0;i < numtokens;i++)     
  14.         printf("%d:%s
    ", i, argvp[i]);     
  15.     return 0;     
  16. }    
  17.  
  18. int main(int argc, char **argv){  
  19.     char delim[] = " \t";  
  20.     int i;  
  21.     char **argvp;  
  22.     int numtokens;  
  23.     char *test = "mine -c 10 2.0";  
  24.  
  25.     if((numtokens = makeargv(test, delim, &argvp)) == -1){  
  26.         fprintf(stderr, "failed to parse the string you given:%s
    ", test);  
  27.         return 1;  
  28.     }  
  29.     printf("argument contains :
    ");  
  30.     for(i = 0;i < numtokens;i++)  
  31.         printf("%d:%s
    ", i, argvp[i]);  
  32.     return 0;  
  33. }   

実行結果は次のとおりです.

  
  
  
  
  1. C:\development\cpl\usp>ls   
  2. Makefile a.exe makeargv.c nbproject   
  3.  
  4. C:\development\cpl\usp>a   
  5. argument contains :   
  6. 0:mine   
  7. 1:-c   
  8. 2:10   
  9. 3:2.0 

個人的な感覚では、指の多段ポインタをこのような熟練度に使うことができて、やっとCに対して掌握しました.「UNIXシステムプログラミング」のコードはとても優雅で、大学2年生から卒業まで、卒業後も暇を見つけて読んでいます.私はできるだけ続々と体得を貼って、参考にします.