一般情况下,数组名就是数组首元素的地址,但是有以下两种情况除外。 1. 数组名单独作为sizeof函数的参数,如sizeof(数组名); 表示的是整个数组所占字节大小。 2. 对数组名做取地址操作,即:&数组名; 代表的是整个数组。即整个数组的地址,其+1操作是跨过整个数组长度大小。
第二:sizeof()库函数在以为整型数组中的应用int main(){ // 一维整型数组的用sizeof函数计算所占字节大小 int arr[] = { 1,2,4,8,16 }; printf("%d ", sizeof(arr)); // 20 整个数组所占字节大小:4 * 5 = 20 printf("%d ", sizeof(arr + 0)); // 4 | 8 首元素的地址,即地址所占字节:固定 printf("%d ", sizeof(*arr)); // 4 首元素所占字节大小,即int | 1所占字节大小:4 printf("%d ", sizeof(arr + 1)); // 4 | 8 第二个元素的地址所占字节大小:是固定的 printf("%d ", sizeof(arr[1])); // 4 第二个元素所占字节大小,即int | 2所占字节大小:4 printf("%d ", sizeof(&arr)); // 4 | 8 数组的地址所占字节大小:固定大小,该地址+1是跳过整个数组 printf("%d ", sizeof(*&arr)); // 20 整个数组所占字节大小(*&arr等同于a),即&arr是得到整个数组的地址,对其解引用得到的是整个数组,故为4 * 5 = 20; printf("%d ", sizeof(&arr + 1));// 4 | 8 指向数组最后一个元素后面所在内存地址的大小:固定大小 printf("%d ", sizeof(&arr[0])); // 4 | 8 首元素地址所占字节大小:固定 printf("%d ", sizeof(&arr[0] + 1)); //4|8第二个元素地址所占字节大小:固定 return 0;}
第三:一维字符数组在sizeof()函数中的应用int main(){ // 一维字符数组的用sizeof函数计算所占字节大小 char str[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g'}; printf("%d ", sizeof(str)); // 7 整个数组所占字节大小:1 * 7 = 7 printf("%d ", sizeof(str + 0)); // 4 | 8 首元素的地址,即地址所占字节:固定 printf("%d ", sizeof(*str)); // 1 首元素所占字节大小,即char | 'a'所占字节大小:1 printf("%d ", sizeof(str + 1)); // 4 | 8 第二个元素的地址所占字节大小:是固定的 printf("%d ", sizeof(str[1])); // 1 第二个元素所占字节大小,即char | 'b'所占字节大小:1 printf("%d ", sizeof(&str)); // 4 | 8 数组的地址所占字节大小:固定大小,该地址+1是跳过整个数组 printf("%d ", sizeof(*&str)); // 7 整个数组所占字节大小(*&str等同于str),即&str是得到整个数组的地址,对其解引用得到的是整个数组,故为1 * 7 = 7; printf("%d ", sizeof(&str + 1));// 4 | 8 指向数组最后一个元素后面所在内存地址的大小:固定大小 printf("%d ", sizeof(&str[0])); // 4 | 8 首元素地址所占字节大小:固定 printf("%d ", sizeof(&str[0] + 1)); //4|8第二个元素地址所占字节大小:固定 return 0;}
第四:一维字符数组在strlen中的应用strlen函数计算字符串长度,其在内存中遇到'\0',则结束计算
strlen的参数为一个地址。
int main(){ char str[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g' }; printf("%d ", strlen(str)); // 随机值 str为首元素的地址,从该位置向后访问,直到遇到'\0'时,结束 printf("%d ", strlen(str + 0)); // 随机值 str+0也为首元素的地址,从该位置向后访问,直到遇到'\0'时,结束 // printf("%d ", strlen(*str)); // ERROR 传的是‘a’,其ascll为97,即从内存为97的位置开始访问,属于非法访问内存 // 0x538AFF5C (ucrtbased.dll)处(位于 指针进阶.exe 中)引发的异常: 0xC0000005: 读取位置 0x00000061 时发生访问冲突 // printf("%d ", strlen(str[1])); // ERROR 同上 读取0x00000062时(十进制:98)发生访问冲突 // 0x52BDFF5C (ucrtbased.dll)处(位于 指针进阶.exe 中)引发的异常: 0xC0000005: 读取位置 0x00000062 时发生访问冲突。 printf("%d ", strlen(str + 1)); // 随机值 - 1 从数组的第二个元素所在地址开始向后访问 printf("%d ", strlen(&str)); // 随机值 从数组的地址(和数组首元素地址相同)的位置开始向后访问 printf("%d ", strlen(*&str)); // 随机值 整个数组所占字节大小(*&str等同于str),即&str是得到整个数组的地址,对其解引用得到的是整个数组,从首元素处开始向后访问; printf("%d ", strlen(&str + 1));// 随机值 - 7 从数组最后一个元素后面所在内存地址开始访问 printf("%d ", strlen(&str[0])); // 随机值 从数组首元素地址处开始向后访问 printf("%d ", strlen(&str[0] + 1)); //随机值 - 1 从数组第二个元素地址处开始向后访问 return 0;}
第五:用常量字符串进行初始化的一维数组关于sizeof的应用int main(){ // 一维字符数组(用常量字符串进行初始化, 数组中还存放了'\0'),用sizeof来计算所占字节大小 char str[] = "abcdefg"; printf("%d ", sizeof(str)); // 8 整个数组所占字节大小:1 * 8 = 8 printf("%d ", sizeof(str + 0)); // 4 | 8 首元素的地址,即地址所占字节:固定 printf("%d ", sizeof(*str)); // 1 首元素所占字节大小,即char | 'a'所占字节大小:1 printf("%d ��ʷ,����", sizeof(str + 1)); // 4 | 8 第二个元素的地址所占字节大小:是固定的 printf("%d ", sizeof(str[1])); // 1 第二个元素所占字节大小,即char | 'b'所占字节大小:1 printf("%d ", sizeof(&str)); // 4 | 8 数组的地址所占字节大小:固定大小,该地址+1是跳过整个数组 printf("%d ", sizeof(*&str)); // 8 整个数组所占字节大小(*&str等同于str),即&str是得到整个数组的地址,对其解引用得到的是整个数组,故为1 * 8 = 8; printf("%d ", sizeof(&str + 1));// 4 | 8 指向数组最后一个元素后面所在内存地址的大小:固定大小 printf("%d ", sizeof(&str[0])); // 4 | 8 首元素地址所占字节大小:固定 printf("%d ", sizeof(&str[0] + 1)); //4|8第二个元素地址所占字节大小:固定 return 0;}
第六:用常量字符串进行初始化的一维数组关于strlen的应用int main(){ // 一维字符数组(用常量字符串进行初始化, 数组中还存放了'\0'),用strlen来计算字符串的大小 char str[] = "abcdefg"; printf("%d ", strlen(str)); // 7 str为首元素的地址,从该位置向后访问,直到遇到'\0'时,结束:7 printf("%d ", strlen(str + 0)); // 7 tr+0也为首元素的地址,从该位置向后访问,直到遇到'\0'时,结束 //printf("%d ", strlen(*str)); // ERROR 传的是‘a’,其ascll为97,即从内存为97的位置开始访问,属于非法访问内存 printf("%d ", strlen(str + 1)); // 6 从数组的第二个元素所在地址开始向后访问 //printf("%d ", strlen(str[1])); // ERROR 同上 读取0x00000062时(十进制:98)发生访问冲突 printf("%d ", strlen(&str)); // 7 从数组的地址(和数组首元素地址相同)的位置开始向后访问 printf("%d ", strlen(*&str)); // 7 同strlen(str),即&str是得到整个数组的地址,对其解引用得到的是整个数组,故为7 printf("%d ", strlen(&str + 1)); // 随机值 从数组最后一个元素后面所在内存地址开始访问 printf("%d ", strlen(&str[0])); // 7 从数组首元素地址处开始向后访问 printf("%d ", strlen(&str[0] + 1)); // 6 从数组第二个元素地址处开始向后访问 return 0;}
第七:用常量字符串进行初始化的字符指针关于sizeof的应用int main(){ // 用字符指针变量接收一个常量字符串(是将该字符串的首字符的地址赋值给字符指针),用sizeof来计算所占字节大小 char *pstr = "abcdefg"; printf("%d ", sizeof(pstr)); // 4 | 8 p是一个指针变量,其存的是地址,故其大小是固定的 printf("%d ", sizeof(pstr + 0)); // 4 | 8 字符串中首元素a的地址,即地址所占字节:固定 printf("%d ", sizeof(*pstr)); // 1 字符串首元素a所占字节大小,即char | 'a'所占字节大小:1 printf("%d ", sizeof(pstr + 1)); // 4 | 8 字符串中第二个元素b的地址所占字节大小:是固定的 printf("%d ", sizeof(pstr[1])); // 1 字符串第二个元素b所占字节大小,即char | 'b'所占字节大小:1 printf("%d ", sizeof(&pstr)); // 4 | 8 指针变量pstr的地址,是固定大小的。 printf("%d ", sizeof(*&pstr)); // 4 | 8 等同于sizeof(pstr) printf("%d ", sizeof(&pstr + 1));// 4 | 8 pstr的地址的下一个地址,是固定的 printf("%d ", sizeof(&pstr[0])); // 4 | 8 首元素地址所占字节大小:固定 printf("%d ", sizeof(&pstr[0] + 1)); //4|8字符串中第二个元素b地址所占字节大小:固定 return 0;}
第八:用常量字符串进行初始化的字符指针关于strlen的应用int main(){ // 用字符指针变量接收一个常量字符串(是将该字符串的首字符的地址赋值给字符指针),用strlen来计算所占字节大小 char* pstr = "abcdefg"; printf("%d ", strlen(pstr)); // 7 pstr为首元素的地址,从该位置向后访问,直到遇到'\0'时,结束:7 printf("%d ", strlen(pstr + 0)); // 7 pstr+0也为首元素的地址,从该位置向后访问,直到遇到'\0'时,结束 //printf("%d ", strlen(*pstr)); // ERROR 传的是‘a’,其ascll为97,即从内存为97的位置开始访问,属于非法访问内存 printf("%d ", strlen(pstr + 1)); // 6 从字符串中的第二个元素b所在地址开始向后访问 //printf("%d ", strlen(pstr[1])); // ERROR 同上 读取0x00000062时(十进制:98)发生访问冲突 printf("%d ", strlen(&pstr)); // 随机值 从数组的地址(和数组首元素地址相同)的位置开始向后访问 printf("%d ", strlen(*&pstr)); // 7 同strlen(str),即&str是得到整个数组的地址,对其解引用得到的是整个数组,故为7 printf("%d ", strlen(&pstr + 1)); // 随机值 从数组最后一个元素后面所在内存地址开始访问 printf("%d ", strlen(&pstr[0])); // 7 从字符串中首元素a地址处开始向后访问 printf("%d ", strlen(&pstr[0] + 1)); // 6 从字符串中第二个元素b地址处开始向后访问 return 0;}
第九:二维数组在sizeof中的应用int main(){ // 二维数组 用sizeof计算所占字节大小 // 把一个二维数组看成一个一维数组时,则把其每一行看成一个元素, // 即每个元素又是一个一维数组,其对应的数组名为arr[i], i = 0 1 ... nrow - 1 // i行j列的值:arr[i][j] = *(arr[i] + j) = *(*(arr + i) + j) = *(arr + i)[j] int arr[2][3] = { 1,2,3,4,5,6 }; int i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { printf("%p\t", &arr[i][j]); } printf("\n"); } printf("%d ", sizeof(arr)); // 24 整个数组所占字节大小:2 * 3 * 4 = 24 printf("%d ", sizeof(arr[0][0])); // 4 数组中第一行第一列值所占字节大小:int|1,为4 printf("%d ", sizeof(arr[0])); // 12 arr[0]是二维数组中第一个元素|首元素|一维数组的数组名,计算的该数组的整个大小 printf("%d_%d ", sizeof(arr[0] + 1), *(arr[0] +1)); // 4_2, 此时arr[0]是一个一维数组中首元素的地址,+1则代表该一维数组中第二个元素的地址和值 printf("%d ", sizeof(*(arr[0] + 1))); // 4 | 8 第一行第二列元素所占字节 printf("%d_%p ", sizeof(arr + 1), *(arr + 1)); // 4 | 8 第二行的地址,不是二维数组中第二个元素的地址(arr[1]) printf("%d ", sizeof(*(arr + 1))); // 12 等价于arr[1] 第二行(一维数组)的地址解引用得到第二行(一维数组),二维数组中第二个元素|一维数组的数组名 printf("%d_%p ", sizeof(&arr[0] + 1), &arr[0] + 1); // 4 | 8 第二行的地址,一个一维数组的地址 printf("%d ", sizeof(*(&arr[0] + 1))); // 12 第二行的大小 printf("%d ", sizeof(*arr)); // 12 第一行的大小 printf("%d ", sizeof(arr[3])); // 12 第四行所对应的一维数组的数组名,代表整个一维数组的大小 return 0;}
第十:公司面试题解析int main(){ // 解析: // 1. **++cpp // cpp指向的是数组cp中首元素的地址,++cpp则cpp指向数组cp中第二个元素的地址 // *++cpp: 对其进行解引用,得到cp中第二个元素的内容:c+2 // **++cpp: 对其进行解引用,得到c+2所指向的内容,而c+2是数组c中第三个元素的地址,即得到数组c中第三个元素 // 数组c中第三个元素为字符串"python"首字母的地址,对其进行打印,则得到python // 2. *--*++cpp + 3 // ++cpp,则是cpp指向数组cp中下一个元素的地址,即c+1的地址 // *++cpp:对其进行解引用,得到其指向的内容:c+1,对其进行--操作,即内容-1,即c+1-1 = c // *--*++cpp:对c进行解引用,得到c指向的内容,c为数组c首元素的地址,即得到数组c的首元素,即字符串"hello"首字符的地址 // 对其进行+3操作,即得到字符串"hello"中第二个l字符的地址,对其进行打印,得到lo //3. *cpp[-2]+3 = *(*(cpp-2)) + 3 // 得到cpp所指向内容的前面第二个内容(c+3)的地址,对其进行解引用得到内容;c+3 // 对其进行及引用,得到c+3所指向的内容,即数组c中第四个元素,即字符串"coming"首字符的地址,对其+3操作,得到字符i的地址,对其打印,得到ing //4. cpp[-1][-1] + 3 = *(*(cpp-1) - 1) + 3 // cpp - 1:指向cpp所指向的前面的地址:c+2的地址,解引用得到c+2,即*(c+2 - 1) + 3 = *(c+1) + 3 // c+1: 是数组c中第二个元素的地址,对其解引用得到数组c中第二个元素,即字符串"world"的首字符的地址, + 1 得到字符o的地址,打印时,得到orld char* c[] = { "hello", "world", "python", "coming" }; char** cp[] = { c + 3, c + 2, c + 1, c }; char*** cpp = cp; printf("%s\n", **++cpp); printf("%s\n", *--*++cpp + 3); printf("%s\n", *cpp[-2] + 3); printf("%s\n", cpp[-1][-1] + 1); // return 0;}
它们之间的分布情况如下:
结果如下: