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コード
関数は、3つのパラメータを受け入れます.1つ目は分析する列で、2つ目は定義子シーケンスで、3つ目は生成された「ポインタのポインタ」(すなわち2次元配列)のポインタです.実装は比較的簡単で、主にポインタの使い方を見ています.
Cコード
プログラムの本体は比較的簡単で、入力されたsに従って、定義子delimitersに従って分割し、分割が完了したら1つの2次元配列に配置し、1次元は最後の配列を表し、2次元は1つの配列の各要素の値を表す.
テスト
では、実行状況をテストします.
Cコード
実行結果は次のとおりです.
個人的な感覚では、指の多段ポインタをこのような熟練度に使うことができて、やっとCに対して掌握しました.「UNIXシステムプログラミング」のコードはとても優雅で、大学2年生から卒業まで、卒業後も暇を見つけて読んでいます.私はできるだけ続々と体得を貼って、参考にします.
一般的には、ポインタを配列に結びつけて理解します.例えば、*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コード
- int makeargv(const char *s, const char *delimiters, char ***argvp);
- int makeargv(const char *s, const char *delimiters, char ***argvp);
関数は、3つのパラメータを受け入れます.1つ目は分析する列で、2つ目は定義子シーケンスで、3つ目は生成された「ポインタのポインタ」(すなわち2次元配列)のポインタです.実装は比較的簡単で、主にポインタの使い方を見ています.
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に従って分割し、分割が完了したら1つの2次元配列に配置し、1次元は最後の配列を表し、2次元は1つの配列の各要素の値を表す.
テスト
では、実行状況をテストします.
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
", test);
- return 1;
- }
- printf("argument contains :
");
- for(i = 0;i < numtokens;i++)
- printf("%d:%s
", 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
", test);
- return 1;
- }
- printf("argument contains :
");
- for(i = 0;i < numtokens;i++)
- printf("%d:%s
", i, argvp[i]);
- return 0;
- }
実行結果は次のとおりです.
- 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システムプログラミング」のコードはとても優雅で、大学2年生から卒業まで、卒業後も暇を見つけて読んでいます.私はできるだけ続々と体得を貼って、参考にします.