8.1 一维数组
8.1.1 数组名
int a;
int b[10];
a是标量,b为数组。
在C中几乎所有的数组名的表达式中,数组名的值是一个指针常量,也就是数组第一个元素的地址。
不过也不要根据这个得出数组和指针是相同的结论。数组具有一些何指针完全不同的特征。例如,数组具有确定数量的元素,而指针只是一个标量。编译器用数组名来记住这些属性。只有当数组名在表达式中使用时,编译器才会为他产生一个指针常量。
注意,这个值是指针常量而不是指针变量。你不能修改常量的值。
只有在两种情况下,数组名并不用指针常量来表示—-就是当数组名作为sizeof操作符或单目操作符&的操作数时;
c = &a[0];
c = a;
这两条语句所执行的任务是完全一样的。
int a[10];
int b[10];
b = a ;
这样赋值是非法的,你不能使用赋值符把一个数组的所有元素复制到另一个数组。你必须使用一个循环依次赋值。
int a[10];
int *c;
a =c;
这也是非法的,因为a的值是一个常量,不能被修改。
8.1.2 下标引用
array[subscript]
*( array + ( subscript))
8.1.3 指针与下标
指针表达式和下表表达式可以互换使用。
假定这两种方法都正确,下标绝不会比指针更有效率,但指针有时会比下标更有效率
8.1.4 指针的效率
指针比下标更有效率,前提是它们被正确地使用。
在开始例子之前首先要注意,不要为了效率上的细微差别而牺牲可读性。
#define SIZE 50
int x[size];
int y[size];
int i;
int *p1,*p2;
这是函数的下标版本
void try1()
{
for (i = 0; i< SIZE; i++)
x[i] = y[i];
}
一、改用指针方案
void try2()
{
for(p1 = x,p2 = y;p1 - x < SIZE ; *p1++ = *p2++);
}
这与第一个版本相比并没有多大改进。
二、重新使用计数器
void try3()
{
for(i = 0,p1 = x,p2 = y;i < SIZE;i++)
*p1++ = *p2++;
}
重新使用了计数器,用于控制循环何时退出,这样可以去除指针减法,并因此缩短目标代码的长度。
三、消除计数器
void tyr4()
{
register int *p1, *p2;
for(p1 = x,p2 = y;p1 < &x[SIZE];)
*p1++ = *p2++;
}
这个版本代码非常紧凑,速度也很快。
总结:
1. 当你根据某个固定数目的增量在一个数组中移动时,使用指针变量的效率会更高一点。
2. 声明寄存器变量的指针通常比位于静态内存和堆栈中的指针效率更高。
3. 如果你可以通过测试一些已经初始化并经过调整的内容来判断循环是否应该终止,那么你就不需要使用一些单独的计数器。
4. 那些必须在运行时求值的表达式较之诸如&array[SIZE]或array+SIZE这样的常量表达式往往代价更高。