# 指针和数组
计算机的硬件指令很大程度上要依赖于地址,所以指针是你能够类似于计算机底层的表达方式来表达自己的意愿;这使得使用指针的程序有着更高的运行效率。特别地,指针能够更有效地处理数组,数组标记实际上是一种变相使用指针的方式。
数组名同时也是该数组首元素的地址。
```
flizny = &flizny[0] //数组名是该数组元素的首地址
```
flizny和&flizny[0]都代表首元素的内存地址(&是地址运算符),两者都是常量,因为在程序运行的过程中它们保持不变。然而可以把他们作为赋给指针变量的值,然后你可以修改指针变量的值,如下面程序所示
```
//pnt_add.c //指针加法
#include
#define SIZE 4
int main(void)
{
short dates [SIZE];
short * pti;
short index;
double bills[SIZE];
double * ptf;
pti = dates; //把数组地址赋给指针;
ptf = bills;
printf("%23s %10s\n", "short", "double");
for(index = 0; index < SIZE; index++)
{
printf("pointers + %d: %10p %10p\n", index, pti+index, ptf+index);
}
return 0;
}
```
运行后,我的计算机上输出以下结果
```
short double
pointers + 0: 0061FF0C 0061FEE8
pointers + 1: 0061FF0E 0061FEF0
pointers + 2: 0061FF10 0061FEF8
pointers + 3: 0061FF12 0061FF00
```
可以看出,在short为2个字节,double为8个字节。在C中,对一个指针加1的结果是对该指针增加一个存储单元。对数组而言,地址会增加到下一个元素的地址,而不是下一个字节。所以在声明指针是必须声明它所指向的类型,不然计算机无法得知存储对象所用的字节数。
---------------------------------------------------------------------------------
* 指针的数值就是他所指向的对象的地址。
* 在指针前使用运算符*就可以得到该指针所指向的对象的数值。
*对指针加1,等价于对指针的值加上它所指向的对象的字节大小。
```
dates + 2 == &dates[2] //相同的地址
*(dates + 2) == dates[2] //相同的值
*dates + 2 //第一个元素的值和2相加;间接运算符*优先级高于+,因此等价于(*dates)+2
```
这些关系总结了数组和指针间的密切关系:可以用指针标识数组的每个元素,并得到每个元素的数值。从本质上说,对同一个对象有两种不同的符号表示方法。C语言标准在描述数组是,也借助了指针的概念,例如,定义ar[n]时,意识是*(ar+n),即寻址到ar,然后移动n个单位,再取出数值。
----------------------------------------------------------------------------------
```
#include
#define MONTHS 12
int main(void)
{
int days[MONTHS] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int index;
for(index = 0; index < MONTHS; index++)
{
printf("Month %2d has %d days.\n", index + 1, *(days + index));
//*(days + index)与days[index]相同
}
return 0;
}
```
运行程序的结果:
```
Month 1 has 31 days.
Month 2 has 28 days.
Month 3 has 31 days.
Month 4 has 30 days.
Month 5 has 31 days.
Month 6 has 30 days.
Month 7 has 31 days.
Month 8 has 31 days.
Month 9 has 30 days.
Month 10 has 31 days.
Month 11 has 30 days.
Month 12 has 31 days.
```
上面的程序展示了*(days + index)与days[index]等价,days是数组首元素的地址,days+index是元素days[index]的地址,*(days + index)是这个元素的值,与days[index]等价。
-------------
-------------
-------------
# 函数、数组和指针
假定一个返回数组中所有元素的和的函数:
```
int sun(int *ar, int n)
{
int i;
int toatl = 0;
for( i = 0; i < n; i++)
{
total += ar[i];
}
return total;
}
```
第一个参数把数组地址和数组类型的信息传递给函数,第二个参数把数组中的元素个数传递给函数。
在函数原型或函数定义头的场合中(并且也只有这两种场合中),可以用 int *ar代替 int ar[]:
int sum(int ar[], int n);
无论在任何情况下,形式int *ar都表示ar是指向int的指针。形式int ar[]也可以表示ar是指向int的指针,但只在声明形式参量时才可以这样使用。*PS: 在gcc version 8.2.0 (MinGW.org GCC-8.2.0-3)下使用int ar[]作为函数的形参已经会报错,修改为int* **ar就没问题*
# 指针操作
* 赋值:可以把一个地址赋给指针。通常使用数组名或地址运算符&来进行地址赋值。
* 求值或取值:运算符*可以取出指针地址中所存储的数值。
* 取指针地址:使用运算符&可以得到存储指针本身的地址。
* 将一个整数加给指针:可以使用+运算符来把一个整数加给指针,或者把一个指针加给一个整数。两种情况下,这个整数都会和指针所指的 类型的字节数相乘,然后得到的结果会加到初始地址上。
* 增加指针的值:可以通过一般的加法或增量运算来增加一个指针的值,对指向某数组元素的指针做增量运算,可以让该指针指向下一个地址。
* 从指针中减去一个整数:可以使用-运算符来从一个指针中减去一个整数。指针必须是第一个操作数,或者是一个指向整数的指针。这个整数都会和指针所指向的类型的字节数相乘,然后所得的结果会从初始地址中减掉。
*减小指针的值:指针也可以做减量运算。
*求差值:可以求出两个指针之间的差值。通常对分别指向同一个数组的两个内存元素的指针求差值,以求出元素之间的距离。
*比较:可以使用比较运算符来比较两个指针的值,前提是两个指针具有相同的类型。
使用指针,有一个规则需要特别注意:不能对未初始化的指针取值,例如下面的例子:
```
int *pt;
*pt = 5;
```
程序的第二行表示把数值5存储到pt所指向的位置,但由于pt没有被初始化,因此他的值是随机的,不知道5将会被存储到什么位置。因此,在使用指针之前,必须要给他赋予一个已分配的内存地址。