006 从不同的角度理解数组名的意义——“C”
一、数组名的意义是什么?
引入
1.数组名的意义:sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小
&数组名。这里的数组名表示整个数组。取出的是整个数组的地址
除此之外所有的数组名都表示首元素的地址
2.strlen函数基本用法:size_t strlen ( const char * str );
strlen: Returns the length of the C string str.
返回字符串的长度
The length of a C string is determined by the terminating null-character: A C string is as long as the number of characters between the beginning of the string and the terminating null character (without including the terminating null character itself).
字符串的长度取决于空字符\0的所在位置,字符串的长度包括给定的字符串起始位置到\0处,不包含\0
3.sizeof运算符基本用法:以字节为单位返回类型或值的大小,该值为无符号整数
二、使用步骤
1.从数组元素为单个字符的形式理解数组名的意义
int main()
{
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));
// sizeof(数组名):整个数组的大小,6个字节
printf("%d\n", sizeof(arr+0));
// 数组首元素地址,地址是编号,大小为4/8个字节
printf("%d\n", sizeof(*arr));
// 不是只有arr(数组名)放在里面 取地址*arr是首元素的大小,计算的是首元素的大小
// 字节为1
printf("%d\n", sizeof(arr[1]));
// 数组的第二个元素大小,1个字节
printf("%d\n", sizeof(&arr));
// 取出整个数组的地址,4/8
printf("%d\n", sizeof(&arr+1));
//4个字节
// &数组名:取出整个数组的地址,+1:跳过整个数组后的地址,依旧是地址
// sizeof不会真的去访问地址,
printf("%d\n", sizeof(&arr[0]+1));
//取出第一个元素的地址,+1第二个元素的地址 4/8
return 0;
}
int main()
{
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", strlen(arr));
//随机值,不知\0的位置
printf("%d\n", strlen(arr + 0));
//传给str首元素的地址从后数
// printf("%d\n", strlen(*arr));
// arr:数组首元素的地址,*解引用地址=97
//传给str字符‘a’=97,代码是有问题的,str把97当作地址
//这一块地址不是arr的,把地址传给str,会形成非法访问0X000061=16
// printf("%d\n", strlen(arr[1]));
// 字符'b'=98
//把字符‘b’当作地址,形成非法访问,str
printf("%d\n", strlen(&arr));
//随机值 虽然是数组地址,但传给Str就知道从起始位置开始数
printf("%d\n", strlen(&arr + 1));
//随机值 跳过一个数组,从数组末尾开始数,随机值-6
printf("%d\n", strlen(&arr[0] + 1));
//从b的位置往后数,随机值-1
return 0;
}
2.从数组元素为字符串的形式理解数组名的意义
int main()
{
char arr[] = { "abcdef" };
printf("%d\n", sizeof(arr));
//只有数组名,表示整个数组的大小
//数组的大小,7个元素,7个字节
printf("%d\n", sizeof(arr + 0));
//arr数组名不是单独放在括号里面,表示数组首元素的地址
//地址是编号,4/8个字节
printf("%d\n", sizeof(*arr));
//arr数组名不是单独放在括号里面
//arr数组首元素的地址 *arr是首元素,计算的是首元素的大小:char类型: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 &arr[0]:数组首元素的地址 +1:下一个元素的地址
printf("%d\n", strlen(arr));
//6个字节
//数组名表示数组首元素地址
//传入一个数组名的时候,strlen默认在数组起始位置开始统计,到\0结束
printf("%d\n", strlen(arr + 0));
//6个字节
//数组名表示数组首元素地址 +0:依旧是数组首元素的地址传给strlen作为起始位置
//printf("%d\n", strlen(*arr));
//传给str字符‘a’=97,代码是有问题的,str把97当作地址
//这一块地址不是arr的,把地址传给str,strlen要访问地址找到起始位置
//会形成非法访问 err
//printf("%d\n", strlen(arr[1]));
//把字符‘b’=98当作地址,形成非法访问,err
printf("%d\n", strlen(&arr));
//6
//取出的是整个数组的地址 类型应该是指针类型 数组指针char (*)[7]
//strlen的类型是const char*类型
//但传给Str就把数组首元素地址当作起始位置
printf("%d\n", strlen(&arr + 1));
//&数组名:表示整个数组,取出的是整个数组的地址
//随机值 跳过一个数组,从数组末尾开始数,随机值-6
printf("%d\n", strlen(&arr[0] + 1));
//从b到\0大小为5个字节
return 0;
}
3.从指针的角度理解数组名的意义
int main()
{
char* p = "abcdef";
printf("%d\n", strlen(p));
//指针p中存放的是a的地址,起始位置为a,6个字节大小
printf("%d\n", strlen(p + 1));
//p+1是‘b’的地址 字节大小为5
printf("%d\n", strlen(*p));
//err 将aAscll码值当作地址,非法访问
printf("%d\n", strlen(p[0]));
//相当于*(p+0) 将aAscll码值当作地址 非法访问 err
/printf("%d\n", strlen(&p));
//随机值
printf("%d\n", strlen(&p + 1));
//随机值,跳过p变量
printf("%d\n", strlen(&p[0] + 1)); //'b'的地址,5
return 0;
}
非法访问err
屏蔽掉代码后成功运行
int main()
{
char* p = "abcdef";
printf("%d\n", sizeof(p));
//指针变量是用来存放地址的
//一个指针变量的大小4/8字节
printf("%d\n", sizeof(p+1));
//‘b’的地址,4/8个字节
printf("%d\n", sizeof(*p));
//解引用,字节大小为1,一个字符的大小
printf("%d\n", sizeof(p[0]));
//相当于*(p+0) 表示字符'a' 1个字节
printf("%d\n", sizeof(&p));
//4/8个字节
//指针p中存放地址类型为char* &p--char** 把&p的地址取出来放到二级指针中去
//char**pp *pp表明pp是指针,
//char*说明pp指向的是p,p的类型是char*
printf("%d\n", sizeof(&p+1));
//pp指向的是char*的数据,+1跳过一个char*的数据,4/8个字节
printf("%d\n", sizeof(&p[0] + 1)); //'b'的地址,4/8个字节
return 0;
}
4.从二维数组的角度理解数组名的意义
int main()
{
int a[3][4] = { 0 }; //定义一个二维数组
printf("%d\n", sizeof(a));
//48个字节 a这个二维数组的数组名单独放在sieof内部,计算整个数组的大小
printf("%d\n", sizeof(a[0][0]));
//第一行的第一个元素,4个字节
printf("%d\n", sizeof(a[0]));
//a[0]作为第一行的数组名,这个时候数组名单独放在sizeof内部,计算的第一行的数组大小
//一行4个整型,16个字节
printf("%d\n", sizeof(a[0]+1));
//a[0]是第一行的数组名,a[0]不是单独放在sizeof内部,表示首元素的地址,即第一行第一个元素的地址
//+1第一行第二个元素的地址
//4个字节
printf("%d\n", sizeof(*(a[0]+1)));
//解引用 a[0][1]大小为4个字节
printf("%d\n", sizeof(a+1));
//第二行的地址,依旧是地址,大小为4个字节
//a+1是跳过一行,指向了第二行
// a作为二维数组的数组名并非单独放在sizeof内部,所以表示二维数组首元素的地址
// 二维数组首元素地址是第一行的地址
//二维数组的首元素是第一行,这里的a就是第一行的地址--类型为int(*)[4]数组指针
//+1类型不变,还是数组指针
//并不是指向第一行第二个元素,第一行第二个元素是整形指针,指向一个整形
printf("%d\n", sizeof(*(a+1)));
//对数组第二行解引用得到第二行的大小,16个字节
printf("%d\n", sizeof(&a[0]+1));
//&a[0]是第一行的地址
//&a[0]+1是第二行的地址,4个字节
printf("%d\n", sizeof(*(&a[0]+1)));
//解引用第二行的地址,字节大小为16个字节
printf("%d\n", sizeof(*a));
//数组名不是单独放在里面,相当于二维数组首元素的地址--第一行的地址
//解引用大小为16个字节
//*a==*(a+0)==a[0]
printf("%d\n", sizeof(a[3]));
//大小为16个字节
//sizeof不会真的访问。不越界
//根据类型属性就判断出a[3]与a[1]类型属性相同,不会去访问第四行
return 0;
}