::: warning strlen只能计算字符数组的长度。 sizeof可以计算任意类型大小。 :::
一维数组
数组名是首元素地址。 两个例外: 1. sizeof(数组名),数组名表示整个数组。 2. &数组名,数组名表示整个数组。
int main()
{
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a)); //16
printf("%d\n", sizeof(a + 0)); //4/8。a+0不是数组名,此时a表示首元素地址
printf("%d\n", sizeof(*a)); //4。a表示首元素地址,*a表示首元素
printf("%d\n", sizeof(a + 1)); //4/8。和a+0思路一致
printf("%d\n", sizeof(a[1])); //4/8。第二个元素大小。
printf("%d\n", sizeof(&a)); //4/8。&a取出的是数组a地址,指针的大小是4/8字节
printf("%d\n", sizeof(*&a)); //16。&a取出数组a地址,数组地址解引用访问整个数组
printf("%d\n", sizeof(&a + 1)); //4/8。数组a的地址+1,跳过数组a,仍表示地址
printf("%d\n", sizeof(&a[0])); //4/8。相当于&(a[0]),取出首元素地址
printf("%d\n", sizeof(&a[0] + 1)); //4/8。相当于(&a[0])+1,取出第二个元素地址
return 0;
}
字符数组
int main()
{
char arr[] = { 'a','b', 'c', 'd ', 'e ', 'f' };
printf("%d\n", sizeof(arr)); //6
printf("%d\n", sizeof(arr + 0)); //4
printf("%d\n", sizeof(*arr)); //1
printf("%d\n", sizeof(arr[1])); //1
printf("%d\n", sizeof(&arr)); //4/8
printf("%d\n", sizeof(&arr + 1)); //4/8
printf("%d\n", sizeof(&arr[0] + 1)); //4/8
return 0;
}
strlen计算字符长度时一定要找到\0才能停止。
int main()
{
char arr[] = { 'a', 'b','c ', 'd', 'e', 'f'};
printf("%d\n", strlen(arr)); //随机值
//arr是首元素地址开始向后计算
printf("%d\n", strlen(arr + 0)); //随机值
//等同于strlen(arr)
printf("%d\n", strlen(*arr)); //error
//strlen的参数是地址,*arr是首元素,相当于传入'a'的ASCII码97,
//strlen会把97当成起始地址向后计算字符,非法访问内存
printf("%d\n", strlen(arr[1])); //error
//相当于传入'b'的ASCII码98,非法访问内存
printf("%d\n", strlen(&arr)); //随机值
//&arr取得数组(首元素)地址,等同于strlen(arr)
printf("%d\n", strlen(&arr + 1)); //随机值
//&arr首元素地址+1,跳过整个数组
printf("%d\n", strlen(&arr[0] + 1)); //随机值
//&arr首元素地址+1,从第二个元素开始
return 0;
}
::: warning char arr1[] = { 1,2,3,4,5,6 }; arr1中元素为1,2,3,4,5,6。 char arr2[] = "123456"; arr2中元素为1,2,3,4,5,6,\0。 :::
int main()
{
char arr[] = "abcdef";
printf("%d\n", sizeof(arr)); //7
printf("%d\n", sizeof(arr + 0)); //8
printf("%d\n", sizeof(*arr)); //1
printf("%d\n", sizeof(arr[1])); //1
printf("%d\n", sizeof(&arr)); //4/8
printf("%d\n", sizeof(&arr + 1)); //4/8
printf("%d\n", sizeof(&arr[0] + 1)); //4/8
return 0;
}
#include <string.h>
int main()
{
char arr[] = "abcdef";
printf("%d\n", strlen(arr)); //6。arr表示首元素地址
printf("%d\n", strlen(arr + 0)); //6。等同于strlen(arr)
//printf("%d\n", strlen(*arr)); //error
//strlen的参数是地址,*arr是首元素,相当于传入'a'的ASCII码97,
//strlen会把97当成起始地址向后计算字符,非法访问内存
//printf("%d\n", strlen(arr[1])); //error
printf("%d\n", strlen(&arr)); //6。&arr取得数组地址,等同于strlen(arr[0])
//printf("%d\n", strlen(&arr + 1)); //error。&arr取得数组地址,+1跳过整个数组
printf("%d\n", strlen(&arr[0] + 1)); //5。从第二个字符向后计算
return 0;
}
上述代码第11行中,arr是数组,&arr的取出数组的地址,应该存放在数组指针char( * p)[7]中,类型是char( * )[7],strlen的类型是const char*,类型不同所以sizeof(&arr)运行报警告如下:
int main()
{
char* p = "abcdef"; //p是大小为4字节的指针
//将常量字符串abcdef的首字符a的地址放进p中
printf("%d\n", sizeof(p)); //4/8
//计算指针变量p的大小
printf("%d\n", sizeof(p + 1)); //4/8
//p中存放a的地址,p+1指向b的地址
printf("%d\n", sizeof(*p)); //1
//p是a的地址,*p是'a'
printf("%d\n", sizeof(p[0])); //1
printf("%d\n", sizeof(&p)); //4/8。
//&p表示p的地址
printf("%d\n", sizeof(&p + 1)); //4/8
//*p的地址+1跳过*p,仍是地址
printf("%d\n", sizeof(&p[0] + 1)); //4/8
//p[0]是a的地址,解引用后+1是b的地址
return 0;
}
::: tip 上述代码第11行,当int arr[10]; arr[0] == * (arr + 0); 所以p[0] == * (p + 0) == 'a'; :::
int main()
{
char* p = "abcdef"; //p是大小为4字节的指针
printf("%d\n", strlen(p)); //6
//p存储a的地址,即strlen(p)是从a开始向后计算直到\0
printf("%d\n", strlen(p + 1)); //5
//p存储a的地址,p+1是从b开始向后计算直到\0
printf("%d\n", strlen(*p)); //error
//*p是把a当作地址传给strlen
printf("%d\n", strlen(p[0])); //error
//*p等同于p[0]
printf("%d\n", strlen(&p)); //随机值
//p是存放a的地址的单独的内存空间,取出p的地址向后计算长度,直到遇到\0
printf("%d\n", strlen(&p + 1)); //随机值
//p是放a的地址的单独的内存空间,+1跳过p,取出p的地址向后计算长度,直到遇到\0
printf("%d\n", strlen(&p[0] + 1)); //5
//p[0]是a,&a取到a的地址后+1,是从b开始计算
return 0;
}
二维数组
int main()
{
int a[2][3] = { 0 };
//printf("%p\n", &a[0][0]);
//printf("%p\n", a[0] + 1);
//printf("%p\n", &a[0]+1);
printf("%d\n", sizeof(a)); //24。计算数组总大小:2*3*4
printf("%d\n", sizeof(a[0][0])); //4。第1行第1列的一个元素大小
printf("%d\n", sizeof(a[0])); //12。表示二维数组第一行元素
printf("%d\n", sizeof(a[0] + 1)); //4/8。表示第一行第二个元素地址
//a[0]没有单独放在sizeof内,表示二维数组第1行第1个元素地址
printf("%d\n", sizeof(*(a[0] + 1))); //4。第1行第2个元素大小
printf("%d\n", sizeof(a + 1)); //4/8。二维数组第2行地址
//二维数组的首元素表示第1行,即二维数组的数组名表示第1行的地址
printf("%d\n", sizeof(*(a + 1))); //12。*(a + 1)等同于a[1]
//a+1是第2行地址,解引用找到第2行元素,即第2行的数组名,sizeof(数组名)是数组大小
printf("%d\n", sizeof(&a[0] + 1)); //4/8。&a[0]是第1行地址,+1跳到第2行
printf("%d\n", sizeof(*(&a[0] + 1))); //12。&a[0] + 1是第2行地址,解引用得到第二行
printf("%d\n", sizeof(*a)); //12。a是首元素地址即第一行地址,解引用得到第一行
printf("%d\n", sizeof(a[3])); //12。第四行地址
return 0;
}
上述代码中第6行,a[0]是数组名,sizeof+数组名是计算整个数组的大小即二维数组该行的大小。 ::: warning 在二维数组中,每一行的元素都是arr[行数][i],如下: |arr[0][0]|arr[0][1]|arr[0][2]| |-|-|-| |arr[1][0]|arr[1][1]|arr[1][2]| 就可以把a[0]理解成第一行元素组成的数组的数组名,a[1]理解成第二行元素组成的数组的数组名,数组名+i访问下标元素。 ::: ::: tip 上述代码第6、第7行:
int main()
{
int a[2][3] = { 0 };
printf("%p\n", &a[0][0]);
printf("%p\n", a[0] + 1);
printf("%p\n", &a[0]+1);
return 0;
}
0000004B094FFC78
0000004B094FFC7C
0000004B094FFC84
对第5、第6行结果的对比,表示a[0]+1是第1行第2列元素。 对第6、第7行结果的对比,表示&a[0]是第1行元素的地址。 ::: 上述代码第13行,当二维数组的数组名没有单独出现在sizeof或&后时,将二维数组当作一维数组,二维数组的每一行当作一维数组的每个元素。二维数组的首元素表示第一行,即二维数组的数组名表示第一行的地址 上述代码第20行,sizeof计算a[3]超出数组范围,但sizeof不访问数组,只是列出第4行的数组名,即使数组不存在,sizeof也会根据数组类型计算第四行元素的大小。 ::: warning sizeof内部表达式不参与真实运算。 :::