五、一维数组、二维数组、一级指针、二级指针、数组指针、指针数组
1.一维数组
①. 定义:数组就是某种数据类型变量的集合,存放在一块连续的内存上。
②. 作用:方便定义相同数据类型的变量。
③. 数组框架:元素的数据类型 数组名(元素个数)
例如: int num30 <=> int num[30]。 其中,元素的数据类型有:int char float...int *, char *, struct ....等 注意:元素个数必须是正整数!!!
④. 数组的定义方式
1)int a[3]; //未初始化定义,定义了一个有3个元素的数组,数组的元素类型为:int,数组的成员 值为随机值 2)int a[3]={1, 2, 3}; //全部初始化定义,定义了一个有3个元素的数组,数组的元素类型为: int,数组的成员值为:a[0] == 1, a[1] == 2, a[2] == 3 3)int a[3]={1,2}; //部分初始化定义,定义了一个有3个元素的数组,数组的元素类型为: int,数组的成员值为:a[0] == 1, a[1] == 2, a[2] == 0 4)int a[]={1, 2, 3, 4, 5}; //不定长数组,必须初始化,定义了一个有5个元素的数组,数组的 元素类型为:int,数组的成员值为:a[0] == 1, a[1] == 2, a[2] == 3,a[3] == 4,a[4] == 5 5) int num; //变长数组,不能初始化,定义时,num的值必须确定, scanf("%d", &num); int a[num]; //定义了一个有num个元素的数组,数组的元素类型为:int; 如果要给数组赋值,需要一个一个赋值 。
⑤. 计算数组的内存大小
数组的内存大小 == 数组元素类型所占字节数*元素个数 例如: int a[10]; sizeof(a) == sizeof(int)*10 == 40; char b[10]; sizeof(b) == sizeof(char)*10 == 10;
⑥. 访问数组元素
int a[5]={1,2,3,4,5}; a[0]==1; a[1]==2; a[2]==3; a[3]==4; a[4]==5; //数组元素最大的下标值等于元素个数-1
⑦. 数组名和数组的数据类型
1)数组名是数组首元素地址 //int a[5]; a==&a[0]; 2)数据类型 int a[3]; //数组a的数据类型是:int()[3]; //数组a的元素类型是:int;
2.二维数组
①. 二维数组本质上也是一维数组,只是其元素数据类型为一维数组,所以叫二维数组。
②. 二维数组定义模型
小数组的元素类型 数组名[N][M] //N:大数组的元素个数; //M:小数组的元素个数; //小数组的元素类型: int, char, float.... 例如: int array[2][3] --》表示定义了一个二维数组array,它有两个元素类型为int()[3]的元素。
③. 二维数组的定义和初始化
1)int a[2][3]; //未初始化定义,定义了一个二维数组,该数组有两个元素, 元素类型为:int ()[3],它的值为随机值 2)int a[2][3]={{1, 2, 3}, {4, 5, 6}}; //全部初始化定义,定义了一个二维数组,该数组有两个元素,元素类型为:int ()[3], 它的小数组的元素值:a[0][0]==1, a[0][1]==2, a[0][2]==3, a[1][0]==4, a[1][1]==5, a[1][2]==6 3)int a[2][3]={1, 2, 3, 4, 5, 6}; //全部初始化定义,定义了一个二维数组,该数组有两个元素,元素类型为:int ()[3], 它的小数组的元素值:a[0][0]==1, a[0][1]==2, a[0][2]==3, a[1][0]==4, a[1][1]==5, a[1][2]==6 4)int a[2][3]={{1}, {4, 5}}; //部分初始化定义,定义了一个二维数组,该数组有两个元素,元素类型为:int ()[3], 它的小数组的元素值:a[0][0]==1, a[0][1]==0, a[0][2]==0, a[1][0]==4, a[1][1]==5, a[1][2]==0 5)int a[2][3]={1, 2, 3}; //部分初始化定义,定义了一个二维数组,该数组有两个元素,元素类型为:int ()[3], 它的小数组的元素值:a[0][0]==1, a[0][1]==2, a[0][2]==3, a[1][0]==0, a[1][1]==0, a[1][2]==0 6)int a[][3]={{1, 2, 3},{4}}; //不定长二维数组,定义了一个二维数组,该数组有两个元素,元素类型为:int()[3], 它的小数组的元素值:a[0][0]==1, a[0][1]==2, a[0][2]==3, a[1][0]==4, a[1][1]==0, a[1][2]==0 注意:int a[2][]={{1, 2, 3},{4}};//小数组的元素个数必须确定的,否则编译会报错!!!
④. 二维数组的大小
二维数组的大小 == 小数组的元素类型大小 *小数组的元素个数 *大数组的元素个数
== 大数组的元素个数*小数组的数据类型大小
⑤. 数组元素的访问
int a[2][3]={1,2,3,4}; //把这种数组称之为两行三列的数组 a[0][0]==1, --》元素地址为:&a[0][0] a[0][1]==2, --》元素地址为:&a[0][1] a[0][2]==3, a[1][0]==4, a[1][1]==0, --》其余为赋值的元素默认值为0 a[1][2]==0
3.一级指针
①. 概念:指针也是一种变量,指针变量是用来存储对应变量的内存地址的。
②. 如何定义一个指针变量
模型: 被存储变量的数据类型 *变量名 例如: int a; //系统分配了4个字节内存,并把这块内存命名为a a = 100; //把100转化为二进制存储到a这块内存 int *p; //系统分配了4个字节内存,并把这块内存命名为p p=&a; //获取变量a的内存地址,把它转化为二进制存储到p这块内存
③. 怎么使用指针变量(解引用、取目标)
例如: int a= 100; int *p = &a;//--》int *p; p=&a; *p = 200; 《--》 a=200 printf(“*p:%d\n”, *p); //%d==200; printf(“a:%d\n”, a); //%d==200;
④. 指针内存大小:
无论什么类型的指针在32位系统中占4个字节 //char *p==4; int *p1==4; 无论什么类型的指针在在64位系统中占8个字节 //char *p==8; int *p1==8;
⑤. 指针加减--》内存地址加减
例如: int a = 0; int *p =&a; //假设a的地址为0x1000; p+1 --》 &a +1 == &a+1 *(sizeof(int)) //p+1 == 0x1000+1*4 == 0x1004 内存地址分为两部分:地址值和存储的对象 指针加减:和它存储对象的大小是有关系的 地址加减:和它存储对象的大小是有关系的 int 型指针+1 == int 型指针+1*sizeof(int) int 型指针+2== int 型指针+2*sizeof(int) char 型指针+1 == char 型指针+1*sizeof(char) long long 型指针+1 == long long型指针+1*sizeof(long long) int 变量地址+1 == int 变量地址+1*sizeof(int) int 变量地址+2== int 变量地址+2*sizeof(int) char变量地址+1 == char变量地址+1*sizeof(char) long long变量地址+1 == long long变量地址+1*sizeof(long long) 注意: 指针加减要考虑它存储对象的大小 内存地址加减也要考虑它存储对象的大小 内存地址包括两部分:地址值和存储的对象
⑥. 指针类型
int a=100; a的数据类型是:int 100的数据类型是:int &a的类型是:int * int *p=&a; p的数据类型是:int * p存储的对象类型为: int &a 的类型:int * &p的类型:int **
⑦. 通用指针(万能指针)
作用:能合法存储任意类型变量的地址,但是不能直接解引用
#include <stdio.h> #include <strings.h> int main() { unsigned int a =0x12345678; void *p2 = &a; //(unsigned int *)p2 把p2从viod *临时强制类型转换为unsigned int *(欺骗计算机) //此时(unsigned int*)p2+1== (unsignedint*)p2+1*sizeof(unsigned int) printf("%x\n", *((unsigned int *)p2)); printf("%p\n", p2); //printf("%p\n", p2+5); printf("%p\n", (unsigned int *)p2+1); //p2+1*sizeof(unsigned int) //(unsigned char *)p2 把p2从viod *临时强制类型转换为unsigned char *(欺骗计算机) //此时(unsigned char*)p2+1== (unsigned char *)p2+1*sizeof(unsigned char) printf("%p\n", (unsigned char *)p2+1); //(unsigned short *)p2 把p2从viod *临时强制类型转换为unsigned short *(欺骗计算机) //此时(unsigned short*)p2+1== (unsigned short *)p2+1*sizeof(unsigned short) printf("%p\n", (unsigned short *)p2+1); //(unsigned int)p2 -->把把p2从viod *临时强制类型转换为unsigned int, //此时(unsigned int)p2+1== (unsigned int)p2+1 //此时(unsigned int)p2+5== (unsigned int)p2+5 printf("%p\n", (unsigned int)p2+5); return 0; }
指针强制类型转化例子:
#include <stdio.h>
#include <strings.h>int main()
{
unsigned int a =0x12345678;
unsigned int *p = &a;
//p1-->的类型为:unsigned char *, &a的类型为:unsigned int *
unsigned char *p1 = &a;
printf("a:%x\n", a); //12345678
printf("*p:%x\n", *p); //12345678
printf("*p1:%x\n", *p1); //78
return 0;
}
⑧. NULL(空指针)
指针的零值:#define NULL (void *)0x0 int *p ; //野指针,里面的内存地址是不确定,非常危险 int *p = NULL; //指针变量量定义后,未初始化,最好赋值等于NULL *p = 100; 对NULL指针解引用会爆段错误: Segmentation fault (core dumped) -->段错误(非法访问没有访问权限的内存)
4. 二级指针
①. 概念:指针变量用来存储变量内存地址
一级指针存储除了指针变量之外变量的地址
二级指针存储一级指针变量地址
②. 模型:一级指针变量类型 *变量名;
int a=100;
int *p =&a;
int **q=&p;
③. 二级指针的大小:
32位系统占4个字节 64位系统占8个字节 int **q; sizeof(q) == 4;
④. 二级指针数据类型问题
int a=100; a的数据类型是:int 100的类型是:int &a的类型是:int * int *p = &a; p的数据类型是:int * &a的类型是:int * &p的类型是:int ** int **q=&p; q的数据类型是:int ** &p的类型是:int ** &q的类型是:int ***
5.数组指针
①. 概念:本质是一级指针,用来存储数组的地址
int a[3]; //数组a的类型是: int ()[3] //&a的类型是:int (*)[3] int (*p)[3] = &a; //定义一个数组指针,把数组a的地址存储到数组指针变量p里面 int b[4]; //数组b的类型是: int ()[4] //&b的类型是:int (*)[4] int (*p1)[4] = &b; //定义一个数组指针,把数组b的地址存储到数组指针变量p1里面 int c[2][3]; //数组c的类型是: int ()[2][3] //&c的类型是:int (*)[2][3] int (*p2)[2][3] = &c; //定义一个数组指针,把数组c的地址存储到数组指针变量p2里
②. 模型
char a[10]; //它的类型为:char ()[10] //&a的类型为:char (*)[10] char (*p)[10] = &a; -------------------- int a[2]; //它的类型是:int ()[2] 不等价的 int ()[10] //&a的类型为:int (*)[2] 定义一个相应类型的指针变量合法存储数组地址 int (*p)[2] = &a; int (*p1)[10] = &a; //不合法存储 -------------------- int a[2][3]; //它的类型是:int ()[2][3] //&a的类型为:int (*)[2][3] int (*p)[2][3] = &a ------------------- 模型: 数组的数据类型 *变量名
③. 内存大小
32位系统占4个字节 64位系统占8个字节
④. 数组指针公式: *(p+1) == p[1] == *(1+p) == 1[p]
*(a+1) == a[1] == *(1+a) == 1[a]
例如: #include <stdio.h> #include <strings.h> int main() { int a[3]={1, 2, 3}; int *p=&a[0]; //int *p=a; printf("*(p+1):%d\n", *(p+1)); //*(p+1) == p[1] == *(1+p) == 1[p] printf("*(a+1):%d\n", *(a+1)); //*(a+1) == a[1] == *(1+a) == 1[a] printf("*(1+p):%d\n", *(1+p)); printf("*(1+a):%d\n", *(1+a)); //*(a+1) == a[1] printf("a[1]:%d\n", a[1]); //a --> int * printf("p[1]:%d\n", p[1]); //p --> int * printf("1[a]:%d\n", 1[a]); //a --> int * printf("1[p]:%d\n", 1[p]); //p --> int * //比较特别的地方 printf("sizeof(a):%d\n", sizeof(a)); //sizeof(a)表示数组a的大小 printf("sizeof(p):%d\n", sizeof(p));//sizeof(p)表示指针变量p的大小 printf("*(p+2):%d\n", *(p+2)); printf("*(a+2):%d\n", *(a+2)); return 0; }
6.指针数组
①. 概念:本质是一个一维数组,它的元素类型是指针
int a=100;
int b=200;
int c=300;
int d=400;/*int *p1=&a;
int *p2=&b;
int *p3=&c;
int *p4=&d;*/定义指针数组
(int *) array[4]; int *array[4];
array[0] = &a; //非初始化赋值
array[1] = &b;
array[2] = &c;
array[3] = &d;