文章目录
数组名在
C语言中有着特殊的地位,它表示整个数组的首元素的地址。但是在某些情况下,数组名有两个例外。
- 一是在
sizeof操作符中,数组名表示整个数组,计算的是整个数组的大小,单位是字节; - 二是在取地址操作符
&中,数组名同样表示整个数组,取出的是数组的地址。
1. 对于一维数组,如int a[] = {1, 2, 3, 4}
我们可以通过以下例子来理解数组名的用法:
printf("%d\n", sizeof(a));
// 输出16,a表示整个数组,计算的是整个数组的大小,单位是字节,即4个元素 * 4字节/元素 = 16字节
printf("%d\n", sizeof(a + 0));
// 输出4/8,a并非单独放在sizeof内部,也没有&,所以a是数组首元素的地址,a+0还是首元素的地址,大小为4/8字节
printf("%d\n", sizeof(*a));
// 输出4,a并非单独放在sizeof内部,也没有&,所以a是数组首元素的地址,*a就是首元素,大小为4字节(int类型)
printf("%d\n", sizeof(a + 1));
// 输出4/8,a并非单独放在sizeof内部,也没有&,所以a是数组首元素的地址,a+1就是第二个元素的地址,大小为4/8字节
printf("%d\n", sizeof(a[1]));
// 输出4,a[1]表示数组的第二个元素,计算的是第二个元素的大小,单位是字节,即4字节
printf("%d\n", sizeof(&a));
// 输出4/8,&a表示取出数组的地址,但是数组的地址也就是地址,所以大小为4/8字节
printf("%d\n", sizeof(*&a));
// 输出16,对数组指针解引用访问一个数组的大小,单位是字节,即16字节
printf("%d\n", sizeof(&a + 1));
// 输出4/8,&a表示数组的地址,&a+1还是地址,大小为4/8字节
printf("%d\n", sizeof(&a[0]));
// 输出4/8,&a[0]表示首元素的地址,计算的是地址的大小,即4/8字节
printf("%d\n", sizeof(&a[0] + 1));
// 输出4/8,&a[0]表示首元素的地址,&a[0]+1就是第二个元素的地址,大小为4/8字节
2. 对于字符数组类型,如char arr[] = { 'a','b','c','d','e','f' };
strlen函数用来计算字符串的长度,统计的是在字符串中'\0'之前出现的字符的个数。类似地,我们可以通过以下例子来理解数组名的用法:
定义了一个字符数组arr,包含了6个元素('a', 'b', 'c', 'd', 'e', 'f')。
printf("%d\n", strlen(arr)); //随机值
printf("%d\n", strlen(arr + 0)); //随机值
这两行代码使用了strlen函数来计算字符串长度,但是传入的参数类型不正确,因此会导致结果不确定。
strlen(arr):arr作为数组名,实际上会转换成指针,传递的是首元素的地址,而strlen函数期望传入的是以空字符结尾的字符串,因此结果不确定,可能会输出随机值。strlen(arr + 0):arr + 0仍然是数组的首元素地址,同样不符合strlen函数的要求,结果也不确定。
printf("%d\n", strlen(*arr)); //err
printf("%d\n", strlen(arr[1])); //err
这两行代码都会导致编译错误。strlen函数接受的参数类型应该是以空字符结尾的字符串,而*arr和arr[1]分别是首元素和第二个元素,不符合参数类型要求。
printf("%d\n", sizeof(arr));
//6 数组名arr单独放在sizeof内部,计算的是整个数组的大小,单位是字节
printf("%d\n", sizeof(arr + 0));
//4/8, arr是首元素的地址==&arr[0],是地址就是4/8个字节
//char*
//指针变量的大小和类型无关,不管什么类型的指针变量,大小都是4/8个字节
//指针变量是用来存放地址的,地址存放需要多大空间,指针变量的大小就是几个字节
//32位环境下,地址是32个二进制位,需要4个字节,所以指针变量的大小就是4个字节
//64位环境下,地址是64个二进制位,需要8个字节,所以指针变量的大小就是8个字节
//门缝里看指针,把指针给看扁了
//
printf("%d\n", sizeof(*arr));
//1, arr是首元素的地址,*arr就是首元素,大小就是1Byte
printf("%d\n", sizeof(arr[1]));//1
printf("%d\n", sizeof(&arr));
//4/8, &arr是数组的地址,sizeof(&arr)就是4/8个字节
printf("%d\n", sizeof(&arr + 1));
//4/8, &arr+1 是跳过数组后的地址,是地址就是4/8个字节
printf("%d\n", sizeof(&arr[0] + 1));
//4/8, 第二个元素的地址,是地址就是4/8Byte
3. 对于字符串类型,如char* p = "abcdef";
char* p = "abcdef";
printf("%d\n", strlen(p));
//6, 计算字符串常量"abcdef"的长度,结果是6。
printf("%d\n", strlen(p + 1));
//5, 计算指针p加1后的地址所指向的字符串的长度,结果是5。即从字符'b'开始到字符串末尾的长度。
printf("%d\n", strlen(*p));
//err, 由于*p等价于字符数组的第一个元素,即字符'a',所以计算字符'a'的长度,结果是未定义的行为,因为strlen函数要求以空字符'\0'作为字符串的结束标志。
printf("%d\n", strlen(p[0]));
//err, 由于p[0]等价于*(p+0),所以计算字符'a'的长度,结果同样是未定义的行为。
printf("%d\n", strlen(&p));
//err, 计算指针变量p的地址所指向的字符串的长度,结果是未定义的行为。
printf("%d\n", strlen(&p + 1));
//err, 计算指针变量&p加1后的地址所指向的字符串的长度,结果是未定义的行为。
printf("%d\n", strlen(&p[0] + 1));
//5, 计算字符数组的第二个元素(字符'b')之后的字符串的长度,结果是5。
printf("%d\n", sizeof(p));
//4/8, 计算的是指针变量的大小
printf("%d\n", sizeof(p + 1));
//4/8, p+1还是地址,大小是4/8个字节
printf("%d\n", sizeof(*p));
//1个字节, *p == 'a'
printf("%d\n", sizeof(p[0]));
//1个字节, p[0]--> *(p+0) --> *p == 'a';
printf("%d\n", sizeof(&p));
//4/8个字节,&p 是地址
printf("%d\n", sizeof(&p + 1));
//4/8, &p是地址,&p+1还是地址,是地址就是4/8个字节
printf("%d\n", sizeof(&p[0] + 1));
//4/8, 计算表达式&p[0] + 1的大小,由于结果仍然是指针类型,大小也是4/8个字节。
4. 对于二维数组类型,如int a[3][4] = { 0 };
printf("%zd\n", sizeof(a));
// 48,计算整个二维数组a的大小,结果为48字节。由于a的类型是int[3][4],所以它有3行4列,每个元素占4个字节。
printf("%zd\n", sizeof(a[0][0]));
// 4,计算数组中的单个元素a[0][0]的大小,结果为4字节。该元素的类型是int,所以大小为4个字节。
printf("%zd\n", sizeof(a[0]));
// 16,计算数组中的单个元素a[0][0]的大小,结果为4字节。该元素的类型是int,所以大小为4个字节。
printf("%zd\n", sizeof(a[0] + 1));
// 4/8,计算第一行的首元素地址加1后的地址所指向的地址的大小,结果为4或8字节。由于a[0]既没有放在sizeof内部,也没有使用取地址符&,所以a[0]表示第一行这个一维数组的首元素地址。
printf("%zd\n", sizeof(*(a[0] + 1)));
// 4,计算第一行的第二个元素的大小,结果为4字节。其中,*(a[0] + 1)等价于a[0][1],即第一行的第二个元素。
printf("%zd\n", sizeof(a + 1));
// 4/8,计算第二行的地址的大小,结果为4或8字节。由于a作为二维数组的数组名没有放在sizeof内部,所以它表示二维数组的首行的地址。
printf("%zd\n", sizeof(*(a + 1)));
// 16,计算第二行这个一维数组的大小,结果为16字节。其中,*(a + 1)等价于a[1],即二维数组的第二行。
printf("%zd\n", sizeof(&a[0] + 1));
// 4/8,计算第二行的地址加1后的地址所指向的地址的大小,结果为4或8字节。由于&a[0]取出的是第一行这个一维数组的地址。
printf("%zd\n", sizeof(*(&a[0] + 1)));
// 16,计算第二行这个一维数组的大小,结果为16字节。其中,*(&a[0] + 1)等价于*(a + 1),即二维数组的第二行。
printf("%zd\n", sizeof(*a));
// 16,计算第一行这个一维数组的大小,结果为16字节。其中,*a等价于a[0],即二维数组的第一行。
printf("%zd\n", sizeof(a[3]));
// 16,sizeof(a[3]):计算第四行这个一维数组的大小,结果为16字节。由于数组a只有3行,而访问越界是未定义行为,但是sizeof是类型属性,可以推测出其大小。
文章详细解释了C语言中数组名在sizeof和strlen函数中的行为,包括一维、字符数组、字符串和二维数组的实例,以及数组名作为地址和计算大小的区别。
872

被折叠的 条评论
为什么被折叠?



