作者博客主页:谦逊码农的旅程
1. sizeof中单独放一个数组名,此时的数组名表示整个数组。
2. &数组名,表示整个数组的地址。
3. 在 C 语言中,变量的地址通常是由一个指针来表示,而指针的大小取决于计算机架构和操作系统。一般来说,在32位系统中,指针的大小为4个字节(32位),在64位系统中,指针的大小通常为8个字节(64位)。因此,变量的地址在内存中占据的字节数取决于系统的位数。
4. sizeof 运算符用于计算数据类型或变量在内存中所占的字节数,不关注内存中放的是什么数据。
5. sizeof是一个操作符,不是函数。
6. 指针的加法会根据其指向的数据类型进行适当的偏移,确保指针指向正确的内存位置。
一维数组
一维数组的每个元素的地址类型为int*
整型数组
定义一个数组:
int a[] = { 1,2,3,4 };
一、 a
printf("%d\n", sizeof(a))
sizeof括号内的a表示整个数组,所以sizeof返回的是a数组的大小,结果是16。
二、a+0
printf("%d\n", sizeof(a+0));
a + 0是一个表达式,a没有单独出现在sizeof内,所以此时的a只能表示数组首元素的地址,a + 0是数组第一个元素的地址,在32位环境下地址的大小是4,64位环境下地址的大小是8。所以结果是4 / 8
三、*a
printf("%d\n", sizeof(*a));
*a表示解引用数组首元素的地址,得到的是一个整型的数1,它在内存中的大小是4个字节。
相当于 *(a+0)
四、a+1
printf("%d\n", sizeof(a + 1));
此处的a表示数组首元素的地址,加1表示跳过一个数组元素所占的空间,即数组第2个元素的地址。是地址结果就是4/8
五、a[1]
printf("%d\n", sizeof(a[1]));
a[1] 表示数组下标为1的元素,也可以表示成 *(a + 1) ,是一个整型,在内存中占4个字节。
六、&a
printf("%d\n", sizeof(&a));
&a表示整个数组的地址,整个数组的地址与数组首元素的地址相同,其次数组的地址也是地址,是地址大小就是4/8个字节。
七、*&a
printf("%d\n", sizeof(*&a));
*与&符号相抵消,所以此处表示整个数组,最后的结果是整个数组所占空间的大小,为16个字节
八、&a+1
printf("%d\n", sizeof(&a + 1));
&a表示数组a的地址,加1表示跳过整个数组所占的内存空间。是一个地址,结果为4/8
九、&a[0]
printf("%d\n", sizeof(&a[0]));
表示下标为0的元素的地址,结果为4/8
十、&a[0]+1
printf("%d\n", sizeof(&a[0] + 1));
&a[0]表示首元素的地址,加1表示a[1]的地址,结果为4/8
字符数组
代码1:
char arr[] = { 'a','b','c','d','e','f' };
一、arr
printf("%d\n", sizeof(arr));
此处的 arr表示整个数组,结果为 6
二、arr+0
printf("%d\n", sizeof(arr + 0));
此处的arr表示数组首元素的地址,加0也是数组首元素的地址,结果为4/8
三、*arr
printf("%d\n", sizeof(*arr));
首先,此处的arr表示数组首元素的地址,*arr表示解引用首元素的地址,即arr[0],也可以表示为
*(arr + 0),表示的是一个具体的数据,结果为1
四、arr[1]
printf("%d\n", sizeof(arr[1]));
arr[1]表示下标为1的数组元素,是一个数,结果为1
五、&arr
printf("%d\n", sizeof(&arr));
&arr表示数组的地址,数组的地址与数组首元素的地址相同,地址的大小为4/8
六、&arr+1
printf("%d\n", sizeof(&arr + 1));
&arr 表示arr数组的地址,加1表示跳过整个数组所占的内存空间大小,是一个地址,结果为4/8
七、&arr[0]+1
printf("%d\n", sizeof(&arr[0] + 1));
&arr[0]表示数组首元素的地址,加1表示跳过了数组中第一个元素的内存空间,即移动到了数组中下一个元素的地址,是arr[1]的地址,即&arr[1],大小为4/8
代码2:strlen函数统计字符串的长度
strlen函数接收的参数是个地址,它顺着这个地址往后统计字符的个数,直到遇到'\0'结束。
char arr[] = { 'a','b','c','d','e','f' };
一、arr
printf("%d\n", strlen(arr));
strlen是计算长度,它统计 '\0' 之前的字符个数。上述arr数组中没有'\0',会持续往后找,直到在内存中遇到 '\0' ,所以最终的结果是一个随机值。
二、arr+0
printf("%d\n", strlen(arr + 0));
strlen函数接收的是字符串的地址,arr+0表示数组arr的首地址,strlen函数会顺着这个地址往后统计字符的个数直到遇到'\0',所以结果是一个随机值。
三、*arr
printf("%d\n", strlen(*arr));
*arr是字符'a',ASCII码值是97,相当于将97作为地址传给了strlen,97这个地址指针无法访问,所以strlen得到的是一个野指针,结果会报错。
四、arr[1]
printf("%d\n", strlen(arr[1]));
arr[1] 是字符'b',ASCII码值是98,相当于将98作为地址传给了strlen,98这个地址指针无法访问,所以strlen得到的是一个野指针,结果会报错。
五、&arr
printf("%d\n", strlen(&arr));
&arr表示整个数组的地址,整个数组的地址是在数组首元素的地址处开始,strlen会一个一个的往后找,直到遇到'\0',结果为随机值。
六、&arr+1
printf("%d\n", strlen(&arr + 1));
&arr + 1表示跳过整个数组所占的空间长度,结果为随机值。
七、&arr[0] + 1
printf("%d\n", strlen(&arr[0] + 1));
&arr[0]是数组首元素的地址,加1表示arr[1]的地址,所以strlen会从arr[1]的地址开始往后找'\0',
结果为随机值。
代码3:
char arr[] = "abcdef";
一、arr
printf("%d\n", sizeof(arr));
在sizeof中arr表示整个数组,此时sizeof计算的是整个数组所占的空间,双引号会在结尾处自动添加'\0',所以结果是7
二、arr+0
printf("%d\n", sizeof(arr + 0));
此处的arr表示数组的首元素的地址,+0也是数组的首元素,地址在内存中的大小为4/8,结果为4/8
三、*arr
printf("%d\n", sizeof(*arr));
*arr表示数组中第一个元素,这个数组是char类型的,所以第一个元素占1个字节。
四、arr[1]
printf("%d\n", sizeof(arr[1]));
arr[1]是数组中的第2个元素,是char类型,所以结果为1。
五、&arr
printf("%d\n", sizeof(&arr));
&arr是整个数组的地址,是地址大小就是4/8
六、&arr+1
printf("%d\n", sizeof(&arr + 1));
&arr+1也是一个地址,大小是4/8
七、&arr[0]+1
printf("%d\n", sizeof(&arr[0] + 1));
&arr[0]是数组首元素的地址,加1是数组第二个元素的地址,大小为4/8
代码4:指针变量
char* p = "abcdef";
一、p
printf("%d\n", sizeof(p));
此处的p是指针变量,它存放的是字符串的首地址,也就是'a'的地址,大小为4/8
二、p+1
printf("%d\n", sizeof(p+1));
p+1是字符串中第二个元素的地址,即'b',大小为4/8
三、*p
printf("%d\n", sizeof(*p));
*p是字符'a',占1个字节
四、p[0]
printf("%d\n", sizeof(p[0]));
p[0]表示*(p+0),是字符a,大小为1
五、&p
printf("%d\n", sizeof(&p));
&p表示指针变量p的地址,大小为4/8
六、&p+1
printf("%d\n", sizeof(&p+1));
&p+1是跳过一个char大小的空间后的地址,大小为4/8
七、&p[0]+1
printf("%d\n", sizeof(&p[0]+1));
p[0]表示*(p+0),表示字符'a',&p[0]表示字符'a'的地址,再加1表示字符'b'的地址,大小为4/8
二维数组
int a[3][4] = { 0 };
每一排是一个一维数组。
a[0]、a[1]、a[2] 相当于二维数组a的三个元素
二维数组相当于数组的数组,传到子函数变成数组的指针,上述二维数组每个元素的类型是int*[4]
所以二维数组首元素的类型就是int*[4]。
二维数组在内存中是连续存放的,上述图只是便于理解和观察。
二维数组实际在内存中的存放:
一、a
printf("%d\n", sizeof(a));
此处的数组名a表示整个数组,sizeof计算整个数组所占空间的大小,总共有12个元素,每个元素为int类型,所以结果为48
二、a[0][0]
printf("%d\n", sizeof(a[0][0]));
a[0][0]表示第一个元素,结果为4
三、a[0]
printf("%d\n", sizeof(a[0]));
a[0]表示二维数组中的第一排的数组的数组名,单独放sizeof中表示这一排的整个数组,第一排数组中有4个元素,每个占4个字节,所以结果为16
四、a[0]+1
printf("%d\n", sizeof(a[0] + 1));
此时的a[0]没有单独放在sizeof中,所以不表示第一排的整个数组。此处的a[0]表示第一排数组的数组名,是第一排数组的首元素的地址即&arr[0][0],加1表示跳过一个int空间的大小,
即是&arr[0][1],大小为4/8
五、*(a[0]+1)
printf("%d\n", sizeof(*(a[0] + 1)));
a[0]是第一排数组的数组名,表示数组首元素的地址,它的类型是一个指针,指向一个地址,加1是第一排第二个元素的地址&arr[0][1],再解引用是第二个元素的值arr[0][1],大小为4个字节。
六、a+1
printf("%d\n", sizeof(a + 1));
此处的a表示二维数组的数组名,是二维数组首元素的地址,也就是第一排数组的地址,加1跳过一行,表示第二排数组的地址,a+1是一个数组指针,指向的是一个数组地址,结果为4/8
七、*(a+1)
printf("%d\n", sizeof(*(a + 1)));
两种理解方式:
1. a+1是第二排数组的地址,类型是一个数组指针,解引用就是第二排数组,大小为16个字节
2. *(a+1)是 a[1] ,单独放在sizeof中,表示第二排数组
八、&a[0]+1
printf("%d\n", sizeof(&a[0] + 1));
此处的a[0]是第一排数组的数组名,&a[0]表示的是第一排数组的地址,它的类型是一个数组指针,加1跳过一个数组所占的空间大小,所以&a[0] + 1表示第二排数组的地址,等价于 a+1,大小为4/8
九、*(&a[0]+1)
printf("%d\n", sizeof(*(&a[0] + 1)));
*(&a[0] + 1)表示第二排数组的地址解引用,是第二排数组,大小为16字节
十、*a
printf("%d\n", sizeof(*a));
此处的a没有单独放在sizeof中,所以表示二维数组首元素的地址,是第一排数组的地址,解引用后表示第一排数组a[0],大小为16个字节
十一、a[3]
printf("%d\n", sizeof(a[3]));
a[3]虽然不是二维数组a中的元素,但sizeof只是计算所占空间的大小,并没有去访问这个元素。a[3]无需真实存在,仅仅通过类型的推断就能算出大小。a[3]是第四排的数组名,单独放在sizeof内表示第四排数组,大小为16个字节。
创作不易,觉得还不错的话,点个赞吧