2016-04-23 15 views
0

私はシェルを作成するこの小さなプログラムを見ています。 parse()は、文字ポインタlineと文字ポインタの配列argvを取り、各単語のアドレスをargvに保存します。私は理解していない何ポインタの配列へのポインタが初期アドレスに戻る

void parse(char *line, char **argv) { 
while (*line != '\0') {  /* if not the end of line ....... */ 
     while (*line == ' ' || *line == '\t' || *line == '\n') 
      *line++ = '\0';  /* replace white spaces with 0 */ 
     *argv++ = line;   /* save the argument position  */ 
     printf("%p\n",*argv); 
     while (*line != '\0' && *line != ' ' && 
      *line != '\t' && *line != '\n') 
      line++;    /* skip the argument until ... */ 
} 
*argv = '\0';     /* mark the end of argument list */ 
} 

argvは何とかバック関数が終了した後の最初の単語であるということです。主な機能は、呼び出します。それは、右の前にlineの終わりだったとき

parse(line, argv);  /* parse the line    */ 
     if (strcmp(argv[0], "exit") == 0) /* is it an "exit"?  */ 
      exit(0); 

がどのようlineの冒頭にargv[0]のですか?

+3

'* argv = '\ 0'; '、' argv'は文字列ではなく文字列へのポインタです。 '* argv = NULL'を意味しますか? –

+2

[最小完全な検証可能な例](http://stackoverflow.com/help/mcve)を参照してください。 – user3386109

+0

この質問は、後者と重複しない場合はhttp://stackoverflow.com/q/25769443/694576に関連しています。 – alk

答えて

2

理由はC.に値で渡されたパラメータは、それをこの方法を考えることである:上記の印刷物の両方で

void func(int a) 
{ 
    a = 20; 
} 

int main() 
{ 
    int val = 10; 
    printf("%d", val); 
    func(val); 
    printf("%d", val); 
} 

を、あなたはでのvalを変更したい場合は10になり、プリントアウト値funcの場合は、そのアドレスを渡す必要があります。ポインタでも同じです。ポインタは他のパラメータと同様に値渡しされます。あなたはこのようなものがあればこのように、:だろう

gcc a.c 
./a.out hello how are you 

出力:

#include <stdio.h> 

void func(char **argv) 
{ 
    while (*argv != 0) { 
    printf("%s\n", *argv); 
    argv++; 
    } 
    printf("*****done*****\n"); 
} 

int main(int argc, char **argv) 
{ 
    func(argv); 
    printf("%s\n", argv[0]); 
} 

をそしてあなたがそれを実行したい場合は

./a.out 
hello 
how 
are 
you 
*****done***** 
./a.out 

はARGVが最後のパラメータを指すように関数から戻ると、そのアドレスを渡す必要があります:

#include <stdio.h> 

void func(char ***argv) 
{ 
    while (**argv != 0) { 
    printf("%s\n", **argv); 
    (*argv)++; 
    } 
    (*argv)--; 
    printf("*****done*****\n"); 
} 

int main(int argc, char **argv) 
{ 
    func(&argv); 
    printf("%s\n", argv[0]); 
} 

そして今、出力は次のようになります。

./a.out 
hello 
how 
are 
you 
*****done***** 
you 
2

混乱がどこにあるか私は理解していれば、あなたがvoid parse(char *line, char **argv)関数にlineargvポインタを送る呼び出すとき、関数がして、各ポインタのCOPYを受け取ります各コピーにはすべて独自のアドレスがあります。増分は唯一の引数ベクトルのコピーに起こっとされているのでそうにかかわらず、あなたが関数内のポインタ自体に何をすべきか(例えばargv++, argv++argvを反復、それらの変更がmain()で見られることはありません

オリジナルのポインタはバックmainインチそれのいずれかについての手掛かりを持っていないあなたはargv内の個々の文字列のいずれかの内容を変更した場合

さて、これらの変更は、バックmainで見られますが、その他の非コンテンツの変更変更あなたの機能にのみローカルです。

あなたの関数内でポインタを変更できる唯一の方法は、のアドレスにの関数へのポインタを渡すことです。それでvoid parse(char **line, char ***argv)のプロトタイプが得られます。次に、自分の関数内でポインタiselfを変更し、それらの変更をmainに表示することができます。char *tmp = (*argv)[0]; (*argv)[0] = (*argv)[1]; (*argv)[1] = tmp;

関連する問題