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;
}

ps:注意区分a+1与a[0]+1的区别:

a代表二维数组的数组名,二维数组的数组名表示二维数组首元素的地址即第一行的地址

 a[0]是第一行的数组名表示第一行首元素的地址,即第一行第一个的元素,+1为第一行第二个元素。

总结
以上就是今天要讲的内容:

从strlen()函数与操作符sizeof入手结合二维数组,指针,字符数组的角度来理解数组名的意义同时加强对strlen()函数,sizeof,二维数组,指针理解

posted @ 2023-04-03 10:40  Fan_558  阅读(6)  评论(0编辑  收藏  举报  来源