K&R(Cプログラミング言語第2版)の第5章では、以下を読みました。
最初に、特定の状況下でポインターを比較できます。
p
とq
が同じ配列のメンバーを指す場合、==
、!=
、<
、>=
などの関係。 正しく機能します。
これは、同じ配列を指すポインターのみを比較できることを意味するようです。
しかし、私がこのコードを試したとき
char t = 't';
char *pt = &t;
char x = 'x';
char *px = &x;
printf("%d\n", pt > px);
1
が画面に出力されます。
最初に、pt
とpx
が同じ配列を指していないため(少なくとも私の理解では)、未定義になるか、タイプやエラーが発生すると思いました。
また、pt > px
も同じです。これは、両方のポインタがスタックに格納されている変数を指しているため、スタックが大きくなり、t
のメモリアドレスがx
のメモリアドレスより大きいためです。 pt > px
が正しい理由はどれですか?
Mallocが導入されると、さらに混乱します。また、8.7章のK&Rには、次のように書かれています。
ただし、
sbrk
によって返されるさまざまなブロックへのポインターを有意義に比較できるという前提はまだ1つあります。これは、配列内でのみポインタ比較を許可する標準では保証されていません。したがって、このバージョンのmalloc
は、一般的なポインター比較が意味のあるマシン間でのみ移植可能です。
ヒープにmallocされた領域を指すポインターとスタック変数を指すポインターを比較しても問題はありませんでした。
たとえば、次のコードは正常に機能し、1
が出力されました。
char t = 't';
char *pt = &t;
char *px = malloc(10);
strcpy(px, pt);
printf("%d\n", pt > px);
私のコンパイラーでの実験に基づいて、ポインターが個別にどこを指しているかに関係なく、ポインターは他のポインターと比較できると考えられています。さらに、2つのポインター間のポインター演算は、ポインターが格納するメモリアドレスを使用しているだけなので、ポインターが個別にどこを指していても問題ないと思います。
それでも、K&Rで何を読んでいるのか混乱しています。
私が尋ねている理由は私の教授だからです。実際に試験問題にしました。彼は次のコードを与えました:
struct A { char *p0; char *p1; }; int main(int argc, char **argv) { char a = 0; char *b = "W"; char c[] = [ 'L', 'O', 'L', 0 ]; struct A p[3]; p[0].p0 = &a; p[1].p0 = b; p[2].p0 = c; for(int i = 0; i < 3; i++) { p[i].p1 = malloc(10); strcpy(p[i].p1, p[i].p0); } }
これらは何を評価しますか:
p[0].p0 < p[0].p1
p[1].p0 < p[1].p1
p[2].p0 < p[2].p1
答えは0
、1
、0
です。
(私の教授は、質問がUbuntu Linux 16.04、64ビットバージョンのプログラミング環境に関するものであるという免責事項を試験に含めています)
(編集者のメモ:SOより多くのタグが許可されている場合、その最後の部分は x86-64 、 linux 、そして多分 アセンブリ 。質問/クラスのポイントが移植可能なCではなく、具体的には低レベルのOS実装の詳細だった場合。)
それは簡単です。オブジェクトのメモリ位置が宣言したのと同じ順序になるとは限らないため、ポインタを比較しても意味がありません。例外は配列です。 &array [0]は&array [1]よりも小さいです。それがK&Rが指摘していることです。実際には、構造体のメンバーのアドレスも、私の経験で宣言した順序になっています。保証はありません...もう1つの例外は、ポインタを等しいかどうか比較する場合です。あるポインターが別のポインターと等しい場合、同じオブジェクトを指していることがわかります。それが何であれ。あなたが私に尋ねる場合、悪い試験問題。 Ubuntu Linux 16.04、試験問題の64ビットバージョンのプログラミング環境によって異なりますか?本当に ?