首先来看2张图片:
这个程序是将二维数组 a 里面的元素输出出来,但是左图给指针赋值可以,但是右图不行,为什么?
因为p是一个数组,对于数组而言,p是一个常量,常量的地址是固定的,所以p=a相当于给常量赋值,这当然是不行的,语法上就是错误,而在左边,相当于对数组p里的元素赋值,元素的地址虽然确定了,但是元素的内容可以修改,他的元素内容是两个指向整型变量的指针,指针也是一种数据类型,更是一种变量,所以可以赋值
但是下图为什么可以赋值,请注意,右图的p首先是与指针符号相结合的,是一个指针,而指针是一个变量,和一般的变量没有区别,所以可以赋值,而左图或中图,p首先是一个数组,数组名是常量,所以不能直接给数组名赋值,这就是右图在指定的地方会报错的原因
从下面的例子看数组首地址的区别:
char a[4],*p;
char (*pa)[4],*pb;
pa = &a;
pb = &a[0];
&a和&a[0]都表示数组a的首地址,但是这两者有区别,&a[0]就是一个普通的char型变量的首地址,和p没有什么区别,指向一个内存单元;而&a不是一个简单的char型指针,而是char *[4]型指针,指向的是4个内存单元,所以使用
p = &a的时候就会报错,所以当给指针赋值的时候,还要判断这两者是否指向同样大小的内存单元。数组指针pa和pb所指向的是同一个起始地址(也就是pa=pb的),但是由于指针的类型不同,所指向的内存单元的大小不一样。pb到pb+1的变化大小是由它所指向的类型决定,由于指针是字符指针,所以变化一个字节,假如是整型指针,那就要变化4个字节;而pa到pa+1的变化大小为4个字节,所以在做指针运算时候尤其注意指针所指向的类型。
注意一点:看一个地址是否能复制给指针变量,主要就看该地址
+1和指针变量+1后,各自地址改变的长度是否一样
对于指针,主要包括2部分,一个是指针符号*,另一个就是指针变量,当然这个变量可以是普通的变量,也可以是数组或者函数,对于指针符号用在定义声明里面时,它就是个符号,表示变量是一个指针类型,但是当用在语句中的时,它就是指向指针变量所指向的地址里面的内容;
而对于指针变量,记住2点:
1、它是一个变量
2、它是一个地址:它的值就是一块内存区域的首地址,这块内存区域就是它所指的内存区域
指针变量p和普通变量一样,同样需要存储该变量的内存和地址,这个地址就是&p,而对于存储该地址的内存,int,char,double三种类型的指针在32位系统上都占4个字节的内存,但是像普通变量一样,指针也有值,和其他普通值的唯一一点区别就是,该值同样代表着计算机内的一块地址,换句话说,它的值和计算机内某一块内存首地址的名字是相同的,当在执行语句中,用指针命令符作用在该指针上的时候,它又指向该地址里面存储的值。
还要注意一点的是:指针变量占用内存的大小与它本身的类型无关,而是由计算机决定的,但是不同类型的指针变量所指向的内存区域的大小并不相同
Example:
char a=1, *pa;
int b=2, *pb;
double c=3, *pc;
pa = &a;
pb = &b;
pc = &c;
在这个定义中,pa,pb,pc分别在内存中占用4个字节,但是它们所指向的地址&a,&b,&c分别1个字节,4个字节和8个字节
************************************二维数组名和指针的关系****************************************
int a[2][2],*p;
对于a,&a,a[0],&a[0],a[0][0],&a[0][0]和指针p的关系,数组名a其实就是&a[0],值和类型都是相同的。而&a是整个数组的指针(不论是几维数组,&a都表示整个数组的指针),&a+1是变化到了数组a的4个元素以外的空间;而a[0]的值和&a[0][0]的值是相同的,就像a和&a[0]一样,属于同一类型。那a[0][0]应该表示什么呢?当然是数组第一个元素的值了。其中a,&a,a[0],&a[0],&a[0][0]的值是相同的,都是数组的首地址,但是它们步进的大小是不同的,其中a=&a[0],步进为2;a[0]=&a[0][0],步进为1;而&a步进为4