007-数组,指针
数组:
什么是数组?数组有什么用?
数组即是同类型变量的集合;
作用就是一次性定义多个同类型的变量;
如何定义数组:
格式:
数组的成员类型 数组名[数组的成员个数]
数组的成员类型也被称为数组的基本类型;
数组的成员个数决定了系统为数组分配的空间的多少;
系统会为数组的每一个成员分配一个对应的存储空间;
系统会为数组分配一个连续的存储空间,顺序存放数组的成员变量;
数组的成员类型有哪些:
基本数据类型:
char,short,int,long,float,double
特殊数据类型:
结构体、指针、数组…
数组成员的名字表现形式:
数组名[下标];
使用下标来标注数组的第几个成员变量;
下标的范围是0~(数组成员个数-1);
数组的类型是什么?
无论任何时候,任何类型数据
从目标变量的定义去看该变量的类型
变量定义:
变量类型 变量名;
查看方式是找到变量名
变量定义时除变量名之外的所有都是变量类型
例子:
int a[5];
意思是定义了一个数组,该数组的基本类型为int
成员个数为5
成员名为a[0],a[1],a[2],a[3],a[4]
注意没有成员a[5]
a[5]属于越界访问,不建议
首先越界是错误的,但是程序运行系统会不会直接段错误呢?
不一定会
该数组的变量类型是:
int [5]
意义:
空间如何分配
系统会为数组分配一块连续的存储空间
会把存储空间分割成一块块对应基本类型的大小空间
并由小到大命名0~(n-1)
数组的初始化及赋值:
例子:
1.
int a[5];
a = 1,2,3,4,5; //错误的
注意:
数组的根本任然是一个又一个变量
所以需要指定数组的成员进行单独赋值
a[0] = 1; //正确赋值方式
a[1] = 2;
a[2] = 3;
a[3] = 4;
a[4] = 5; //注意不要越界
2.
利用循环逐个赋值
int a[5];
int i;
for(i=0;i<5;i++)
{
a[i] = i+1;
}
或者
for(i=1;i<=5;i++)
{
a[i-1] = i;
}
3.
特殊复制:初始化
1.
int a[5] = {1,2,3,4,5};
为a[0]~a[4]分别赋值为1,2,3,4,5
2.
int a[5] = {1,2};
a[0]=1,a[1]=2,a[2]~a[4]默认初始化为0
3.
int a[5] = {};
a[0]~a[4]都被默认初始化为0
4.
int a[5];
a = {1,2,3,4,5}; 不属于初始化
错误的
若相对数组进行整体赋值,必须是定义阶段进行,即是初始化
若定义阶段未进行整体赋值,则其后不能再进行整体初始化
4.
1.
int a[5] = {1,2,3,4,5,6}; 写法是错误的
因为越界了
2.
int a[] = {1,2,3,4,5,6}; 写法是正确的
不定长数组
3.
int a[]; 写法是错误的
因为不定长数组一定要在定义时进行初始化
虽然叫不定长数组,但是是通过初始化时的舒适化数值的个数,对数组的长度进行定义
4.
int n=5;
int a[n]; 写法是正确的
变长数组 可根据变量来确定数组的长度
变长数组指的是每一次数组的定义长度都可能不一样
并不是说数组定义完成后,还可随意更改数组长度
问题:
若数组定义完毕之后,改变n的值为10,数组的大小会变吗?
不会
因为系统为a分配空间是因为定义语句的执行
而改变n的大小不会引起数组的空间再一次分配
5.
int n;
int a[n];
n=5; 写法是错误的
原因是想要使用变长数组,那么是数组长度变化的变量n
必须在数组定义之前的位置确定一个大小,然后才能使用变长数组
*总结:
宗旨是任何变量在被定义时,一定要确定大小
即是确定变量类型,若是数组,则还需额外确定数组成员个数,不能是随机
数组名出现在一些地方时,表示什么意思:
例子:
int a[5];
数组名 a
数组首元素 a[0]
数组首元素的地址 &a[0]
sizeof(a); a表示的就是数组a
计算出的结果是数组a的整个大小
实际即是计算a的类型大小是多少
a的变量类型是int [5]
a 当数组名a单独出现或参与运算时
表示数组a的首元素的地址
即是a等价于&a[0]
a+1表示的是&a[1]
&a a表示的是数组a
而&a即是表示取得数组a的整个空间的大小
int b[4][5];
4表示二维数组b的成员变量的个数
5表示二维数组的成员变量b[0]~b[3]的成员变量的个数
二维数组的成员变量是一维数组
b是二维数组的名字,二维数组的类型是int [4][5]
sizeof(b) = 4*5*4 = 80字节
b单独参与一些运算时,表示数组b的首元素b[0]的地址
即是b等价于&b[0]
b[0]是二维数组b的首元素,本质是一个一维数组,类型是int [5]
sizeof(b[0]) = 4*5 = 20字节
思考:
*(b[0]+1) 获得的是b[0][1]的值
b[0]本质是一个一维数组
*(&b[0][0]+1) b[0][0]的地址类型大小4字节
*(&b[0][1])
b[0][1]
*(*(b+1)+1) 获得的是b[1][1]的值
b本质是一个二维数组
*(*(&b[0]+1)+1)
*(*(&b[1])+1)
*(b[1]+1)
*(&b[1][0]+1)
*(&b[1][1])
b[1][1]
练习:
定义一个数组,数组长度由n确定,n是由终端输入的数字来确定的
然后通过终端分别为数组的每一个成员变量进行赋值
最后比较数组中的所有数字,找出最大数和最小数
指针:
什么是指针?
指针就是寻址的地址
例如:0xbfebe668
什么是指针变量?
用来保存地址数据的变量,就是指针变量
指针变量不属于基本类型
指针在指向目标变量时,必须保证指针本身的指向类型和目标的变量类型一致
指针的特点:
特点是具有指向性
因为它保存的数据就是目标的地址
指针的定义:
格式:
目标变量的类型 *变量名;
*表示该变量的类型是指针
指针的目标变量类型必须与接下来的指向目标的类型一致
例子:
int *p; 指向基本数据类型的指针
char *p;
float *p;
指向符合类型数据的指针:
数组、指针、结构体、函数。。。
例子:
int *p;
指针的类型: 即是指的指针变量的数据类型
int * *表明p是指针变量
指针所指向的目标量的类型:
int
int **q;
指针的类型: 即是指的指针变量的数据类型
int ** 最右边的*表明q是指针变量,其它的*表明q所指向变量的类型
指针所指向的目标量的类型:
int *
指针的大小是多少:
即是指针变量的存储空间有多大?
char *p; 4字节
short *p; 4字节
int *p; 4字节
long *p; 4字节
float *p; 4字节
double *p; 4字节
指针的本质是保存一个地址,用来进行寻址
指针的指向类型的大小是多少:
char *p; 1字节
short *p; 2字节
int *p; 4字节
long *p; 4字节
float *p; 4字节
double *p; 8字节
指针的加法运算:
不能用来计算两个指针之间的加法
因为两个地址加在一起是没有意义的
指的是指针加上数字,进行的地址上的跳转
运算规则:
指针每+1,越过指针所指向的类型的空间大小
例子:
char *p1;
假设p1指向地址0xFFCCDD00
请问p1+1指向哪个地址?
0xFFCCDD00+1*1 = 0xFFCCDD01
请问p1+10指向哪个地址?
0xFFCCDD00+1*10 = 0xFFCCDD0A
int *p2;
假设p2指向地址0xFFCCDD00
请问p2+1指向哪个地址?
0xFFCCDD00+4*1 = 0xFFCCDD04
请问p2+10指向哪个地址?
0xFFCCDD00+4*10 = 0xFFCCDD28
指针的减法运算:
只能是两个同类型的指针之间进行相减
结果表示两个指针地址之间的单位差
怎样让指针变量指向目标量:
也即是在为指针变量进行赋值
利用符号& 叫取地址符
意思即是获得目标变量的地址
怎样使用指针访问指针所指向的变量的存储空间:
利用符号* 叫解引用
意思即是直接访问目标地址的存储空间
注意:
*和&在很多时候是可以认为是一对逆操作的
需要注意的是指针的类型,或者说之地址的类型
甄别地址类型的简单方式是,考虑类型的大小
问p2+10指向哪个地址?
0xFFCCDD00+4*10 = 0xFFCCDD28
指针的减法运算:
只能是两个同类型的指针之间进行相减
结果表示两个指针地址之间的单位差
怎样让指针变量指向目标量:
也即是在为指针变量进行赋值
利用符号& 叫取地址符
意思即是获得目标变量的地址
怎样使用指针访问指针所指向的变量的存储空间:
利用符号* 叫解引用
意思即是直接访问目标地址的存储空间
注意:
*和&在很多时候是可以认为是一对逆操作的
需要注意的是指针的类型,或者说之地址的类型
甄别地址类型的简单方式是,考虑类型的大小