3

ポインタ値を増減するときにポインタアドレスがどのように変更されるかを確認したい。

私のコードは次のとおりです。

void pointers_plus_minus()
{
    char *c = (char *) 0x7fff80ccd35c;
    int *i = (int *) 0x7fff80ccd35c;

    c++;
    i++;

    cout << "char pointer" << c << endl;
    cout << "int pointer" << i << endl;
}

しかし、このコードは私に与えますSegmentation fault (core dumped)

アドレスに何か問題があることは理解していますが、何が原因かは不明です。修正方法は?私は64ビットのUbuntuを使用しています。

4

3 に答える 3

9

整数のようにポインターを操作することはできません (よく定義されたコンテキストの外ではありません)。

ポインタが所有する配列内を指している場合にc++のみ許可されます。i++

おっと、これは実際には明確に定義されていると思います。なぜなら、1 つの要素が 1 の配列として扱われ、配列の末尾を 1 つの要素で超えることができるからです。ただし、そのポインターからの読み取りはまだ定義されていません。

とにかく、未定義ですが、クラッシュはおそらくcout << cポインターではなく文字列を出力しようとするためです。にキャストしvoid*ます:

cout << "char pointer" << static_cast<void*>(c) << endl;

これはあなたの好奇心を満足させますが、それは良いことですが、まだ定義されておらず、実行すべきではありません。

于 2013-05-30T18:31:55.190 に答える
5

定数アドレスをポインターに割り当てる方法を尋ねましたが、(a) ひどく移植性がなく、(b) ポインターをインクリメントする効果を確認するという目的に必ずしも役立つとは限りません。

これは、未定義の動作が原因で爆発する可能性がなく、好奇心を満足させるプログラムです。

#include <iostream>
int main() {
    const int len = 10;
    char char_array[len];
    int int_array[len];

    char *cp = char_array;
    for (int i = 0; i <= len; i ++) {
        std::cout << "cp = " << static_cast<void*>(cp) << "\n";
        cp ++;
    }

    std::cout << '\n';

    int *ip = int_array;
    for (int i = 0; i <= len; i ++) {
        std::cout << "ip = " << static_cast<void*>(ip) << "\n";
        ip ++;
    }
}

私の(64ビット)システムでの出力は次のとおりです。

cp = 0x7fffaa5ddc30
cp = 0x7fffaa5ddc31
cp = 0x7fffaa5ddc32
cp = 0x7fffaa5ddc33
cp = 0x7fffaa5ddc34
cp = 0x7fffaa5ddc35
cp = 0x7fffaa5ddc36
cp = 0x7fffaa5ddc37
cp = 0x7fffaa5ddc38
cp = 0x7fffaa5ddc39
cp = 0x7fffaa5ddc3a

ip = 0x7fffaa5ddc00
ip = 0x7fffaa5ddc04
ip = 0x7fffaa5ddc08
ip = 0x7fffaa5ddc0c
ip = 0x7fffaa5ddc10
ip = 0x7fffaa5ddc14
ip = 0x7fffaa5ddc18
ip = 0x7fffaa5ddc1c
ip = 0x7fffaa5ddc20
ip = 0x7fffaa5ddc24
ip = 0x7fffaa5ddc28

これに関する注意事項:

各ポインターは常に適切な型の配列の要素、またはその末尾のすぐ後ろを指すため、ポインターのインクリメントは有効です。(配列の末尾のすぐ後ろにポインターを作成することは許可されていますが、そのようなポインターを逆参照することは許可されていません。)

タイプのポインターを印刷するときに生成される出力void*は、実装定義です。私のシステムでは、ポインター値の 16 進数表現であり、整数であるかのように解釈されます。これはおそらく最も一般的な方法です。

char*ポインターが毎回 1 ずつインクリメントされ、ポインターが 4 ずつインクリメントされているように見えることがわかりますint*。私のシステム (およびおそらくあなたのシステム) では、ポインターはバイト アドレスとして格納されます。ポインター演算は、バイト単位ではなく、ポイント先の型の単位で定義されます。ポインタをインクリメントすると、以前の位置からバイト後のint*メモリ位置sizeof (int)(この場合は 4 バイト) を指すようになります。すべてのポインター演算はこのように定義されます。ptr2 - ptr12つのアドレス間の要素の数(タイプptr1ptr2ポイントに関係なく)を示します。

表示された特定の値は、システムでメモリ アドレスがどのように管理されているかを示しています。ポインターと整数の間のマッピングは、通常、システムのメモリ モデルを反映します。そのモデルは、主に実装固有です。

于 2013-05-30T18:39:48.447 に答える
-2

スタック オーバーフローの次に好きなエラー メッセージであるセグ フォールトは、不正なメモリ空間に書き込もうとしたときに発生します。そうは言っても、プログラムがメモリにロードされたときに、スタック/ヒープ領域が予約しようとしている領域内にあることをどのように保証できますか? ハードウェアへのアクセスがはるかに少ないため、これはおそらくAssemblyで実行できることですが、Cで実行できる(または実行できる場合は実行する必要がある)ことを真剣に疑っています.

于 2013-05-30T18:37:47.873 に答える