C语言之指针详解(8)

目录
本章重点
1. 字符指针
2. 数组指针
3. 指针数组
4. 数组传参和指针传参
5. 函数指针
6. 函数指针数组
7. 指向函数指针数组的指针
8. 回调函数
9. 指针和数组面试题的解析
指针和数组笔试题解析
#include<stdio.h>
int main()
{
	//一维数组
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(a + 0));
	printf("%d\n", sizeof(*a));
	printf("%d\n", sizeof(a + 1));
	printf("%d\n", sizeof(a[1]));
	printf("%d\n", sizeof(&a));
	printf("%d\n", sizeof(*&a));
	printf("%d\n", sizeof(&a + 1));
	printf("%d\n", sizeof(&a[0]));
	printf("%d\n", sizeof(&a[0] + 1));
	return 0;
}
大家可以试着先分析一下结果是多少,分析错了不要紧,我逐个逐个给大家解释
首先这是一个数组,里面放的都是整型数据
数组元素的总大小是16个字节
sizeof(数组名)--数组名表示整个数组
&数组名---数组名表示整个数组
对于第一个sizeof(数组名),计算的是数组的总大小--单位是字节---16
对于第二个sizeof(a+0)结果是4,数组名在这里表示数组首元素的地址,a+0还是首元素的地址,地址的大小就是4/8个字节
对于第三个sizeof(*a)---数组名表示首元素的地址,*a就是首元素,sizeof(*a)就是4
对于第四个sizeof(a+1)--数组名在这里表示首元素的地址,a+1是第二个元素的地址,地址的大小就是4/8个字节
对于第五个sizeof(a【1】)--第二个元素的大小--4
对于第六个sizeof(&a)--&a取出的是数组的地址,但是数组的地址那也是地址,地址的大小就是4/8个字节
对于第七个sizeof(*&a)--16---&a数组的地址,数组的地址解引用访问的数组,sizeof计算的就是数组的大小--单位是字节
对于第八个sizeof(&a+1)--&a是数组的地址,&a+1虽然地址跳过整个数组,但还是地址,所以是4/8个字节
对于第九个sizeof(&a【0】)--&a【0】是第一个元素的地址
对于最后一个sizeof(&a【0】+1)--&a【0】+1是第二个元素的地址
我们把代码结果运行给大家看一下
X86平台演示的结果
X64平台演示的结果

 

下面我们来看字符数组
#include<stdio.h>
int main()
{
	//字符数组
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", sizeof(arr));
	printf("%d\n", sizeof(arr + 0));
	printf("%d\n", sizeof(*arr));
	printf("%d\n", sizeof(arr[1]));
	printf("%d\n", sizeof(&arr));
	printf("%d\n", sizeof(&arr + 1));
	printf("%d\n", sizeof(&arr[0] + 1));
	return 0;
}
我们还是一个一个来分析
对于第一个sizeof(arr)--计算的是数组的大小,6*1=6个字节
对于第二个sizeof(arr+0)--arr是首元素的地址,arr+0还是首元素的地址,地址的大小是4/8个字节
对于第三个sizeof(*arr)--arr是首元素的地址,*arr就是首元素,首元素是字符大小是一个字节
对于第四个sizeof(arr【1】)--1
对于第五个sizeof(&arr)--&arr虽然是数组的地址,但还是地址,地址大小为4/8个字节
对于第六个sizeof(&arr+1)--&arr+1是跳过整个数组后的地址,地址的大小是4/8个字节
对于最后一个sizeof(&arr【0】+1)--第二个元素的地址---4/8个字节
希望大家能够理解,我们把两个代码运行起来给大家看一下
X86平台演示的结果
X64平台演示的结果

 

我们再来看一组代码

#include<stdio.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", strlen(arr));
	printf("%d\n", strlen(arr + 0));
	printf("%d\n", strlen(*arr));
	printf("%d\n", strlen(&arr));
	printf("%d\n", strlen(arr[1]));
	printf("%d\n", strlen(&arr + 1));
	printf("%d\n", strlen(&arr[0] + 1));
	return 0;
}

我们还是给大家讲解一下

对于第一个strlen(求字符串长度)---找不到\0的位置,\0的位置不确定,所以结果打印随机值

对于第二个strlen---1--数组名---首元素的地址,和第一种情况相同---随机值

对于第三个strlen---这里传了个'a'--97过去,他就把97当作一个地址,大家有听说过吗?所以这叫非法访问,是有问题的

对于第四个strlen---同第三个,非法访问,是有问题的

对于第五个strlen----取地址arr---虽然是取出来的是数组的地址,但是数组的地址也是从'a'开始的,所以结果也是随机值

对于第六个strlen---也是随机值,但是随机值跟前面的随机值差6

对于第六个strlen---也是随机值,但是比前面的随机值差1

我们还是把代码运行起来给大家看一下

X86平台演示的结果X64平台演示的结果我们接着来看代码

#include<stdio.h>
int main()
{
	char arr[] = "abcdef";
	printf("%d\n", sizeof(arr));
	printf("%d\n", sizeof(arr + 0));
	printf("%d\n", sizeof(*arr));
	printf("%d\n", sizeof(arr[1]));
	printf("%d\n", sizeof(&arr));
	printf("%d\n", sizeof(&arr + 1));
	printf("%d\n", sizeof(&arr[0] + 1));
	return 0;
}

我们还是来给大家讲解一下

第一个:计算的是数组的大小,单位是字节---7

第二个:计算的是地址的大小,arr+0是首元素的地址

