3

ポインターに 1 を追加すると、実際に追加される値は、ポインターが指す型のサイズになりますか? 例えば:

int* num[5];
cout << *num << ", " << *(num + 2) << endl; 

これにより、num[1] と num[2] に格納されている値が出力されるため、間違っていなければ num + 2 は実際には num + 2*sizeof(int) になります。

ここで、char へのポインターの配列を文字列リテラルに初期化すると、次のようになります。

char* ch[5] = 
{
     "Hi",
     "There",
     "I,m a string literal"
};

これが可能なのは、"hi" のような文字列リテラルが最初の文字 (この場合は 'h') のアドレスを表すためです。今私の質問は、次のようなものをどのように書くことができるかです:

cout << *(ch + 2);

出力として「I、ma文字列リテラル」を取得しますか?ポインターは char を指しているので、実際にはポインターに 2 を追加するのは (ch + 2*sizeof(char)) ではないでしょうか? 「そこに」という出力が得られますか?

クーと関係あるの?cout は、ポイントされた値のメモリを検索して、ポイントされた値の内容を文字列として認識し、ポインター演算を変更する '\0' を見つけるかどうかを確認しますか? ただし、文字列を指す char へのポインターに 1 を追加すると、文字列は任意のサイズになる可能性があるため、毎回 (char のサイズではなく) 異なるバイト数を追加することになります。それとも私は完全に間違っていますか?申し訳ありませんが、私は C++ の初心者であり、一般的なプログラミングを行っています。

4

4 に答える 4

4

配列はs を格納charしているのではなく、s を格納していchar *ます。したがって、言うch + 2ことは と同等になりch + 2*sizeof(char *)ます。次に、 を指しているそれを逆参照し"I'm a string literal"ます。

あなたの最初の例は混乱を示しています:

int* num[5];
cout << *num << ", " << *(num + 2) << endl; 

これは int へのポインターの配列です。したがって、ではなく*(num + 2)になります。小さなプログラムでこれを示しましょう。*(num + 2*sizeof(int *)) 2*sizeof(int)

#include <iostream>

int main()
{
    int *num[3];
    int x, y, z;
    x = 1;
    y = 2;
    z = 3;

    num[0] = &x;
    num[1] = &y;
    num[2] = &z;

    std::cout << *(num + 2) << "\n";
}

0x22ff28これは、値ではなくポインタを保持しているため、メモリアドレス(のような)を出力します。

C と C++ では、配列とポインターは非常によく似ています (多くの本では、それらはまったく同じであると主張されています。これは完全に真実ではありませんが、多くの状況で真実です)。

最初の例はint num[5]. 次に、*(num + 2)(これは と同等ですnum[2]) は と同等になり*(num + 2*sizeof(int)ます。うまくいけば、これで混乱がいくらか解消されます。

于 2013-06-07T02:00:22.377 に答える
2

「ポインターに 1 を追加すると、実際に追加される値は、ポインターが指す型のサイズになりますか?」

C++ 標準では、ポインターがポインターが指すメモリのバイト数であるという保証はありません。ポインターに整数を追加すると、結果はその配列の次の要素nへのポインターになります。n

int iarr[10];
int* pi = iarr;  // pi points to iarr[0]
int* pi2 = pi+2; // pi2 points to iarr[2]

たとえばint repr = (int)pi;、C++ 標準では定義されていません。

最も人気のあるプラットフォーム/実装で何が起こるかというと、

(int)pi2 == ((int)pi) + 2*sizeof(int)

ポインターの配列がある場合、まったく同じことが起こります。

int* piarr[10];
int** ppi = piarr;     // ppi points to iarr[0]
int** ppi2 = piarr+2;  // ppi2 points to iarr[2]

piarrの型はint への 10 ポインターの配列であるため、その配列の要素はint への型ポインターを持つことに注意してください。したがって、その配列の要素へのポインターは、 int へのポインター のポインター型になります。


char* ch[5]への 5 つのポインタcharの配列です。

"Hello"などは (狭い) 文字列リテラルです。(狭い) 文字列リテラルはn const の配列ですchar。ここで、nは文字列の長さに 1 (終端\0文字) を加えたものです。配列は、配列の最初の要素へのポインターに暗黙的に変換できます。これがここで行われます。

char* ch[5] = 
{
     "Hi",
     "There",
     "I,m a string literal"
};

配列には、 char へchの3 つのポインターが含まれています。これらは配列をポインターに変換することによって取得されているため、それぞれがchar の配列の最初の要素を指しています。ポインター(配列の最初の要素) は、配列 "Hi" の最初の要素を指し、 「そこ」の最初の要素など。ch[0]chch[1]

const charからへの変換も含まれていることに注意してくださいchar。これは非推奨であり、避ける必要があります。より良い形式は次のとおりです。

char const* ch[5] = 
{
     "Hi",
     "There",
     "I,m a string literal"
};

この式*(ch + 2)は次のように解釈されます。

  • chその配列の名前 (上記参照)
  • ch + 2は、配列の最初の要素を指すポインターであるcharへのポインターへの 3 つのポインターの配列chから、char へのポインターへのポインターへの暗黙的な変換を行います。したがって、この式の型は、char へのポインターへのポインターです。ch
  • ch + 2最後のステップからのポインターが 2 番目の次の要素を指すようにします。の最初の要素を指していたchので、今は配列の 3 番目の要素を指していchます。
  • *(ch + 2)最後に、*ポインターを逆参照し、指しているオブジェクトを「フェッチ」します。によって作成されたポインタch + 2は、配列 の 3 番目の要素を指すchため、この式は配列 の 3 番目の要素に解決されchます。式の型はchar へのポインターになりました

式の結果は に渡されstd::cout::operator<<ます。式の型はcharへのポインタcoutであるため、その文字列を出力します: array の 3 番目の要素ですch

于 2013-06-07T02:25:29.513 に答える
1

C では、文字は datatype で表されcharます。任意の ASCII 文字を保持でき、範囲は 0 ~ 255 です。さらに、1 バイトのサイズを使用します。

ただし、文字列は で表されchar*、技術的にはchars の配列です。違いがあります。Acharは a と同じではありませんchar*。前者は単一の文字を格納し、後者は文字列のオフセットに対応するメモリ方向を格納します。

さて、あなたの例でchは、ではchar*なく、char**です。これは、chars の配列の配列、または文字列の配列です。chのように 1 回逆参照*chすると、最初の文字列が取得されますHi。のように 2 回逆参照すると**ch、最初の文字列の最初の文字が取得されますH。これで、ポインター演算を開始できます。

cout << *(ch + 2)出力しますI,m a string literal

cout << **(ch + 1)出力しますT(2番目の文字列の最初の文字)

cout << *(*ch + 1)出力しますi(最初の文字列の2番目の文字)

文字と文字列がどのように出力されるかをよりよく理解するために、これらの例に取り組み続けてください! ポインター演算がすべてです。

于 2013-06-07T02:19:35.210 に答える