用试题这把“剑“帮你破除指针与数组之间的那些猫腻

作者主页:paper jie的博客_CSDN博客-C语言,算法详解领域博主

本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。

本文录入于《系统解析C语言》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将C语言基础知识一网打尽,希望可以帮到读者们哦。

其他专栏:《C语言》《算法详解》《C语言-语法篇》

内容分享:本期对C语言中的指针的进阶知识进行进行具体讲解,各位看官姥爷快搬好小板凳坐好叭。

    -------- 不要998,不要98,只要一键三连,三连买不了吃亏,买不了上当

目录

写在前面

指针与一维数组

解析:

代码

指针与字符指针

char arr[] = { 'a','b','c','d','e','f' }

解析 

代码

char arr[] = "abcdef"

分析

代码

char* p = "abcdef"

分析 

代码

指针与二维数组

分析

代码 


写在前面

在开始前我们要注意两个知识点:

1. sizeof(数组名),这里的数组名表示的是整个数组,计算的是整个数组的大小

2. &数组名,这里的数组名表示的是整个数组,取出的是整个数组的大小

3. 除此之外,其他的数组名都是首元素的地址

指针与一维数组

用试题这把“剑“帮你破除指针与数组之间的那些猫腻_第1张图片

解析:

sizeof(a) 计算的是整个数组的大小 。

sizeof(a+0): a不是sizeof(a),也不是&a 所以他是首元素地址 +0,它是1的地址 是一个整型指针 4个字节 。

sizeof(*a): *a就是1 1是一个整型  sizeof(*a) = 4。

sizeof(a+1): a+1 是首元素的地址加一 跳过一个整型,是2的地址 还是一个整型指针 4个字节。 

sizeof(a[1]): a[1]=2 2是整型 4个字节。

sizeof(&a): &a取出的是整个数组 但它本质上还是一个整型指针 4个字节。

sizeof(*&a): &a取出的是整个数组 解引用得到的是整个数组的内容 里面有4个整型。

sizeof(&a+1):  &a+1是跳过这个数组指向后面的内容 但还是一个指针 .。

sizeof(&a[0]): &a[0]是取出a[0]的地址 是一个整型指针。

sizeof(&a[0]+1): &a[0]+1 是a[1]的地址 是一个整型指针.

代码

#include 

int main()
{
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));
	//16
	//sizeof(a) 计算的是整个数组的大小
	printf("%d\n", sizeof(a + 0));
	//4
	//a不是sizeof(a),也不是&a 所以他是首元素地址 +0
	//它是1的地址 是一个整型指针 4个字节 
	printf("%d\n", sizeof(*a));
	//4
	//*a就是1 1是一个整型  sizeof(*a) = 4
	printf("%d\n", sizeof(a + 1));
	//4
	//a+1 是首元素的地址加一 跳过一个整型
	//是2的地址 还是一个整型指针 4个字节
	printf("%d\n", sizeof(a[1]));
	//4
	//a[1]=2 2是整型 4个字节
	printf("%d\n", sizeof(&a));
	//4
	//&a取出的是整个数组 但它本质上还是一个整型指针 4个字节
	printf("%d\n", sizeof(*&a));
	//16
	//&a取出的是整个数组 解引用得到的是整个数组的内容 里面有4个整型
	printf("%d\n", sizeof(&a + 1));
	//4
	//&a+1是跳过这个数组指向后面的内容 但还是一个指针 
	printf("%d\n", sizeof(&a[0]));
	//4
	//&a[0]是取出a[0]的地址 是一个整型指针
	printf("%d\n", sizeof(&a[0] + 1));
	//&a[0]+1 是a[1]的地址 是一个整型指针

	return 0;
}

指针与字符指针

char arr[] = { 'a','b','c','d','e','f' }

用试题这把“剑“帮你破除指针与数组之间的那些猫腻_第2张图片

解析 

arr 是计算整个数组的大小,6个char类型 6

arr+0  首元素地址加0 指向的还是a 它是一个地址就是指针,是指针就是4个字节

*arr arr是首元素的地址,解引用就是a 计算的就是首元素a的大小 char类型 1

arr[1] 是第二个元素,计算的是第二个元素的大小 1

&arr 取出的是整个数组 但它本质是一个char指针 计算的就是一个cha类型的指针r

&arr+1 取出整个数组的地址再加1,跳过整个数组 这是一个指向数组后一个元素的指针 

&arr[0]+1 取出第一个元素的地址加1 就是第二个元素的地址,本质上还是一个指针 