第三个:*arr是首元素,计算的是首元素的大小--1

第四个:arr【1】是第二个元素,计算的是第二个元素的大小

第五个:&arr虽然是数组的地址,但也是地址,所以是4/8个字节

第六个:&arr+1是跳过整个数组后的地址,但也是地址---4/8个字节

第七个:&arr【0】+1是第二个元素的地址--4/8个字节

我们来把代码演示结果给大家展示一下

X86平台演示的结果X64平台演示的结果

我们来看下面的代码

#include<stdio.h>
int main()
{
	char arr[] = "abcdef";
	printf("%d\n", strlen(arr));
	printf("%d\n", strlen(arr + 0));
	printf("%d\n", strlen(*arr));
	printf("%d\n", strlen(arr[1]));
	printf("%d\n", strlen(&arr));
	printf("%d\n", strlen(&arr + 1));
	printf("%d\n", strlen(&arr[0] + 1));
	return 0;
}

还是给大家一个一个讲解一下

第一个:6,字符串的长度

第二个:6,和第一个相同

第三个:非法访问内存,访问97的这个地址,所以是有问题的

第四个:和第三个是一个道理,访问的是'b'--98的地址,属于非法访问,是有问题的

第五个:&arr---数组的地址--strlen的返回类型为const char*,我们正常使用应该使用数组指针---char(*p)7==&arr

第六个:&arr+1把\0也跳过去了,你也不知道后面的字符串有多长,所以结果是随机值

第七个:跳过了a这个字符从b开始往后数,所以长度为5

我们运行代码看一下结果

X86平台演示的结果 X64平台演示的结果

如果大家能够理解,我们继续来看下面的代码

#include<stdio.h>
int main()
{
	char* p = "abcdef";
	printf("%d\n", sizeof(p));
	printf("%d\n", sizeof(p + 1));
	printf("%d\n", sizeof(*p));
	printf("%d\n", sizeof(p[0]));
	printf("%d\n", sizeof(&p));
	printf("%d\n", sizeof(&p + 1));
	printf("%d\n", sizeof(&p[0] + 1));
	return 0;
}

我们还是来解释一下

第一个:计算指针变量p的大小---4/8个字节

第二个:p+1得到的是字符b的地址,地址的大小为4/8个字节

第三个:*p就是字符串的第一个字符,也就是字符a,a为字符--1个字节

第四个:---可以等价等int arr[10]----arr[0]==*(arr+0)    p[0]==*(p+0)=='a',所以还是字符a--大小为1个字节

第五个:计算的地址,地址是4/8个字节

第六个:也是地址,大小为4/8个字节

第七个:b的地址---大小为4/8个字节

我们运行起来看一下效果

X86平台演示的结果

X64平台演示的结果

我们再来看下一个代码

#include<stdio.h>
int main()
{
	char* p = "abcdef";
	printf("%d\n", strlen(p));
	printf("%d\n", strlen(p + 1));
	printf("%d\n", strlen(*p));
	printf("%d\n", strlen(p[0]));
	printf("%d\n", strlen(&p));
	printf("%d\n", strlen(&p + 1));
	printf("%d\n", strlen(&p[0] + 1));
	return 0;
}

第一个:6-从a开始的字符串的长度到\0结束

第二个:5-从b开始的字符串的长度到\0结束

第三个:error--将a的值传过去了

第四个:error--同第三个代码

第五个:地址如果内存分配不同,结果也会不同(涉及大小端知识)--随机值

第六个:也是随机值---取地址加1对于后面的内存,地址的大小我们也不知道,所以是随机值

第七个:5--从第二个元素开始到\0结束

给大家运行代码看一下结果

X86平台演示的结果 

X64平台演示的结果

我们来看最后一个代码

#include<stdio.h>
int main()
{
	//二维数组
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(a[0][0]));
	printf("%d\n", sizeof(a[0]));
	printf("%d\n", sizeof(a[0] + 1));
	printf("%d\n", sizeof(*(a[0] + 1)));
	printf("%d\n", sizeof(a + 1));
	printf("%d\n", sizeof(*(a + 1)));
	printf("%d\n", sizeof(&a[0] + 1));
	printf("%d\n", sizeof(*(&a[0] + 1)));
	printf("%d\n", sizeof(*a));
	printf("%d\n", sizeof(a[3]));
	return 0;
}

我们还是来给大家分析一下

第一个:48

第二个:4

第三个:16--a【0】相当于第一行作为一维数组的数组名,这里计算的是一行的大小

第四个:4---a【0】是第一行的数组名,数组名此时是首元素的地址,a【0】其实是第一行第一个元素的地址,a【0】+1就是第一行第二个元素的地址,地址大小为4/8个字节

第五个:4--*(a【0】+1)是第一行第二个元素,大小是4个字节

第六个:4--a是二维数组的数组名,所以a是首元素的地址,二维数组的首元素是他的第一行,a就是第一行(首元素)的地址,a+1就是第二行的地址

第七个:16---计算的是第二行的大小,单位是字节

第八个:第二行的地址--4

第九个:计算的是第二行的大小,单位是字节

第十个:a是首元素的地址--第一行的地址,*a就是第一行,计算的是第一行的大小

第十一个:16
给大家把代码运行起来看结果

X86平台演示的结果 

X64平台上演示的结果

指针详解的全部知识就给大家讲完了,希望大家能够有所收获

全章终!!!

猜你喜欢

转载自blog.csdn.net/fjj2397194209/article/details/131253158