数组解析与总结
#include<stdio.h> #include<string.h> #include<Windows.h> void bubble_one_i(int bu[], int size0); void bubble_one_d(double bu1[], int size1); void bubble_two(int bu2[][8], int size2); void bubble_more(int bu3[][6][7][8], int size3); int main() { //数组是一种类型(聚合数据类型):只有类型才能定于变量,开辟空间 int arr[] = { 1, 2, 3, 4, 5 }; //[]:是常量表达式(必须>0),只能是整型或宏定义(建议使用宏定义) //此常量表示数组中元素的个数,所以此处默认为5 int size = sizeof(arr) / sizeof(arr[0]); char arr1[] = { 'a', 99, 'e' };//字符数组在内存中都以数字的形式存储 printf("%c\n", arr1[0]);//区别在于输出形式 printf("%d\n", arr1[0]); char arr2[] = "abcdefg";//一个字符串始终以'\0'结尾 //arr2等价于:{'a','b','c','d','e','f','\0'} printf("%d\n", strlen(arr2));//而其长度则不将'\0'计入,结果为7 printf("%d\n", sizeof(arr2) / sizeof(arr2[0])); //但其大小将'\0'计入(原因:大小是指给其开辟的内存空间),结果为8 char *p = "abcdefg";//内存开辟4个空间 //在32位的平台上指针变量开辟4个空间:2的32次方个地址->32个比特位+8位1字节->一个地址则需要4个字节存放 //用字符指针定义字符串,字符串的首元素地址被放入p中,而字符串整体被放在字符常量区,所以在栈区仅开辟4个字节 int arr3[] = { 1, 2, 3, 4, 5, };//最后一个元素后面的逗号可要可不要,对数组长度无影响 //对于数组的赋值:只有在数组初始化的时候可以整体直接赋值(即用{}整体赋值); //arr3 = { 5, 6, 7, 8, 9 };//错误:不可以二次整体赋值 //但不可以二次整体赋值 //数组在内存中的存储 //数组开辟的空间是连续的,从arr[0]到arr[size-1]是递增的 //原因 int i = 5;//一个int型的变量在内存中占4个字节,即为4个地址 int *p1 = &i;//而p1中只能存放一个地址,监视可知存放的是低地址 //而int这个类型决定了此地址后续的共4个地址整个被当做是一个整型 int arr4[] = { 1, 2, 3, 4, 5}; int *p2 = &arr4; //同理:数组也是一个类型,此时p2中存放的也是整个数组开辟空间的最低地址 //而最低地址的后续5*4个地址整体被当做是一个数组//类型决定看待内部地址内容的一个方式 //由此可知:所有的类型存放均是递增的 int arr5[] = { 1, 2, 3, 4}; printf("%p\n", arr);//数组的数组名在做右值或做运算时代表数组首元素的地址 printf("%p\n", &arr);//数组的地址 printf("%p\n", &arr[0]);//数组首元素的地址 //上三者的输出相同:数组的地址在数值上默认和数组首元素的地址是相等的(但在类型上不一致) //右值:代表存储内容;左值:代表存储空间 printf("%d\n", *arr);//如上所说:则*arr代表对数组首元素地址进行解引用 printf("%p\n", arr + 1);//代表数组第二个元素的地址等价于&arr[1] printf("%d\n", *(arr + 1));//代表第二个元素等价于arr[1] for (int j = 0; j < sizeof(arr5) / sizeof(arr5[0]); j++){ printf("%d\t", *(arr + j));//数组名+整数:获取到每个元素的地址 } printf("\n"); //二维数组:也是一种类型,所以在内存中也是连续递增存放的 int arr6[][4] = { { 1, 2, 3 }, { 0 } };//第一个[]代表此二维数组中有多少个元素(可省略) //第二个[]代表每个元素(即为一维数组:每个{}括起来的都标识一个一维数组)的长度(不可省略) //所以二维数组也可以理解为是一个存放多个一维数组的一维数组 printf("%p\n", arr6);//首元素的地址(地址就是指针):首元素即为一个一维数组 printf("%p\n", &arr6 + 1);//下一个二维数组的地址(&arr6代表这个数组的地址),与&arr6相差32:指针-/+整数实质是-/+指针所指类型的大小 int *p3 = &arr6[0][0]; //通过指针向二维数组赋值 for (int k = 0; k < 2 * 4; k++){ *(p3 + k) = k;//二维数组是连续存放的 } //一维数组的练习 //1 int arr7[] = { 1, 2, 3, 4 }; printf("%d\n", sizeof(arr7));//4*4 = 16 printf("%d\n", sizeof(arr7 + 0));//&arr7[0]:4 printf("%d\n", sizeof(*arr7));//*&arr7[0] = arr7[0] = 1:4 printf("%d\n", sizeof(arr7 + 1));//&arr7[1]:4 printf("%d\n", sizeof(arr7[1]));//2:4 printf("%d\n", sizeof(&arr7));//数组的地址:4 printf("%d\n", sizeof(*&arr7));//对数组整个的地址进行解引用:整个数组:16 printf("%d\n", sizeof(&arr7 + 1));//跳过整个数组的下一个地址:4 printf("%d\n", sizeof(&arr7[0]));//4 printf("%d\n", sizeof(&arr7[0] + 1));//&arr7[1]:4 //数组名在sizeof和&时代表整个数组//重中之重!!! //数组名在做右值或做运算时代表数组首元素的地址//重中之重!!! //&arr+1与&arr相差16个字节(整个数组) //arr+1与arr相差4个字节(数组中的一个元素) printf("\n"); //2 char arr8[] = { 'a', 'b', 'c', 'd', 'e', 'f' }; //sizeof:求数组大小 printf("%d\n", sizeof(arr8));//6*1 = 6 printf("%d\n", sizeof(arr8 + 0));//&arr8[0]:4 printf("%d\n", sizeof(*arr8));//*&arr8[0] = arr8[0] = 'a':1 printf("%d\n", sizeof(arr8[1]));//'b':1 printf("%d\n", sizeof(&arr8));//数组的地址:4 printf("%d\n", sizeof(&arr8 + 1));//跳过整个数组的下一个地址:4 printf("%d\n", sizeof(&arr8[0] + 1));//&arr8[1]:4 printf("\n"); //strlen:求字符串的长度 //strlen接收一个char*的参数(以'\0'结束但计算长度不包括'\0') printf("%d\n", strlen(arr8));//由于此字符数组没有'\0'而strlen是求一个字符串的长度 //而在c语言的定义中,字符串是以'\0'结尾的,所以此处的长度是遇到内存中的'\0'而结束所计算的长度 //即为随机值,但此随机值必然>=6,此次编译为17 printf("%d\n", strlen(arr8 + 0));//&arr8[0]:从首元素到结束:结果同上:17 //printf("%d\n", strlen(*arr8));//*&arr8[0] = arr8[0] = 'a':报错 //printf("%d\n", strlen(arr8[1]));//'b':报错 printf("%d\n", strlen(&arr8));//数组的地址:同上:17 printf("%d\n", strlen(&arr8 + 1));//跳过整个数组的下一个地址:则从此地址到内存中'\0'结束的长度:17-6 = 11 printf("%d\n", strlen(&arr8[0] + 1));//&arr8[1]:从第二个元素到'\0'结束的长度:17-1 = 16 printf("\n"); //3 char arr9[] = "abcdef"; //sizeof求字符串的大小包括'\0' printf("%d\n", sizeof(arr9));//7 printf("%d\n", sizeof(arr9 + 0));//&arr9[0]:4 printf("%d\n", sizeof(*arr9));//*&arr9[0] = arr9[0] = 'a':1 printf("%d\n", sizeof(arr9[1]));//'b':1 printf("%d\n", sizeof(&arr9));//数组的地址:4 printf("%d\n", sizeof(&arr9 + 1));//下一个数组的地址(跳过整个数组的下一个地址):4 printf("%d\n", sizeof(&arr9[0] + 1));//&arr9[1]:4 printf("\n"); //strlen:求字符串的长度 //strlen接收一个char*的参数(以'\0'结束但计算长度不包括'\0') printf("%d\n", strlen(arr9));//字符串默认以'\0'结尾,没有的话编译器会默认加上:6 printf("%d\n", strlen(arr9 + 0));//&arr9[0]:从首元素到结束:结果同上:6 //printf("%d\n", strlen(*arr9));//*&arr9[0] = arr9[0] = 'a':报错 //printf("%d\n", strlen(arr9[1]));//'b':报错 printf("%d\n", strlen(&arr9));//数组的地址:同上:6 printf("%d\n", strlen(&arr9 + 1));//下一个数组的地址(跳过整个数组的下一个地址):则从此下一个地址到内存中下一个'\0'结束的长度 //此次编译为25 printf("%d\n", strlen(&arr9[0] + 1));//&arr9[1]:从第二个元素到'\0'结束的长度:6-1 = 5 printf("\n"); //4 char *p4 = "abcdef";//p4指向此字符串常量,此时p4中存放的是a(即为字符串首元素)的地址 //注意:指针的数组无关!!! printf("%d\n", sizeof(p4));//字符串第一个元素的地址&a:4 printf("%d\n", sizeof(p4 + 1));//&b :4 printf("%d\n", sizeof(*p4));//*&a = 'a':1 printf("%d\n", sizeof(p4[0]));//'a':1 printf("%d\n", sizeof(&p4));//指针p的地址:4 printf("%d\n", sizeof(&p4 + 1));//跳过存放指针的下一个地址(存放p变量的下一个地址):4 printf("%d\n", sizeof(&p4[0] + 1));//&b:4 printf("\n"); printf("%d\n", strlen(p4));//字符串的第一个元素到末尾的'\0'的长度:6 printf("%d\n", strlen(p4 + 1));//从b位置到末尾的'\0'的长度:6-1 = 5 //printf("%d\n", strlen(*p4));//*&a = 'a':1//报错 //printf("%d\n", strlen(p4[0]));//'a':1//报错 printf("%d\n", strlen(&p4));//指针p的地址:从存放指针的地址开始到内存中下一个'\0'结束的长度 //此次编译为3 printf("%d\n", strlen(&p4 + 1));////跳过存放指针的下一个地址,则从此下一个地址到内存中下一个'\0'结束的长度 //此次编译为25 printf("%d\n", strlen(&p4[0] + 1));//从b位置到末尾的'\0'的长度:6-1 = 5 printf("\n"); //二维数组练习 int arr10[3][4] = { 0 }; printf("%d\n", sizeof(arr10));//3*4*4 = 48 printf("%d\n", sizeof(arr10[0][0]));//第一个元素(一维数组int [])的第一个元素(int):4 printf("%d\n", sizeof(arr10[0]));//第一个元素(一维数组int []):4*4 = 16 printf("%d\n", sizeof(arr10[0] + 1));//注意!!!arr10[0]代表第一个元素,而第一个元素是一个一维数组 //一维数组的数组名+1:代表&arr10[0][0]+1,则其代表&arr10[0][1]:4 printf("%d\n", sizeof(arr10 + 1));//第二个元素(一维数组int [])的地址:4 printf("%d\n", sizeof(&arr10[0] + 1));//第二个元素的地址:4 printf("%d\n", sizeof(*arr10));//*&arr10[0] = arr10[0] :4*4 = 16 printf("%d\n", sizeof(arr10[3]));//注意!!!结果正常输出16 //原因:允许访问和比较数组最后一个元素的下一个元素,但不允许写入 //数组名在sizeof和&时代表整个数组//重中之重!!! //数组名在做右值或做运算时代表数组首元素的地址//重中之重!!! //关于数组传参 /* 1、任何数组都是一维数组 2、一维数组传参时会降维:(作用)减少开销 3、会降维成指向其内部元素类型的一级指针 */ //一维数组传参 int bu[5]; int size0 = sizeof(bu) / sizeof(bu[0]); bubble_one_i(bu ,size0); double bu1[5]; int size1 = sizeof(bu1) / sizeof(bu1[0]); bubble_one_d(bu, size1); //二维数组传参 /* 二维数组传参时,第一个[](代表该数组的长度)可以不写,其余必须补充完整 原因:数组传参时都会降维成指向其内部类型的一级指针,而二维数组是内部元素为一维数组的一维数组 而第二个[]代表内部元素一维数组的元素个数,所以内部类型必须完整!!! */ int bu2[7][8]; int size2 = sizeof(bu2) / sizeof(bu2[0]); bubble_two(bu2, size2); //多维数组传参:要保证数组内部类型的完整,所以后三个[]必须完整!!! int bu3[5][6][7][8];//四维数组:存放5个三维数组的一维数组 int size3 = sizeof(bu3) / sizeof(bu3[0]);//适用于任何数组 bubble_more(bu3, size3); system("pause"); return 0; } void bubble_one_i(int bu[], int size0)//一维数组传参时,[]中会被忽略,可不写 { printf("%d\n", sizeof(bu));//4:降维成整型一级指针 } void bubble_one_d(double bu1[], int size1)//一维数组传参时,[]中会被忽略,可不写 { printf("%d\n", sizeof(bu1));//4:降维成双精度浮点型一级指针 } void bubble_two(int bu2[][8], int size2)//此处等价于int (*)[4] { printf("%d\n", sizeof(bu2));//4:降维成一维数组类型的一级指针 } void bubble_more(int bu3[][6][7][8], int size3)//此处等价于int (*)[6][7][8] { printf("%d\n", sizeof(bu3));//4:降维成三维数组类型的一级指针 }