0

ライブラリ関数を使用して文字列を比較するには、比較関数を記述して 2 つの文字列を比較する方法を学びましたが、なぜこれを行っているのかはよくわかりません。

int StrCmp(const void *a, const void *b){
    char *s1 = *(char**) a;
    char *s2 = *(char**) b;
    return strcmp(s1,s2);
}

最初に char ** にキャストする必要があるのはなぜですか? それらを char * に直接キャストしないのはなぜですか? お気に入り

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

(ポインター)を(ポインターへのポインター)にキャストすることの意味は何ですか

char *x = "string";

x のキャストを行う場合

(char**)x; // what is this? Is this character 's'?

私はこれとかなり混乱しています。明確にしてくれてありがとう。もう1つの質問は、それがconstである場合、constについてです。まだキャストできますか?(できることはわかっていますが)

4

3 に答える 3

4

「なぜ最初に (char ポインタ ポインタ) にキャストしなければならないのですか? なぜ (char ポインタ) に直接キャストしないのですか?」


彼らはそれをあるがままにキャストしなければなりません。入ってくる値がメモリ位置 10,000 を指していると仮定すると、次のようになります。

  (char **) 

  a                 address a
                    "points to"
                    *a                **a   
  mem 1000          mem 10000         mem 20000
  to mem 1007       to mem 10007
  _____________     _____________     _______________ 
  pointer var  --> char pointer   ->  char
  10000             20000             'a'
  _____________     _____________     _______________

これを (char *) にキャストすると、a (この場合は 10,000) が参照するアドレスが char であることをコンパイラーに伝えます。これは正しくありません。

  (char *)          address a points 
  a                 to
  mem 1000          mem 10000         mem 20000
  to mem 1007
  _____________     ______            ________________
  pointer var  -->  "char"            unreachable char
  10000             ?                 'a'
  _____________     ______            ________________

「(ポインターを)(ポインターへのポインター)にキャストすることの意味は何ですか

char *x = "文字列"; x のキャストを行う場合

(char**)x; // これは何ですか?このキャラクターは's'ですか?」


この例には次のようなものがあります。

x            *x or x[0] x[1]       x[2]      x[3]      x[4]      x[5]      x[6]
mem 15000    mem 30000  mem 30001  mem 30002 mem 30003 mem 30004 mem 30005 mem 30006
to 15007
char *       char       char       char      char      char      char      char
_________    _________  _________  _________ _________ _________ _________ _________

30000    -->    's'       't'         'r'      'i'      'n'       'g'       '\0'
________     _________  _________  _________ _________ _________ _________ _________

x が char** であることをコンパイラに伝えると、次のパターンであると見なされます。

x              *x or x[0]         **x
               char *
mem 15000      mem 30000          "char" 
to 15007       to 30007
__________     _________          _________

30000      --> "string\0?"
               converted to
               pointer value  ->   ??
__________     _________          _________

30000 から始まる最初の 8 バイトが解決される「アドレス」に誤って移動し、「文字」を取得します。しかし、30000 は null で終わる文字配列の開始であるため、せいぜいメモリの一部に移動し、有効な文字であると考えてランダムなバイトを取得します。最悪の場合、このプログラムにとって無効なアドレスを取得し、アクセスしようとすると致命的なエラーが発生します。


だから私はただすることができますか

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

いいえ、a と b は char ポインターではないためです。避けられない char ポインターを取得するには、次のようにします。

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

Linden の例を使用すると、次のように呼び出します。

#include <stdio.h>
#include <string.h>

int StrCmp(const void *a, const void *b){
    char *s1 = *(char**) a;
    char *s2 = *(char**) b;
    printf("s1:%s\n",s1);
    printf("s2:%s\n",s2);
    return strcmp(s1,s2);
}

const char* arr_of_ptr[] =
{
  "hello",
  "world"
};

const char **p_arr_of_ptr = arr_of_ptr;

int main(void)
{
   const char *cstring1 = "LaDonna";
   const char *cstring2 = "McPherson";
   const char **pcstring1 = &cstring1;
   const char **pcstring2 = &cstring2;
   StrCmp(&arr_of_ptr[0],&arr_of_ptr[1]);
   StrCmp(pcstring1,pcstring2);
   StrCmp(p_arr_of_ptr,p_arr_of_ptr + 1);
}
于 2012-09-17T07:27:24.857 に答える
4

ほとんどの場合、その関数の呼び出し元は、次のようなポインターの配列を使用しています。

const char* arr_of_ptr[] =
{
  "hello",
  "world"
};

その場合、配列の最初の要素は char へのポインターであり、それ自体は char ではありません。したがって、StrCmp 関数は、通常の C 文字列へのポインターの配列間のトランスレーターとして機能します。

ただし、const キーワードも捨てていますが、これは悪い習慣です。関数は次のように記述します。

int StrCmp(const void *a, const void *b){
    const char *s1 = *(const char**) a;
    const char *s2 = *(const char**) b;
    return strcmp(s1,s2);
}

トピックについてよく読んでください。

于 2012-09-17T06:44:05.453 に答える