数组的基本概念
数组就是一个可以一次性定义多个相同类型的变量,并可以放到一个连续的内存中去。
初始化
只有在定义的时候顺便赋值才叫初始化。
int a = 1024 ; int arr[5] = {1,2,3,4,5}; // 完全初始化
int arr1[] = {1,2,3,4,5,6,7,8,9,10} // 正确,定义的时候并没有确定大小, 初始化后才确定的大小
arr2 = {1,2,3,4,5,}// 不可行, 数组只有在初始化的时候可以统一赋值
int arr2 [5] = {1,2,3,4,5,6,7}; // 语法上可以,但是逻辑上不允许, 涉嫌越界
int arr3[50] = {1,2,3,4,5}; // 不完全初始化 , 没有初始化部分自动填充0
数组名字的含义
数组名在不同的环境中表示的意思不一样
表示整个数组
a.在定义的时候 int a[10];
b.在sizeof(a)语句中;
c.在取地址&a时。
表示数组首元素的首地址
a.除了上面三种情况以外,其他所有情况都表示首元素的首地址。
数组元素引用
存储方式:一片连续的内存空间,按照具体的数据类型进行分割
数组下标:以数组首地址为起点的偏移量
int arr1[5] = {1, 2, 3, 4, 5};
printf("arr1[1]:%p
", &arr1[1]);
printf("arr1[2]:%p
", &arr1[2]);
printf("arr1[3]:%p
", &arr1[3]);
printf("arr1[4]:%p
", &arr1[4]);
printf("arr1[5]:%p
", &arr1[5]);
//输出结果,可得相邻的数组元素地址相差4,与数组的类型所占的大小相等
arr1[1]:0x7fffeec8c1f4
arr1[2]:0x7fffeec8c1f8
arr1[3]:0x7fffeec8c1fc
arr1[4]:0x7fffeec8c200
arr1[5]:0x7fffeec8c204
注意:
1.一位数组中arr表示首元素的起始地址,&arr表示整个数组的起始地址,虽然值是一样的但是代表的意义却不一样;
2.arr+1与&arr[1],arr+2与arr&[2].....arr+n与&arr[n]是相同的意思;
3.a[1]与1[a],a[2]与2[a]....a[n]与n[a]是相同的意思。
字符数组、字符串数组
专门用来存放字符数据的数组,成为字符数组。
char s1 [5] = {'a' ,'b' , 'c' ,'d' , 'e'}; // 中存放的是字符数据
char s2 [6] = {'a' ,'b' , 'c' ,'d' , 'e' , ' '}; // 中存放的是字符串数据
char s3 [6] = {"hello"} ; // s3中存放的是字符串 , 注意数组大小必须能完整存储下整个字符串包括结束符
char s4 [6] = "hello"; // 使用双引号的时候大括号可以省略
s4[1] = 'E' ;
printf("s1:%s
" , s1 ); // 注意该数组为字符数组,不应该使用%s来访问输出,他会涉嫌越界,%s需要遇到' '才愿意停下来
printf("s2:%s
" , s2 ); // 常规操作 printf("s2:%s
" , s2+2 ); s2+2 加了两个 char 的大小 ,
printf("s3:%s
" , s3 );
printf("s4:%s
" , s4 );
多维数组
二维数组可以理解为:数组内容为数组。
/* 测试代码 */
int arr[3][3] = {{1, 11, 111} ,
{2, 22, 222} ,
{3, 33, 333}};
printf("&arr: %p
", &arr);
printf("&arr+1:%p
", &arr+1);
printf("arr[0][0]:%p
", *arr+0);
printf("arr[0][1]:%p
", *arr+1);
printf("arr[0][2]:%p
", *arr+2);
printf("arr[0][0]:%p
", *(arr+0));
printf("arr[1][0]:%p
", *(arr+1));
printf("arr[2][0]:%p
", *(arr+2));
printf("arr[0][1]:%d
", *(*(arr+0)+0));
printf("arr[0][2]:%d
", *(*(arr+0)+1));
printf("arr[0][3]:%d
", *(*(arr+0)+2));
注意:
1.如果将代码中的&arr,arr+0,(arr+0)传递给相应的指针,其所代表的意义也将传递给指针。
零长数组
长度为零的数组
int a[0];
其主要的功能是放在结构体的末尾,作为结构的最后一个成员,可以作为结构体内存扩容入口,数组是C语言中唯一一个允许越界访问的东西。
越界访问:只是访问本来不属于某个变量的内存(数组原本申请大区域)不一定就是非法访问
越界是访问的内存只要都属于我当前程序所用的内存就不属于非法访问。
非法访问:访问的内存地址不属于你这个程序的内存。
变长数组
概念: 在定义数组之前可能他的长度是未知的, 定义语句执行后他的长度是固定的。
重点: 在定于语句中数组的长度是一个变量,定义结束之后即使长度的变量有所变化也不会影响数组的长度了。
说白了就是数组的长度是一个变量;
int i = 90 ; 。。。 。。 int buf[ i ] ;
int a = 10 ; int arr[ a ] = {0} ; // error: variable-sized object may not be initialized
注意:
变长数组不可以初始化。
指针数组
用来存放指针的数组
int * arr[5] ;
int a , b ,c ,d, e ;
arr[0] = &a ;
arr[1] = &b ;
char * str [3] = {"Hello" , "GZ2075" , "eVEN"};
for (int i = 0; i < 3; i++)
{
printf("str[%d]:%s
" , i , str[i]);
}
字符串常量
常量:不可以被修改的量
存储在常量区的字符串数据称为字符串常量,实际上是一个匿名数组
printf("%d
" , sizeof("GZ2075")); // "GZ2075"表示的整个数组
printf("%p
" , &"GZ2075"); // "GZ2075"表示的整个数组
printf("%c
" ,"GZ2075"[1]); // 使用与数组类似的方法来访问某一位元素
char * p1 = "GZ2075" ; // p1指向 "GZ2075" 匿名数组的首元素的首地址
char * p2 = "GZ2075" + 1; // p2 指向 "GZ2075" 匿名数组的第二个元素 ‘Z’
注意:
1.字符串都是以' '结尾的,不可忽略它的存在;
2.注意下面两个语句的区别:
char *p1 = "hello"; //直接将字符串常量的地址给了p1
char p2[] = "world"; //将字符串常量赋值到p2所在的存储区中,相当于拷贝了一份