55

ポインターで何かを理解しようとしていたので、次のコードを書きました。

#include <stdio.h>

int main(void)
{
    char s[] = "asd";
    char **p = &s;

    printf("The value of s is: %p\n", s);
    printf("The direction of s is: %p\n", &s);

    printf("The value of p is: %p\n", p);
    printf("The direction of p is: %p\n", &p);

    printf("The direction of s[0] is: %p\n", &s[0]);
    printf("The direction of s[1] is: %p\n", &s[1]);
    printf("The direction of s[2] is: %p\n", &s[2]);

    return 0;
}

gcc でコンパイルすると、次の警告が表示されます。

$ gcc main.c -o main-bin -ansi -pedantic -Wall -lm
main.c: In function ‘main’:
main.c:6: warning: initialization from incompatible pointer type
main.c:9: warning: format ‘%p’ expects type ‘void *’, but argument 2 has type ‘char (*)[4]’
main.c:11: warning: format ‘%p’ expects type ‘void *’, but argument 2 has type ‘char **’
main.c:12: warning: format ‘%p’ expects type ‘void *’, but argument 2 has type ‘char ***’

(gcc のフラグは、私が C89 でなければならないためです)

ポインターの型に互換性がないのはなぜですか? 配列の名前は最初の要素へのポインタではありませんか? s が 'a' へのポインターである場合は、 a である&s必要がありますchar **。いいえ? また、他の警告が表示されるのはなぜですか? ポインターを出力するには、ポインターを ( ) でキャストする必要がありvoid *ますか?

そして実行すると、次のようなものが得られます。

$ ./main-bin
The value of s is: 0xbfb7c860
The direction of s is: 0xbfb7c860
The value of p is: 0xbfb7c860
The direction of p is: 0xbfb7c85c
The direction of s[0] is: 0xbfb7c860
The direction of s[1] is: 0xbfb7c861
The direction of s[2] is: 0xbfb7c862

s の値とその方向 (そしてもちろん の値p) が同じになるにはどうすればよいでしょうか?

4

8 に答える 8

36

「s」は「char*」ではなく、「char[4]」です。したがって、「&s」は「char **」ではなく、実際には「4文字の配列へのポインタ」です。コンパイラは、「&s」を「&s [0]」と書いたかのように扱う場合があります。これはほぼ同じですが、「char*」です。

「char**p =&s;」と書くと 「現在「asd」を指しているもののアドレスにpを設定したいのですが、現在「asd」を指しているものはありません。「asd」を保持する配列だけがあります。

char s[] = "asd";
char *p = &s[0];  // alternately you could use the shorthand char*p = s;
char **pp = &p;
于 2008-10-13T14:44:10.723 に答える
21

はい、あなたのコンパイラは void * を期待しています。それらを void * にキャストするだけです。

/* for instance... */
printf("The value of s is: %p\n", (void *) s);
printf("The direction of s is: %p\n", (void *) &s);
于 2008-10-13T14:31:38.973 に答える
4

配列の名前を引数として関数に渡すと、配列のアドレスを渡したかのように扱われます。したがって、&sとsは同じ引数です。K&R5.3を参照してください。&s [0]は、配列の最初の要素のアドレスを取得するため、&sと同じです。これは、配列自体のアドレスを取得するのと同じです。

他のすべての場合、すべてのポインタは基本的にメモリ位置ですが、それらはまだ型指定されており、コンパイラはあるタイプのポインタを別のタイプに割り当てることについて警告します。

  • void* p;pはメモリアドレスだと言いますが、メモリに何が入っているのかわかりません
  • char* s;sはメモリアドレスであり、最初のバイトには文字が含まれていると言います
  • char** ps;psはメモリアドレスであり、そこにある4バイト(32ビットシステムの場合)にはchar*型のポインタが含まれていると言います。

cf http://www.oberon2005.ru/paper/kr_c.pdf(K&Rの電子書籍版)

于 2008-10-13T14:37:57.507 に答える
3

これは文字へのポインタではなく、char*4文字の配列へのポインタです char* [4]。g ++では、コンパイルされません。

main.cpp:関数内'int main(int、char **)':main.cpp:126:エラー:初期化時に'char(*)[4]'を'char**'に変換できません

さらに、linuxのマニュアルページに次のように書かれています。

p

void *ポインタ引数は16進数で出力されます(%#xまたは%#lxのように)。それはvoidへのポインタである必要があります。

コードを次のように変更できます。

char* s = "asd";
char** p = &s;

printf("The value of s is: %p\n", s);
printf("The address of s is: %p\n", &s);

printf("The value of p is: %p\n", p);
printf("The address of p is: %p\n", &p);

printf("The address of s[0] is: %p\n", &s[0]);
printf("The address of s[1] is: %p\n", &s[1]);
printf("The address of s[2] is: %p\n", &s[2]);

結果:

sの値は次のとおりです:0x403f00

sのアドレスは次のとおりです:0x7fff2df9d588

pの値は次のとおりです:0x7fff2df9d588

pのアドレスは次のとおりです:0x7fff2df9d580

s [0]のアドレスは次のとおりです:0x403f00

s [1]のアドレスは次のとおりです:0x403f01

s [2]のアドレスは次のとおりです:0x403f02

于 2013-03-15T01:42:51.760 に答える
1

静的配列の値(つまり、アドレス)を変更することはできません。技術用語では、配列の左辺値はその最初の要素のアドレスです。したがってs == &s。それはただの言語の癖です。

于 2008-10-13T14:38:15.980 に答える
1

行を変更:

char s[] = "asd";

に:

char *s = "asd";

そして物事はより明確になります

于 2008-10-13T14:34:39.887 に答える
1

通常、ポインターを不必要に (void*) にキャストするのはスタイルが悪いと考えられています。ただし、ここでは、printf が可変長であるため、printf 引数で (void*) へのキャストが必要です。プロトタイプは、呼び出しサイトでポインターを変換する型をコンパイラーに通知しません。

于 2008-10-13T17:20:20.160 に答える
0

以下を使用しました:

char s[] = "asd";

ここで s は、実際にはバイト "asd" を指しています。s のアドレスもこの場所を指します。

使用した場合:

char *s = "asd";

s は実際にはバイト "asd" へのポインターであるため、s と &s の値は異なります。

使いました:

char s[] = "asd";
char **p = &s;

ここで s はバイト "asd" を指します。p は文字へのポインタへのポインタで、文字のアドレスに設定されています。言い換えれば、p には間接的な要素が多すぎます。char *s = "asd" を使用した場合は、この追加の間接化を使用できます。

于 2008-10-13T14:28:28.587 に答える