指针是一种用于存放另一个变量地址的变量。
一、指针和地址
机器的存储器通常由连续编号(或编址)的存储单元序列组成,这些存储单元可以单个或相连成组的方式操作。通常一个字节可以表示一个字符,两个相连的存储单元可以表示一个短整数,而四个相连的字节则构成一个长整数。指针由能存放一个地址的一组存储单元(通常是两个或四个字节)构成。
int x = 1, y = 2, z[10];
int *p; // p是指向整数的指针,也可以看做 (int *)p
p = &x; // p指向x
y = *p; // y等于p指向的值,也就是1
p = &z[0]; // p指向z[0]
int *p;
一个指针只能指向一个特定的类型的对象,每个指针对象也有一确定的数据类型(void类型除外,void类型的指针可以转换成指向任何对象类型的指针,但它不能间接引用它自身)。
二、指针和数组
指针和数组之间的关系十分密切,数组下标可以完成的任何运算都可以用指针来实现。一般指针运算比数组下标运算的速度快,所以用好指针是很重要的。
但是指针和数组并不是相等的。
int a[5];
int *p;
他们都具有指针值,也可以进行间接访问和下标引用操作。
区别在于声明一个数组时,编译器将根据声明指定的的元素的数量为数组保留内存空间,然后再创建数组名,它的值是一个常量,指向这段空间的起始位置。
声明一个指针变量时,编译器只为指针本身保留空间,它并不为任何整型值分配内存空间。指针变量为初始化为指向任何现有的内存空间,如果他是一个自动变量,它甚至根本不会被初始化。
上面声明之后,表达式*a是完全合法的,表达式*b却是非法的。*b将访问内存中某个不确定的位置,或者导致程序终止。
b = &a[0];
执行赋值语句后,b执行现有内存空间,b和a具有相同的值。一个数组的名字即该数组第0个元素的位置,所以上面语句也可以写成:
b = a;
对于数组啊a[i]的引用也可以写为 *(a+i)的形式。当然如果做取地址符&应用时,也可以写成 &a[i]或 a+i 的形式也是相同的。相应的,如果b是一个指针,那么表达式中可以使用具有下标的指针b, b[i]和 *(b+i) 的含义一样。但是一点要注意,指针是变量,但是数组名不是变量,因而像 a = b 和 a++ 这样的语句是非法的。
三、字符指针与函数
字符串常量最常见的用处或许就是作为函数变元:
printf("hello world\n");
当这样的一个字符串出现在程序中时,实际上时通过字符指针指向访问它,上述函数printf接收的是一个指向字符数组的头一个字符的指针。
语句
char *p;
p = "hello world";
把一个指向该字符的数组指针赋值给指针变量p,其中并未进行字符串的复制,只涉及到指针的操作。c语言中没有提供将一个完整的字符串作为一个整体处理的运算符。
下面两个定义差别很大:
char a[] = "hello world";
char *p = "hello world";
a是一个足以存放字符串初值和空字符'/0'的一位数组。可以更改数组中的单个字符,但是a是一个不可改变的常量,它总是指向同一个存储区。p是一个指针,其初值指向一个字符串常量,之后它可以被修改指向其他地址。