6

いつも私を混乱させていたのは、文字ポインターです。私が再びcに長居しているのは、長い4年後のことです。

前述のケースを例にとります。なぜcharポインタはこのように動作するのですか? ポインティが何も指していない場合、または char ポインタがアドレス以外のものを格納しているようなものである場合、ポインティの内容を直接アドレス指定するにはどうすればよいでしょうか。

#include <stdio.h>
#include <stdlib.h>

int main()
{ 
char* charPtr="I cant understand why";
int* intPtr=60;


printf("%d\n", intPtr); //displays 60
printf("%p\n", intPtr); // displays the hex value of 60

printf("%s\n", charPtr); // displays the wh0le string
printf("%p\n", charPtr); // displays the start address of the string
return 0;

}

次のintポインタは、どのように値 60 を受け入れ、どこに格納されますか?

char ポインターと malloc は別として、ポインターの基本的な考え方は、指すアドレスを取得することだと思いました。

なぜこれらのケースは

 *intptr = 60 ; // should be setting the pointee's value to 60
  intptr = 60 ;  // sets the address

コンパイルエラーをスローする

  int* intPtr=60;

ポインティのアドレスを取得せずに忍び込んだ(またはアドレスとして60が使用されている場合、前者の場合ではこれが受け入れられないのはなぜですか)!

ここで何かが足りないと思いますが、ちょっと!何だと思う ?SOで検索するように言われました!

編集: char ポインターが指すアドレスを int ポインターに指定しても、エラーは発生しません。

int8_t* intPtr= (int8_t*)0x80485c8 ; // works without casting too ! I guess addresses are acceptable.

それを逆参照すると、文字列の最初のものと同等の値が得られIます.これは良い習慣ですか、それともintがcharを保持できるなどのバイトビットサイズの割り当てを除外する他の説明があります..?

hmjd が指摘したように、「初期化構文」が問題です! 自分のコードを書くのは問題ありませんが、誰かのコードを変更すると問題が発生します。

4

4 に答える 4

6

ポインティが何も指していない場合、または char ポインタがアドレス以外のものを格納しているようなものである場合、ポインティの内容を直接アドレス指定するにはどうすればよいでしょうか。

混乱は初期化構文だと思います。これ:

char* charPtr="I cant understand why";

逆参照しませんcharPtr。以下と同等です。

char* charPtr;
charPtr = "I cant understand why";

どちらのコード スニペットも、文字列リテラルのアドレス"I cant understand why"charPtr. 何も起こらないことを指すポインターの逆参照はありません。ポインター変数は、任意の型で、アドレスのみを格納できます。

これ:

int* intPtr=60;

60inのアドレスを格納します。代入も参照も行われintPtrません。この時点では変数は存在しintません。intコンパイラは、この行で警告を発しているはずです。従おうとするintPtrと、ほとんどの場合、クラッシュが発生します。

于 2012-08-29T09:38:10.207 に答える
4

C では、"I can't understand why" のような文字列リテラルcharは、メモリがプログラムの存続期間にわたって利用できるように、配列として格納されます (すべてのアドレスはどこからともなく引き出され、特定のアドレスを表すことを意図したものではありません)。プラットフォームまたはアーキテクチャ):

Item        Address        0x00  0x01  0x02  0x03
-----       -------        ----  ----  ----  ----
"I..."      0x00080000      'I'   ' '   'c'   'a'
            0x00008004      'n'   '''   't'   ' '
            0x00008008      'u'   'n'   'd'   'e'
            0x0000800C      'r'   's'   't'   'a' 
            0x00008010      'n'   'd'   ' '   'w' 
            0x00008014      'h'   'y'  0x00  0x??

文字列リテラルは配列式でもあり、ほとんどのコンテキストでは、型 "N-element array of T" の式は型 "pointer to T" に変換され、その値は配列の最初の要素のアドレスになります (例外は、配列式がsizeofまたは 単項演算子のオペランドである場合、または宣言で配列&を初期化するために使用される文字列リテラルである場合です)。

だからあなたが書くとき

char* charPtr = "I can't understand why";

文字列リテラルのアドレスを次の場所にコピーしていますcharPtr

Item        Address        0x00  0x01  0x02  0x03
----        -------        ----  ----  ----  ----
charPtr     0xffbe4000     0x00  0x08  0x00  0x00

宣言がされていた場合に注意してください

char str[] = "I can't understand why";

strchar文字列を保持するのに十分な長さの配列として割り当てられ、文字列の内容がそれにコピーされます。

Item        Address        0x00  0x01  0x02  0x03
-----       -------        ----  ----  ----  ----
str         0xffbe4000      'I'   ' '   'c'   'a'
            0xffbe4004      'n'   '''   't'   ' '
            0xffbe4008      'u'   'n'   'd'   'e'
            0xffbe400C      'r'   's'   't'   'a' 
            0xffbe4010      'n'   'd'   ' '   'w' 
            0xffbe4014      'h'   'y'  0x00  0x??

あなたが書くとき

int* intPtr = 60;

ポインター値を 60 で初期化しており、値 60 の匿名整数を指すように設定していません。

Item        Address        0x00  0x01  0x02  0x03
----        -------        ----  ----  ----  ----
intPtr      0xffbe4004     0x00  0x00  0x00  0x3C

アドレス 60 は有効なアドレスではない可能性が高いため、逆参照を試みるとintPtr未定義の動作が発生する可能性が高くなります。

のようなことを書いていたでしょうか。

int x = 60;
int *intPtr = &x;

次に、次のような状況になります。

Item        Address        0x00  0x01  0x02  0x03
----        -------        ----  ----  ----  ----
x           0xffbe4004     0x00  0x00  0x00  0x3C
intPtr      0xffbe4008     0xff  0xbe  0x40  0x04

この場合、 の値intPtrは のアドレスですx

最後に、初期化代入は同じものではない ことに注意してください。

T *x = value;

逆参照せず、結果xに代入しません。に直接value割り当てます。の型は として扱われます。警告が表示されることに注意してくださいvaluexvalueT *

int *intPtr = 60;

「キャストなしで整数からポインターを作成する」の行に沿って。

于 2012-08-29T11:34:02.690 に答える
3

あなたが書くとき:

 char* charPtr = "I can't understand why";

これは、文字列「理由がわかりません」のベースアドレスが割り当てられていることを意味します

charPtr は、文字列リテラルもその文字列へのポインターであるためです。

次のように表示できます。

char 配列に格納された文字列の概念

これは、文字列全体のベースアドレスが charPtr に格納されていることを意味します。これで、コードで実行したことになります。

 char *charPtr="i cant understand why";

それに加えて、次のようなステートメントを出力する場合:

printf("%c","i cant understand why"[0]);//prints i
printf("%c","i cant understand why"[2]);//prints c

これらの 2 つの printf は、文字列「理由がわかりません」自体が、文字列が格納されている char 配列へのポインタであるという私の概念を正当化します。

于 2012-08-29T12:51:15.693 に答える
1

絶対intPtrメモリ アドレスを指すように初期化されます60。ここにはバッキング ストアはありません。

ポインター自体を逆参照していないため60、環境によってはプログラムがクラッシュする可能性があるアドレスを読み取ろうとすることはありません。

printf代わりに、引数としてほとんどすべてを取り、フォーマット文字列で指定したとおりに値を解釈するポインター値を渡します。あなたの場合、ポインター値ではなくポインターのアドレスを解釈します。アドレスが60表示されるようになっています。代わりに使用*intPtrしていたら、おそらくクラッシュしていたでしょう。

于 2012-08-29T09:38:45.127 に答える