2016-08-05 5 views
1

私は、プログラムを最初に実行するときにコマンドラインから引数を渡さなければならないmain関数を以下に宣言しました。その後、*argv[]の文字列入力配列を取り、のqsort関数を使用してそれらをソートし、最後にファイル名以外のすべての要素を入力配列に出力します。 qsortに渡さ"qsort"へのこの配列の受け渡しはどのように機能しますか?

int main(int argc,char *argv[]){                                                 
    qsort(argv,args,sizeof(*argv),comp_func); 
    for(int U=1;U<argc;U++)printf("%s\n",argv[U]);                                                
} 

comp_func機能を以下に示します。

int comp_func(char*a,char*b){ 
    return strcmp(*(char **)a,*(char **)b); 
} 

私が知りたいのですがどのようなここで何が起こっているのですか?私はかなりqsort配列の各2長さの並べ替えを与えられたコンパレータ関数に送信します。両方ともargvは文字列の配列なので、この場合は文字列です。しかし、私が得ることはありませんが、ここで何が起こっているかである。

strcmp(*(char **)a,*(char **)b) 

*(char **)aは何をしているのですか? char[]の任意の文字列へのポインタの配列を作成するだけです。その最初の値にaが割り当てられます。その後、最終的に参照解除され、最終的に文字列aが返されます。もしそうなら、それではなぜ普通の古き良きものはありませんa?また、面白いことに、printfが普通のaの場合、??O_?のようなランダムな文字列が出力されます。しかし、代わりに*(char **)aを印刷すると、実際の文字列が入力されます。何故ですか?私はCの初心者ですので、もう質問があれば私にご負担ください。

+1

それから、私はcomp_funcの署名が間違っていると思います。配列の各要素はchar *型であるため、キャストは間違った署名を補償しています。 –

+0

@ S.C.Madsen「署名」とはどういう意味ですか?申し訳ありませんが、それは愚かな質問のように見えるかもしれませんが、再び、私は 'C'のちょうど初心者なので、私はまだすべての条件を知っていません。 –

+0

私の答えは「署名」を参照してください。 comp_funcのパターンは、通常、(** a、** b)または「ポインタへのポインタ」をとります。最も一般的なのはvoid *で、これは基本的に汎用ポインタと呼ばれ、ポインタが実際に指しているものを定義する "キャスト"に依存します – softwarenewbie7331

答えて

2

tldr;その型キャストに続いて服従。

コンペア機能の典型的な形態は

int comp_func(void *a, void *b) 

(char**)aであるが、この場合に、その実際char配列の開始位置へのポインタ、char *にポインタにキャスト。

*(char**)a次に、逆参照します。つまり、配列の先頭へのポインタがstrcmp()関数に渡されます。

printfは、ポインタが配列のchar '\ 0'を指すまで、そのポインタから前方に印刷する配列の先頭へのポインタをとります。それはポインタへのポインタが渡されたためです。代わりにメモリアドレスが表示されます。あなたはchar *argv[]としてdecalredされる機能argvに渡している、だから、char **

として見ることができます。すべての比較関数の

+0

だから '' O_? 'はメモリアドレスですか? –

+0

です。 printfにchar配列を出力してポインタを渡すと、そのポインタから印刷されます(ポインタを1文字サイズだけ移動し続けます)。 '\ 0'文字または0のセットメモリ内の文字のサイズ。 – softwarenewbie7331

2

まず

その後
int comp_func(const void* a, const void* b) 

はコードを解析しようとする必要があります関数内で汎用ボイドポインタをルートタイプchar **にキャストする必要があります。

次に、あなたがそう、比較したいarray of pointersの要素への間接参照を持っている:*(char **)

+0

'a'はすでにポインタなので、普通の' a'は動作しません。基本的に、これを理解していると、 '*(char **)a'はポインタ' a'から実際の文字列を抽出し、 'a'は入力配列からその文字列へのポインタです。 –

+1

@ R.Kapはい、多かれ少なかれ。 'qsort()'は、基本配列の要素へのポインタを与えます。しかし、基本配列はcharポインタの配列なので、実際には 'const char **'を取得します。引数を指定して実際のchar配列を取得するには、ポインタを逆参照する必要があります。 – dhke

4

qsort()は、最初の引数baseなどのオブジェクトの連続した配列を期待しています。さて、argvconst char *ポインタの配列なので、

qsort(argv, args, sizeof(*argv), comp_func); 

sizeof(*argv)const char *の大きさであるポインタの配列を、並べ替え、と言います。

comp_func()に渡されるものは、基本ポインターからオフセットされた2つのオブジェクトのアドレス、つまり、argvのcharポインターのアドレスです。引数文字列を含む実際の文字列配列/ポインタを取得するには、それを逆参照する必要があります。つまり、引数文字列は実際には*a*bにあります。

シグネチャはまだ間違っていて、コンパイラの警告がどこにでも投げられるはずです。 comp_func()は、実際には2つのconst void *を取ります

int 
comp_func(const void *a,const void *b) { 
    return strcmp(*(const char **)a,*(const char **)b); 
} 

*aがあまりにも、const void *strcmp()ニーズconst char *と有効なタイプではないので、キャストが必要です。

関連する問題