(一)简介:
1.本质:一个值为内存地址的变量(或数据对象)。
2.间接运算符‘*’和取地址运算符‘&’的应用示例:
sometype *ptr//定义指针类型
ptr = &bah;//ptr指向bah
===>相当于val=bah(可记为“*”与‘&’抵消)
val = *ptr//找出ptr 指向的值
注:(1)*和指针名之间的空格可有可无。通常,程序员在声明时使用空格,在解引用变量时省略空格。 (2)指针实际上是一个新类型,不是整数类型。ANSI C专门为指针提供了%p格式的转换说明(%p:表示按十六进制输出数据。如果输出数据不够八位数,则左边补零)。
3.普通变量与指针变量的区别:普通变量把值作为基本量,把地址作为通过&运算符获得的派生量,而指针变量把地址作为基本量,把值作为通过‘*’运算符获得的派生量。
4.指针的主要作用:使用指针在函数间通信
e.g. int main(){
............
hanshu(&x, &y)//把地址发送给函数
............
}
sometype hanshu(int * u, int * v)//使用形参接收主函数传来的地址
{
............
}
注:声明函数时可省略ANSI C风格的函数原型中的形参名:sometype hanshu(int *, int *);
5.函数形参的选择(指针类型 or other)
(1)sometype hanshu(int num)//计算或处理值
(2)sometype hanshu(int * ptr)//在被调函数中改变主调函数的变量
(二)指针和数组
1.数组注意点:
(1)使用const可将数组设为只读
(2)数组属于自动存储类别
(3)数组的初始化
1)如果不初始化数组,数组元素和未初始化的普通变量一样,其中存储的都是垃圾值;但是如果部分初始化数组,剩余元素就会被初始化为0。
2)如果初始化数组时省略方括号中的数字,编译器会根据初始化列表中的项数来确定数组的大小。(弊端:无法察觉初始化列表中项数有误)
3)指定初始化器
1.C99规定:可以在初始化列表中使用带方括号的下标指明待初始化的元素。
2.如果指定初始化器后面有更多的值,那么这些后面的值将被用于初始化指定元素后面的元素。(e.g.[4]=31,30,31 ==>shuzu[5]=30, shuzu[6]=31)
3.如果再次初始化指定的元素,那么最后的初始化将会取代之前的初始化。
4.使用指定初始化器的数组未指定元素大小,编译器会把数组的大小设置为足够装得下初始化的值。
5.初始化二维数组时可以省略内部表示多个元素的花括号,只保留最外面的一对花括号。只需保证初始化数值的个数不变。但若初始化的数值不够,则按照先后顺序逐行初始化,直到用完所有值,未初始化的元素被统一初始化为0.
(4)定义一个数组:sometype shuzu[num];
sizeof shuzu是整个数组的大小(以字节为单位),sizeof shuzu[0]是数组中一个元素的大小(以字节为单位)。sizeof shuzu/sizeof shuzsu[0]=数组个数
(5)C保证在给数组分配空间时,指向数组后面第一个位置的指针仍是有效的指针。
(6)给数组元素赋值:除初始化外不允许使用花括号的形式赋值。
2.指针注意点:
(1) *start++//先表达指针指向位置上的值,再递增指针==>等于 *(start++)
*++start//先递增指针,再表达指针指向位置上的值
(*start)++//先表达指针指向位置上的值,再递增该值相同。
(2)指针求差:差值的单位与数组类型的单位。e.g.ptr2-ptr1等于2,means:两指针所 指向的两元素相隔两个int,而不是两字节。
(3)指针比较:使用关系运算符可以比较两个指针的值,前提是两指针都指向同类型的 对象。
(4)创建一个指针时,系统只分配了储存指针本身的内存,并未分配储存数据的内存。因此在使用指针之前,必须先用已分配的地址初始化它。或还可以使用malloc()函数先分配内存。Anyhow,使用指针时一定要注意,一定不要解引用未初始化的指针。
(5)const与指针:const位于'*'前——不能改值,const位于'*'后——不能改地址。
3.指针与数组之间的等价表示
(1)
dates + num = &dates[num]//相同的地址
*(dates + num) = dates[num]//相同的值
注:运算符(*)的优先级高于+,所以*dates+2=(*dates)+2
(2)只有在函数原型或函数定义头中,才可以用int ar[]代替int * ar,在函数定义中不能省略参数名。
声明数组形参:下面四种原型是等价的:
int hanshu(int *ar, int n);
int hanshu(int *,int);
int hanshu(int ar[], int n);
int hanshu(int [], int);
系统用8字节存储地址,函数输入形参即是传递的8字节的地址。
4.指针和多维数组(以二维数组为例)
(1)shuzu[m][n] m>0,n>0
1) 数组名shuzu是该数组首元素的地址,shuzu的首元素是内含两个int值的数组;
2)shuzu[0]是一个占用一个int大小对象的地址,而shuzu是一个占用两个int大小对象的地址。shuzu和shuzu[0]的值相同;
3)*shuzu=&shuzu[0][0] **shuzu=*&shuzu[0][0]=shuzu[0][0]
简而言之shuzu是地址的地址,必须解引用两次才能获取原始值;
(2)指向多维数组的指针
1)声明:sometype (* p)[n];//p指向一个内含n个sometype类型值的数组
注:‘[]’优先级高于‘*’。
sometype * p[n];//p是一个内含n个指针元素的数组,每个元素都指向sometype的指针
(3)other main
1)声明一个指向n维数组的指针时,只能省略最左边方括号中的值。因为第一对方括号只用于表明这是一个指针,而其他方括号则用于描述指针所指向数据对象的类型。
2)传递形参时,数组的维数必须是常量,不能用变量来代替。
5.复合字面量
1)优点:把信息传入函数前不必先创建数组,直接赋给指针。
2)字面量是除符号常量外的常量。
3)形式例如:创建一个数组 (sometype [n]){x,y,z......}
初始化时n可省略。