15

以下は、行 4 および/または 5 で未定義の動作を引き起こしますか?

#include <stdio.h>
int main(void)
{
  char s[] = "foo";
  char * p = s - 1;      /* line 4 */
  printf("%s\n", p + 1); /* line 5 */
  return 0;
}
4

3 に答える 3

16

配列境界外でのポインタのデクリメントは未定義です。

C99 標準項目 6.5.6 パラグラフ 8 は、一部、次のように述べています。

整数型の式をポインターに加算またはポインターから減算すると、結果はポインター オペランドの型になります。... ポインターオペランドと結果の両方が同じ配列オブジェクトの要素を指している場合、または配列オブジェクトの最後の要素の 1 つ後ろを指している場合、評価はオーバーフローを生成しません。それ以外の場合、動作は未定義です。

したがって、4行目は未定義の動作を呼び出しています.

于 2013-08-12T12:35:29.063 に答える
11

はい、4行目は未定義の動作です!

C99 6.5.6 加法演算子、セクション 8

整数型の式をポインターに加算またはポインターから減算すると、結果はポインター オペランドの型になります。ポインターオペランドが配列オブジェクトの要素を指し、配列が十分に大きい場合、結果は元の要素からオフセットされた要素を指し、結果と元の配列要素の添字の差が整数式と等しくなります。つまり、式 Pi-thが配列オブジェクトの要素を指している場合、式(P) + N(同等に、N + (P)) と(P) - N(where Nhas the value ) は、配列オブジェクトの要素が存在する場合、それぞれとnを指します。さらに、式が配列オブジェクトの最後の要素を指している場合、式はi+n-thi−n-thP(P) + 1Q配列オブジェクトの最後の要素の 1 つ後ろを指し、式が配列オブジェクトの最後の要素の 1 つ後ろを指す場合、式は配列オブジェクト(Q) - 1の最後の要素を指します。ポインターオペランドと結果の両方が同じ配列オブジェクトの要素を指している場合、または配列オブジェクトの最後の要素の 1 つ後ろを指している場合、評価はオーバーフローを生成しません。それ以外の場合、動作は未定義です。結果が配列オブジェクトの最後の要素の 1 つ後ろを指している場合、評価される単項演算子のオペランドとして使用されません*

于 2013-08-12T12:35:09.363 に答える
8

以下は、行 4 および/または 5 で未定義の動作を引き起こしますか?

はい、ポインターが配列の境界内または配列の境界を超えた場所を指していないため、4行目は未定義の動作です。配列境界を超えて 1 つを指すことは有効ですが、その要素を逆参照することはできません。

c99 ドラフト標準の関連セクションは、Additive 6.5.6 operator パラグラフ 8です。

整数型の式をポインターに加算またはポインターから減算すると、結果はポインター オペランドの型になります。[...] ポインター オペランドと結果の両方が同じ配列オブジェクトの要素を指している場合、または配列オブジェクトの最後の要素の 1 つ後ろを指している場合、評価はオーバーフローを生成しません。それ以外の場合、動作は undefinedです。

段落の終わりには、最後の要素の 1 つ後ろを参照してはならないことが示されています。

[...]結果が配列オブジェクトの最後の要素の1つ後ろを指している場合、評価される単項*演算子のオペランドとして使用されません

于 2013-08-12T12:33:51.820 に答える