数组是一个由若干同类型变量组成的集合。
数组由连续的存储单元组成,最低地址对应第一个元素,最高地址对应最后一个元素。
数组有一维数组和多维数组。
在学习数组的时候了解指针很有必要,使用指针变量比使用下标效率更高!
一维数组:
数组名问题:
int a[10];
我们把a称为数组,a是一些同类型值得集合,a[0]表示a数组的第1个元素,a[1]表示第二个元素,a[i]表示第i个元素,下标和数组名一起,表示数组中某个特定的值,它们的类型是int型。
数组名a单独使用时,数组名此时代表的是数组第1个元素的地址(一个指针常量)。它的类型取决于数组元素的类型,比如a就是“指向int的常量指针”。
指针常量的值不能被修改!
数组名不作为首元素地址的两种情况:
数组名作为sizeof操作符或单目操作符&的操作数时。sizeof返回整个数组的长度。取一个数组名的地址是取一个指向该数组的指针。
int a[10];
int b[10];
int *c;
c=&a[0];和c=a;
这两条赋值语句的结果是一样的,因为数组名表示的是首元素a[0]的地址!经过赋值后的c所指向的是a数组的第1个元素。
b=a;非法!复制数组元素必须对数组的每一个元素依次进行复制,考虑用循环。
a=c;非法!记住a是指针常量,指针常量的值不能被修改!
下标问题:
a[0]表示数组的第1个元素;
a 表示第一个元素的地址;
*a 呢?
“*”间接访问操作符,对指针进行间接访问操作可以获得这个指针指向的结果值,所以* a的意思就是获得 a指向的元素的值,即就是第一个元素的值a[0]。
*(a+2)其实是a所指向的第1个元素后移2个int长度的位置指向的元素的值。
int arr[10];
int *p=arr+2;
它表示指针p指向了arr+2,其实arr+2表示指向数组第1个元素后移2个int长度的位置,即arr[2]。所以表达式结果是,指针p指向arr[2]。
有时候我们对优先级掌握的不清楚,也会造成判断结果出错。
比如:
*p+6表示的是arr[2]+6。
p+6表示p指向元素arr[2]后移6个int长度位置的元素(&arr[8])。
*(p+6)表示的是p先后移6个整数长度的位置,指向arr[8],在对arr[8]进行间接访问,得到arr[8]的值。
多维数组:
多维数组是在一维数组上的推广延伸。
int a[3];
int b[3][3];
int c[3][3][3];
………
多维数组在存储顺序上和一维数组类似,数组元素的存储顺序是是线性的。
|
|
|
|
|
|
|
|
|
|
在数组名问题上,多维数组和一维数组也是类似的,不过“第1个元素”的含义不同。
一维数组中,第一个元素是第一个值。
多维数组中,第一个元素其实是“第一个数组”,在二维数组里按照咱平时理解就是第一行元素。
指针
了解了数组,让咱了解指针,啥是指针呢?
指针就是一个地址的名字!
指针就是一个地址的名字!
指针就是一个地址的名字!
重要的话说三遍~~~
在计算机里,指针是用来存放地址的变量。
周末我邀请小明来我家玩,我给了小明地址(马栏山马兰坡),保证小明能顺利找到我家。(对没错,马栏山马兰坡就是指针~~~)
同样的如果我们要在计算机中找到某个内存单元,我们要找到该内存单元的地址。这个地址的名字称为“指针”。
这样一说,你就了解了为啥要有指针这种存在了,是为了方便啊,没有“马栏山马兰坡”这地名的出现,小明永远找不到我家!
既然已经知道指针的存在是为了找位置,那么问题来了,在计算机中,怎么编址???
对于32位的计算机,假设有32根地址线,假设每根地址线在寻址的是产生一个电信号,那32根地址线产生的地址就是:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
00000000 00000000 00000000 00000010
00000000 00000000 00000000 00000011
…….
11111111 11111111 11111111 11111111
总共有232地址,每个地址标志一个字节。
32位计算机地址用32个0或1组成二进制序列,所以地址用4个字节存储,所以1个指针的大小是4个字节。
指针有类型吗?
Yes!
在上边说数组名的时候,a是数组第1个元素的地址,是一个“指向int类型的指针变量”,如果数组是char型,那么a就是“指向char类型的指针变量”,其实指针的类型是由它指向变量的类型确定的!
char*类型的指针是为了存放char类型变量的地址,int*类型的指针是为了存放int类型变量的地址…
数组有一维数组,二维数组,多维数组,指针呢?
其实指针还有一级指针,二级指针,多级指针。嗯,对,所谓二级指针就是指向一级指针的指针。
int a=0;
int *p=&a;
int **pp=&p;
a的地址存放在p中,p的地址存放在pp中。
指针运算
指针+整数
结果还是指针。
如果对char类型指针+1,就是后移1个char类型长度位置,结果指向下一个字符。如果对int类型指针+1,就是后移1个int类型长度位置,结果指向下一个整型值。
char占据1个字节的内存空间,int占据4字节的内存空间,指针+1时会自动根据类型进行调整。
表达式 | 指针p | *p的大小 | 增加到指针的值 |
P+1 | char | 1 | 1 |
short | 2 | 2 | |
P+1 | int | 4 | 4 |
double | 8 | 8 | |
P+2 | char | 1 | 2 |
short | 2 | 4 | |
int | 4 | 8 | |
double | 8 | 6 |
指针可以减指针吗?
Yes,但是,前提是,它俩都指向同一个数组当中的元素,p1-p2结果是-4.
|
嗯,看完有没有一丢丢明白了?
指针数组
啥是指针数组?它到底是指针?还是数组?
嗯,它是“数组”。
指针数组,顾名思义,它是存放指针的数组。
int *p[10];//包含10个指针元素的数组。
那么
int (*p)[10];
这个表达式是?
数组指针
啥是数组指针呢,它是数组?还是指针?
嗯,它是“指针”。
数组指针,顾名思义,它是指向数组的指针。
int a[10][3];
int (*p)[3]=a;
这里,a是一个数组名,是一个指针。
P是一个指针变量,它指向包含3个int元素的一维数组。
*(p+1)是数组a的“首元素地址”(二维数组首元素可以理解为第一行元素地址)。
*(p+1)+1表示a[1][1]的地址。
函数指针
函数指针是指向函数的指针。
学习数组时,数组名是一个常量指针,指向数组首元素。
其实函数名也是一个常量指针,指向函数的第一条指令。
程序编译时,编译器要为每个函数分配地址,这个地址用一个指针来保存。此时,这个 指针 就是函数指针。
int (*p)(int x,int y);
函数指针数组
函数指针 数组,就是存放 函数指针 的数组。
int(*p_fun[])(int, int);
函数指针数组的指针
函数指针数组的指针,就是指向一个数组元素都是函数指针的数组的指针。
Void(*(*p)[10])(const char *)
血槽已空。。。。。。 |
|