这是一个简单的程序来解释我的意思。给定长度n,它初始化由标准输入读取的n个整数序列。
int n, *seq, *current;
scanf("%d", &n);
seq = malloc(n*sizeof(int));
for (current = seq; current - seq < n; current++)
scanf("%d", current);
我怀疑是current
的最后一个增量,它使得它指向分配的内存之外的东西。显然从该位置读取是错误的。但如果我不读那个位置呢?
该程序运行正常,但我的问题是:它是一个标准的良好实践,还是可能导致麻烦的东西,应该避免?
更新:那么将其附加到上一个程序的末尾呢?
for (current--; current - seq >= 0; current--)
printf("%d\n", *current);
根据@MOHAMED的回答,这是错误的,不是因为它是对无效位置的访问,而是因为当current - seq >= 0
指向第一个元素之前的一个位置时,current
可能会给出错误的结果,因此具有未定义的值!
答案 0 :(得分:6)
从此topic:
是的,允许指针指向刚好超过数组末尾的位置。但是,不允许您遵循这样的指针。
C99 6.5.6 / 8加法运算符(重点补充)
如果表达式P指向数组对象的最后一个元素,则为 表达式(P)+1指向数组对象的最后一个元素, 如果表达式Q指向一个数组的最后一个元素 对象,表达式(Q)-1指向数组的最后一个元素 宾语。如果指针操作数和结果都指向元素 相同的数组对象,或一个超过数组的最后一个元素 对象,评估不得产生溢出;否则, 行为未定义。如果结果指向最后一个元素 对于数组对象,它不应该用作一元*的操作数 被评估的运算符。
关于您的更新
根据这个topic:
比较current - seq >= 0
在您的情况下是未定义的行为:current - seq
在迭代后递减current
时变为未定义,当它等于{{1 }}
标准第6.5.6节第8部分对此进行了介绍:
当向指针添加或从指针中减去具有整数类型的表达式时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向偏离原始元素的元素,使得结果元素和原始数组元素的下标的差异等于整数表达式。换句话说,如果表达式
seq
指向数组对象的第i个元素,则表达式P
(等效地,(P)+N
)和N+(P)
(其中{{ 1}}具有值(P)-N
)分别指向数组对象的N
- 和n
- 元素,前提是它们存在。此外,如果表达式i+n
指向数组对象的最后一个元素,则表达式i−n
指向数组对象的最后一个元素之后,如果表达式P
指向一个数组对象的最后一个元素,表达式(P)+1
指向数组对象的最后一个元素。如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出; 否则,行为未定义。如果结果指向一个超出数组对象的最后一个元素的结果,则它不应该用作被计算的一元Q
运算符的操作数。
标准的长度覆盖了数组对象的最后一个元素之后的位置处的元素,而位于第一个元素之前的位置的元素属于上述规则的“otherwise”子句。
答案 1 :(得分:2)
如果你不再使用指针(除非你重新分配),那就没关系。
只有拥有指针不会导致未定义的行为,它是何时以及如何使用它会导致问题。所以如果你不使用它,就什么都不会发生。
答案 2 :(得分:0)
没关系,但以下内容可能更清晰,更不容易出错:
int n, *seq, counter;
scanf("%d", &n);
seq = malloc(n*sizeof(int));
for (counter = 0; counter < n; counter++)
scanf("%d", &seq[counter]);