質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

4回答

777閲覧

ポインタのforループ

anndonut

総合スコア667

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/07/20 00:41

配列の初期化などでポインタのforループを書くことがあります。アセンブリ言語に明るい人間ならばこのように書きたがると思いますが、C/C++言語においてこの動作は未定義となりますでしょうか。主に配列の要素以外の部分をポインタが指すときの比較演算が保証されているか、という質問内容になります。よろしくお願いします。

C

1#include <stdio.h> 2 3int main() { 4 int a[5]; 5 int *pe = a + 5; 6 for (int *p = a; p < pe; ++p) *p = 0; 7 for (int *p = pe - 1; p >= a; --p) printf("%d\n", *p); 8 return 0; 9}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

p が a[0] の一つ前を指すようになり、その値を a と比較しているので
未定義動作です。
ポインタが配列の要素を指すとき、その値は配列の要素のアドレスと、
最後の要素の次のアドレスだけが許されています。

例えば、セグメントレジスタとオフセットでデータをアクセスする CPU で
ポインタがオフセット値だけを持つ場合、配列 a がオフセット 0 から
割り付けられていたとすれば、a[0] のアドレスが 0x0000 でその前が
0xffff となり、p <= a が成立しなくなります。

通常の処理系では問題ありませんが、次のように書くと規格上の問題も解決します。

C

1 for (int *p = pe; p > a; ) printf("%d\n", *--p);

投稿2020/07/20 02:22

kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2020/07/20 02:26

そっちもはみ出していたか…
anndonut

2020/07/20 11:51 編集

kazuma-sさん、ご回答ありがとうございます。規格上矛盾のないコード例も非常に参考になりました。ちなみに > セグメントレジスタとオフセットでデータをアクセスする CPU でポインタがオフセット値だけを持つ場合 は正直わかりませんでしたw
dodox86

2020/07/20 16:37

>> セグメントレジスタとオフセットでデータをアクセスする CPU でポインタがオフセット値だけを持つ場合 > > は正直わかりませんでしたw むしろ昔のx86/16ビットWindows用CコンパイラのFARポインタ、NEARポインタがそれに相当するかもですね。今のC言語仕様が適用されてはいなかったかもしれないと言うのと、ポインタの操作において内部で特殊な操作がされていたので、ポインタ演算では状況は違ったかもですが。
guest

0

もちろん逆参照はできませんが、「配列の末尾の次」を指すポインタは、存在・演算が可能なことは保証されています。

式Pが配列オブジェクトの要素を指しており,式Qが同じ配列オブジェクトの最後の要素を指している場合,ポインタ式Q+1(引用者注:この演算が可能なことも別途保証されています)は,Pと比較してより大きいとする。

投稿2020/07/20 00:53

maisumakun

総合スコア146018

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

anndonut

2020/07/20 11:30

maisumakunさん、ご回答ありがとうございます。
guest

0

kazuma-sさんの回答の通りであるため、Cに関しての補足の参考文献のみあげておきます。

Pointer arithmetic | Arithmetic operators - cppreference.com
ポインタ算術 | 算術演算子 - cppreference.com

元のポインタと結果のポインタがどちらも同じ配列の要素または同じ配列の最後の要素の次を指す場合にのみ動作は定義されます。 p が配列の最初の要素を指すとき p-1 は未定義動作でありプラットフォームによっては失敗するかもしれないことに注意してください。

6.5.6 Additive operators | n1570(C11最終ドラフト) P.93

8 (前略)
If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.
(後略)

投稿2020/07/20 10:12

raccy

総合スコア21739

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

anndonut

2020/07/20 11:28

raccyさん、参考文献のご提示ありがとうございます、非常に助かります。
guest

0

ポインタの比較自体は大丈夫ですね
アクセスを伴うとヤバいでしょうけど

#環境によりポインタのオーバーフローは考慮の必要はありそうですが。

投稿2020/07/20 00:51

編集2020/07/20 00:53
y_waiwai

総合スコア88042

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問