数组、指针、C标准……

简介:

说起指针,初学C语言的时候,总是让人感觉似懂非懂。
后来,学习到了很多操作系统、计算机组成原理、体系结构的知识,逐渐深切地认识到:指针其实就是一块一个字长大小的内存单元,它上面保存着 被其指向的 另一块内存的地址。
理解了指针的实现,由于指针所引发的诸多疑难杂症也很容易就一一治愈。于是在某简历中自诩“精通C语言”……
直到有一天,在论坛到看到一些关于C标准的讨论,才发觉C语言比我所理解的要宽泛得多……

有这么个例子:
int a[10], *p;
for (p=a+9; p>=a; p--) {
printf("%d\n", *p);
}
这段代码有问题吗?

看到这个问题的时候,我的第一感觉是:这帮人太无聊了,这段代码怎么会有问题?
但是正确答案却是:有问题!
为什么呢?假设a==0会怎样?p--会溢出,于是p永远比a大,造成死循环……(或者在循环过程中程序就崩溃了。)

那么,改成这样写呢?
int a[10], *p;
for (p=a; p<=a+9; p++) {
printf("%d\n", *p);
}
这样就没问题。
为什么呢?如果p++溢出,p永远都会小于a+9,同样是死循环。那么,既然p--会溢出,p++为什么就不会?

这就要看C标准了:
c99, 6.5.6 Additive operators

When an expression that has integer type is added to or subtracted from a pointer, the
result has the type of the pointer operand. If the pointer operand points to an element of
an array object, and the array is large enough, the result points to an element offset from
the original element such that the difference of the subscripts of the resulting and original
array elements equals the integer expression. In other words, if the expression P points to
the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and
(P)-N (where N has the value n) point to, respectively, the i+n-th and i?n-th elements of
the array object, provided they exist. Moreover, if the expression P points to the last
element of an array object, the expression (P)+1 points one past the last element of the
array object, and if the expression Q points one past the last element of an array object,
the expression (Q)-1 points to the last element of the array object. 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. If the result points one past the last element of the array object, it
shall not be used as the operand of a unary * operator that is evaluated.

这条标准提到,参加加减运算的指针及其结果,只有都指向同一数组内(包括数组元素和数组之后的第一个“元素”)时,才是合法的,否则行为是未定义。
也就是说,标准规则了上面的p++是不溢出的,而p--则未定义。
尽管我到现在还觉得这条标准有些蛮横(凭什么p++不溢出,p--就是未定义呢?要么都不溢出、要么都未定义,对称一点多好!),但是我还是很认同标准中诸如此类的许多概念与表述。

在此之前,我总是对一些网友“啃标准”的行为不以为然,何苦让那些概念与规则把自己绕晕,看看实现,一切都一目了解。但是现在我觉得研究标准也还是很有意义的。

C标准描述的是一个抽象的语言逻辑,而现在我们使用的C语言则是在特定计算机条件下的C语言实现。
如果将来计算机环境发生重大变革,C语言还是C语言,但是C语言的实现则可能大相径庭了。比如(假想一下)内存可能不再是一维的了,于是指向内存的指针也需要保存x、y、z这样的多维信息。等等。
理论上说,不管计算机怎么变革,标准的C语言程序都能无缝的移植。当然,现在不利用到操作系统特性(比如多进程、进程间通信、等等等等)并且又很有价值的程序实在太少了,无缝移植我觉得只是个传说。
但是研究研究标准,对深刻理解语言本身还是很有益处的。


目录
相关文章
|
1月前
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
33 3
|
1月前
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
38 2
|
1月前
|
算法 索引
单链表题+数组题(快慢指针和左右指针)
单链表题+数组题(快慢指针和左右指针)
37 1
|
2月前
|
存储
如何使用指针数组来实现动态二维数组
指针数组可以用来实现动态二维数组。首先,定义一个指向指针的指针变量,并使用 `malloc` 为它分配内存,然后为每个子数组分配内存。通过这种方式,可以灵活地创建和管理不同大小的二维数组。
|
2月前
|
存储
如何通过指针数组来实现二维数组?
介绍了二维数组和指针数组的概念及其区别,详细讲解了如何使用指针数组模拟二维数组,包括定义与分配内存、访问和赋值元素、以及正确释放内存的步骤,适用于需要动态处理二维数据的场景。
|
2月前
|
存储 算法 C语言
C语言:什么是指针数组,它有什么用
指针数组是C语言中一种特殊的数据结构,每个元素都是一个指针。它用于存储多个内存地址,方便对多个变量或数组进行操作,常用于字符串处理、动态内存分配等场景。
|
2月前
魔法指针 之 二级指针 指针数组
魔法指针 之 二级指针 指针数组
20 1
|
2月前
|
存储
一篇文章了解区分指针数组,数组指针,函数指针,链表。
一篇文章了解区分指针数组,数组指针,函数指针,链表。
20 0
|
2月前
|
编译器 C语言
【C语言】指针篇-深入探索数组名和指针数组- 必读指南(2/5)
【C语言】指针篇-深入探索数组名和指针数组- 必读指南(2/5)
|
4月前
|
搜索推荐 C语言
指针与数组
指针与数组
59 9