strlen(arr) arr是首元素地址 计算的是arr数组元素的个数,从第一个元素开始计算在遇到\0不会停止,arr数组没有\0 它是一个随机值

strlen(arr+0) arr+0是首元素的地址 从第一个元素开始计算到\0停止 arr数组没有\0 随机值

strlen(*arr) 是第一个元素是一个字符 但是strlen函数的参数需要一个指针类型 所以err

strlen(arr[1]) arr[1]是一个字符 不合strlen需要的参数

strlen(&arr) 取出的是整个数组 本质上还是一个指针,等于首元素的地址,arr数组里没有\0 它是一个随机值

strlen(&arr+1) &arr+1是跳过整个数组,指向数组后面的内容  从这里开始计算,遇到\0停止 随机 

strlen(&arr(&arr[0]+1) &arr[0]+1取出第二个元素的地址 从第二个元素开始计算,遇到\0停止 随机 

代码

	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", sizeof(arr));
	//6
	//arr 是计算整个数组的大小,6个char类型 6
	printf("%d\n", sizeof(arr + 0));
	//arr+0  首元素地址加0 指向的还是a 它是一个地址就是指针,是指针就是4个字节
	printf("%d\n", sizeof(*arr));
	//1
	//*arr arr是首元素的地址,解引用就是a 计算的就是首元素a的大小 char类型 1
	printf("%d\n", sizeof(arr[1]));
	//1
	//arr[1] 是第二个元素,计算的是第二个元素的大小 1
	printf("%d\n", sizeof(&arr));
	//4
	//&arr 取出的是整个数组 但它本质是一个char指针 计算的就是一个cha类型的指针r
	printf("%d\n", sizeof(&arr + 1));
	//4
	//&arr+1 取出整个数组的地址再加1,跳过整个数组 这是一个指向数组后一个元素的指针 
	printf("%d\n", sizeof(&arr[0] + 1));
	//4
	//&arr[0]+1 取出第一个元素的地址加1 就是第二个元素的地址,本质上还是一个指针 
	printf("%d\n", strlen(arr));
	//随机值
	//strlen(arr) arr是首元素地址 计算的是arr数组元素的个数,从第一个元素开始计算在遇到\0不会停止,arr数组没有\0 它是一个随机值
	printf("%d\n", strlen(arr + 0));
	//随机值 
	//strlen(arr+0) arr+0是首元素的地址 从第一个元素开始计算到\0停止 arr数组没有\0 随机值
	printf("%d\n", strlen(*arr));
	//err
	//strlen(*arr) 是第一个元素是一个字符 但是strlen函数的参数需要一个指针类型 所以err
	printf("%d\n", strlen(arr[1]));
	//err
	//strlen(arr[1]) arr[1]是一个字符 不合strlen需要的参数
	printf("%d\n", strlen(&arr));
	//随机值
	//strlen(&arr) 取出的是整个数组 本质上还是一个指针,等于首元素的地址,arr数组里没有\0 它是一个随机值
	printf("%d\n", strlen(&arr + 1));
	//随机值
	//strlen(&arr+1) &arr+1是跳过整个数组,指向数组后面的内容  从这里开始计算,遇到\0停止 随机 
	printf("%d\n", strlen(&arr[0] + 1));
	//strlen(&arr(&arr[0]+1) &arr[0]+1取出第二个元素的地址 从第二个元素开始计算,遇到\0停止 随机 

char arr[] = "abcdef"

用试题这把“剑“帮你破除指针与数组之间的那些猫腻_第3张图片

分析

"abcdef"里面包含的有:a b c d e f \0  

arr sizeof(arr)是计算整个数组的大小 arr数组里面隐藏了\0 ,得算上\0    7

arr+0 是首元素的地址 计算的就是一个地址的大小 4

*arr 是首元素 计算的就是一个char类型 1

arr[1] 是第二个元素 计算的是一个char类型 1

&arr 取出的是整个数组 它是一个地址 计算的就是地址的大小 4

&arr+1 数组的地址+跳过一个数组 它还是一个地址 计算的就是地址 4

&arr[0]+1 是第二个元素的地址 计算的就是地址 4

arr 计算的是整个数组的个数 strlen遇到\0停止 \0不加入计算 6

arr+0 是首元素的地址 它作为给strlen的参数 从首元素开始计算到\0停止 6

*arr *arr是首元素,它不是地址 strlen的参数要指针 所以err

arr[1] 是第二个元素,它不是地址 strlen的参数要指针 所以err

&arr 取出的是整个元素的大小 但它本质上还是和首元素地址一样 所以从首元素开始计算到\0停止 6

&arr+1 就是跳过整个数组,指向后面的空间,也跳过了数组中的\0, 所以从后面的空间开始到\0 是随机的

&arr[0]+1 是第二个元素的地址 就是从第二个元素开始计算到\0停止 5

代码

	char arr[] = "abcdef";
	//里面包含的有:a b c d e f \0 
	printf("%d\n", sizeof(arr));
	//7
	//arr sizeof(arr)是计算整个数组的大小 arr数组里面隐藏了\0 ,得算上\0    7
	printf("%d\n", sizeof(arr + 0));
	//4
	//arr+0 是首元素的地址 计算的就是一个地址的大小 4
	printf("%d\n", sizeof(*arr));
	//1
	//*arr 是首元素 计算的就是一个char类型 1
	printf("%d\n", sizeof(arr[1]));
	//1
	//arr[1] 是第二个元素 计算的是一个char类型 1
	printf("%d\n", sizeof(&arr));
	//4
	//&arr 取出的是整个数组 它是一个地址 计算的就是地址的大小 4
	printf("%d\n", sizeof(&arr + 1));
	//4
	//&arr+1 数组的地址+跳过一个数组 它还是一个地址 计算的就是地址 4
	printf("%d\n", sizeof(&arr[0] + 1));
	//4
	//&arr[0]+1 是第二个元素的地址 计算的就是地址 4
	printf("%d\n", strlen(arr));
	//6
	//arr 计算的是整个数组的个数 strlen遇到\0停止 \0不加入计算 6
	printf("%d\n", strlen(arr + 0));
	//6
	//arr+0 是首元素的地址 它作为给strlen的参数 从首元素开始计算到\0停止 6
	printf("%d\n", strlen(*arr));
	//err
	//*arr *arr是首元素,它不是地址 strlen的参数要指针 所以err
	printf("%d\n", strlen(arr[1]));
	//err
	//arr[1] 是第二个元素,它不是地址 strlen的参数要指针 所以err
	printf("%d\n", strlen(&arr));
	//6
	//&arr 取出的是整个元素的大小 但它本质上还是和首元素地址一样 所以从首元素开始计算到\0停止 6
	printf("%d\n", strlen(&arr + 1));
	//随机值
	//&arr+1 就是跳过整个数组,指向后面的空间,也跳过了数组中的\0, 所以从后面的空间开始到\0 是随机的
	printf("%d\n", strlen(&arr[0] + 1));
	//5
	//&arr[0]+1 是第二个元素的地址 就是从第二个元素开始计算到\0停止 5

char* p = "abcdef"

用试题这把“剑“帮你破除指针与数组之间的那些猫腻_第4张图片

分析 

p p是字符串首元素的地址 计算的就是一个指针 4

p+1 第二个字符的地址 计算的就是一个指针 4

*p 第一个字符 计算的是一个char类型 1

p[0] ==*(p+0) 第一个字符 计算的是一个char类型 1

&p &p是第一个字符的地址的地址 一个二级指针 计算就是一个指针 4

&p+1 是二级指针加1 跳过一个char**类型 还是一个指针 计算就是一个指针 4

&p[0]+1 第二个字符的地址 是一个指针 计算的就是一个指针 4

p 首字符的地址 strlen通过第一个字符地址向后计算,到\0停止

p+1 第二个字符的地址 strlen通过第二个字符地址向后计算 到\0停止

*p 首字符 strlen参数只接收指针 err

p[0] 首字符 strlen参数只接收指针 err

&p 是首元素的地址的地址  strlen计算的是首元素的地址 相当于地址变成了它要计算的内容 里面不知道有没有\0 就是随机值

&p+1 二级指针加1 strlen计算的是首元素的地址加一  它的内容还是一个指针 随机值

&p[0]+1 第二个元素的地址 从第二个元素开始计算遇到\0停止 5

代码

	char* p = "abcdef";
	printf("%d\n", sizeof(p));
	//4
	//p p是字符串首元素的地址 计算的就是一个指针 4
	printf("%d\n", sizeof(p + 1));
	//4
	//p+1 第二个字符的地址 计算的就是一个指针 4
	printf("%d\n", sizeof(*p));
	//1
	//*p 第一个字符 计算的是一个char类型 1
	printf("%d\n", sizeof(p[0]));
	//1
	//p[0] ==*(p+0) 第一个字符 计算的是一个char类型 1
	printf("%d\n", sizeof(&p));
	//4
	//&p &p是第一个字符的地址的地址 一个二级指针 计算就是一个指针 4
	printf("%d\n", sizeof(&p + 1));
	//4
	//&p+1 是二级指针加1 跳过一个char**类型 还是一个指针 计算就是一个指针 4
	printf("%d\n", sizeof(&p[0] + 1));
	//4
	//&p[0]+1 第二个字符的地址 是一个指针 计算的就是一个指针 4
	printf("%d\n", strlen(p));
	//6
	//p 首字符的地址 strlen通过第一个字符地址向后计算,到\0停止
	printf("%d\n", strlen(p + 1));
	//p+1 第二个字符的地址 strlen通过第二个字符地址向后计算 到\0停止
	printf("%d\n", strlen(*p));
	//err
	//*p 首字符 strlen参数只接收指针 err
	printf("%d\n", strlen(p[0]));
	//err
	//p[0] 首字符 strlen参数只接收指针 err
	printf("%d\n", strlen(&p));
	//随机值
	//&p 是首元素的地址的地址  strlen计算的是首元素的地址 相当于地址变成了它要计算的内容 里面不知道有没有\0 就是随机值
	printf("%d\n", strlen(&p + 1));
	//随机值
	//&p+1 二级指针加1 strlen计算的是首元素的地址加一  它的内容还是一个指针 随机值
	printf("%d\n", strlen(&p[0] + 1));
	//5
	//&p[0]+1 第二个元素的地址 从第二个元素开始计算遇到\0停止 5

指针与二维数组

 用试题这把“剑“帮你破除指针与数组之间的那些猫腻_第5张图片

分析

a sizeof(a)是计算整个二维数组的大小 12*4
a[0][0] 第一行的第一个元素 计算一个整型大小 4

a[0] 代表了数组第一行 可以理解为第一行的数组名 sizeof(数组名)整个数组的大小 16

a[0]+1 表示第一行第二个元素的地址 一个指针 4

*(a[0]+1) 表示第一行的第二个元素 一个整型 4

a+1 a是第一行的地址+1 第二行的地址 一个指针 4

*(a+1) 表示第二行的元素 4个整型 16

&a[0]+1 &a[0]是取出第一行的地址在加一 就是第二行的地址 4

*(&a[0]+1)第二行的地址解引用 得到第二行的4个元素 16

*a a是二维数组首元素的地址 就是第一行的地址 解引用 4个整型 16

a[3]  这里我们不管a[3]越界了 我们只要知道它的类型是一个int [4] sizeof求的就是类型 16

代码 

int a[3][4] = { 0 };
printf("%d\n", sizeof(a));
//48
//a sizeof(a)是计算整个二维数组的大小 12*4
printf("%d\n", sizeof(a[0][0]));
//4
//a[0][0] 第一行的第一个元素 计算一个整型大小 4
printf("%d\n", sizeof(a[0]));
//16
//a[0] 代表了数组第一行 可以理解为第一行的数组名 sizeof(数组名)整个数组的大小 16
printf("%d\n", sizeof(a[0] + 1));
//4
//a[0]+1 表示第一行第二个元素的地址 一个指针 4
printf("%d\n", sizeof(*(a[0] + 1)));
//
//*(a[0]+1) 表示第一行的第二个元素 一个整型 4
printf("%d\n", sizeof(a + 1));
//4
//a+1 a是第一行的地址+1 第二行的地址 一个指针 4
printf("%d\n", sizeof(*(a + 1)));
//16
//*(a+1) 表示第二行的元素 4个整型 16
printf("%d\n", sizeof(&a[0] + 1));
//4
//&a[0]+1 &a[0]是取出第一行的地址在加一 就是第二行的地址 4
printf("%d\n", sizeof(*(&a[0] + 1)));
//16
//*(&a[0]+1)第二行的地址解引用 得到第二行的4个元素 16
printf("%d\n", sizeof(*a));
//16
//*a a是二维数组首元素的地址 就是第一行的地址 解引用 4个整型 16
printf("%d\n", sizeof(a[3]));
//16
//a[3]  这里我们不管a[3]越界了 我们只要知道它的类型是一个int [4] sizeof求的就是类型 16

通过这些奇形怪状的试题,我们一步一步的解析,到现在想必大家对与指针与数组已经门清了儿叭!

你可能感兴趣的:(C语言,c语言,开发语言)