【C语言】指针进阶

大家好啊,因为上个星期生病的原因,没有及时更新,本期这就补上。
本期主要内容是深入解析指针,让大家能够进一步了解指针,希望对各位小伙伴有所帮助!

文章目录

  • 前言
  • 一、指针的基本概念
  • 二、字符指针
  • 三、指针数组
  • 四、数组指针
    • 小知识点——数组名与&数组名
    • 数组指针的使用
    • 小结
  • 五、 数组参数与指针参数
    • 1、一维数组传参
    • 补充知识点
    • 2、二维数组传参
    • 重要知识点
      • 1、void pri(int *p)
      • 2、void pri(int **p)
  • 六、函数指针
    • 1、概念
    • 2、代码
    • 补充
    • 3、两道例题
      • 例题1
      • 例题2
    • 4、计算器
  • 七、函数指针数组
    • 1、概念
    • 2、代码
    • 3、小例子
    • 4、转移表
  • 八、指向函数指针数组的指针
  • 九、回调函数
    • 1、概念
    • 2、qsort函数
      • A、冒泡排序优化
      • B、qsort函数(重点)
        • void*指针
        • qsort排序整型数据类型
        • qsort函数排序结构体数据类型
        • qsort实现冒泡函数
    • 小结
  • 十、指针数组笔试题+讲解
    • 第一组
    • 第二组
    • 第三组(陷阱多)
      • 补充知识点
    • 第四组
      • 补充知识点
    • 第五组
      • 补充知识点
    • 第六组
    • 第七组
    • 第八组
      • 补充知识点
    • 第九组
    • 第十组
    • 第十一组
    • 第十二组
    • 第十三组
    • 第十四组
    • 第十五组
    • 第十六组
  • 总结


前言

	C语言里面的指针可以说是非常重要的了,不管是以后学习数据结构还是什么其他内容,指针是重中之重, 
我本期除了会讲解指针的内容以外,还会有一套指针笔试题的讲解,话不多说,咋们进入正片。

一、指针的基本概念

1、指针其实本质上叫做指针变量,只不过我们为了更方便解读就
口语化式的叫做指针

2、指针在32位平台占4个字节内存大小,在64位平台占8个字节
内存大小


二、字符指针

字符指针的写法为:char *

常用的字符指针写法是:

char ch = 'a';
char* p = &ch;
*p = 'b';
printf("%c\n", ch);

还有一种写法是:

const char ch = "abcdef";
char* p = &ch;

可别小看这两行代码,里面蕴藏着许多内容:
1、这里可不是把abcdef全部放到指针p里面去了,而是把这个定义的字符串首元素a的地址赋给了指针p
【C语言】指针进阶_第1张图片
当有了首元素地址之后,依次向后面打印就可以打印出整个字符串了;
2、这个字符指针的方法使用的时候,字符串“abcdef”是不可以被改变的:
【C语言】指针进阶_第2张图片
这里大家可以看到’a’没有被改为‘w’,并且程序还挂了
【C语言】指针进阶_第3张图片
这是为什么呢?
是因为,这里的“abcdef”是一个常量字符串,常量字符串是不可被修改的。p的权限变大了,因为p没有被修饰,所以p敢改这个字符串,但是程序会死掉,并且出现错误,所以我们才在前面加上一个const,来表明这里的常量字符串,不能被修改。

##  小例题
	char arr1[] = "abcdef";
	char arr2[] = "abcdef";
	char *p1 = "abcdef";
	char *p2 = "abcdef";
	if (arr1 == arr2)
		printf("yes\n");
	else
		printf("no\n");
	if (*p1 == *p2)
		printf("yes\n");
	else
		printf("no\n");

我直接公布答案了哦!
【C语言】指针进阶_第4张图片

是不是有一部分小伙伴们做错了呢?
接下来我们来分析分析:
【C语言】指针进阶_第5张图片

其实很好理解,就是:字符串相同,因为数组不同,所以两个字符串地址不同;而两个指针是指向同一个字符串的,所以两个指针地址相同


三、指针数组

指针数组的本质是一个数组,数组内部存放着指针
它的写法是:
【C语言】指针进阶_第6张图片
在这里插入图片描述

	int* arr1[10];//整型指针数组(也叫一级整型指针数组)
	int* *arr2[10];//二级整型指针数组
	char* arr3[10];//一级字符指针数组
	char* *arr4[10];//二级字符指针数组

四、数组指针

数组指针本质上是一个指针,这个指针指向一个数组
结合上面的指针数组一起来看看:
【C语言】指针进阶_第7张图片

	int arr[5] = {1,2,3,4,5};
	int(*p)[5] = &arr;

【C语言】指针进阶_第8张图片

	int arr[10] = { 0 };
	int (*p)[10] = &arr;

	char* arr2[10] = { 0 };
	char* (*pa)[10] = &arr2;

以上就是数组指针与指针数组的区别,大家可千万不敢搞混了!!!


小知识点——数组名与&数组名

1、一般情况下数组名就是首元素地址
2、在sizeof和&arr的情况下,arr表示整个数组

大家看看两段代码:
【C语言】指针进阶_第9张图片
大家可能会疑惑,接下来我为大家进行讲解:
【C语言】指针进阶_第10张图片
大家只需要记住数组名代表整个数组的情况即可,后面我们有一组列题来专门讲这个数组名知识点的


数组指针的使用

#include
void pri1(int arr[3][5], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}
void pri2(int(*p)[5], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			printf("%d ", p[i][j]);
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
	pri1(arr, 3, 5);
	pri2(arr, 3, 5);
	return 0;
}

大家可以先看看这两段函数代码,我接下来为大家讲讲:
【C语言】指针进阶_第11张图片
【C语言】指针进阶_第12张图片

	int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
	printf("%p\n", arr);
	printf("%p\n", arr + 1);

在这里插入图片描述
可以看到二维数组加1,地址加了20个字节,也就是5个元素,正好就是二维数组的一整行元素

也就是说:

	int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
	pri1(arr, 3, 5);
	pri2(arr, 3, 5);

【C语言】指针进阶_第13张图片


小结

我们来总结一下几个知识点

#include
int main()
{
	int a[5];
	int* b[5];
	int(*c)[5];
	int(*d[10])[5];
	return 0;
}

【C语言】指针进阶_第14张图片
举个例子:
【C语言】指针进阶_第15张图片


五、 数组参数与指针参数

1、一维数组传参

让我们看一组代码:

#include
void test(int arr[])
{}
void test(int arr[10])
{}
void test(int *arr)
{}
void test2(int *arr2[])
{}
void test2(int *arr2[20])
{}
void test2(int **arr2)
{}
int main()
{
	int arr[10] = { 0 };
	int* arr2[20] = { 0 };
	test(arr);
	test2(arr2);
	return 0;
}

大家知道答案吗?我直接公布答案了:
【C语言】指针进阶_第16张图片
答案就是全部正确,大家可能知道1,2,4,5是怎么来的,那大家知道为什么3和4也是正确的吗?
请各位小伙伴们听我详细分解:
【C语言】指针进阶_第17张图片


补充知识点

int *p1//一级指针
int **p2//二级指针
int***p3//三级指针
.
.
.
以此类推

二级指针是用来存放一级指针地址的;三级指针是用来存放二级指针地址的,也是以此类推


2、二维数组传参

#include
void test(int arr[3][5]])
{}
void test(int arr[][5]])
{}
void test(int arr[][])
{}
void test(int *arr)
{}
void test(int *arr[])
{}
void test(int* arr[5])
{}
void test(int(*arr)[5])
{}
void test(int **arr)
{}
int main()
{
	int arr[3][5] = { 0 };
	test(arr);
}

大家知道这些函数接收参数是正确的吗?
【C语言】指针进阶_第18张图片
为什么是以上的答案呢?我们一起来分析分析:
【C语言】指针进阶_第19张图片
注意:上图内容很重要,小伙伴们一定要熟记于心!!!

重要知识点

1、void pri(int *p)

当函数参数是一个指针的时候,实参会是什么数据呢?

1、int arr[10]={0};
    pri(arr);
    可以是一个整型数组数组名
2、int a=10;
    pri(&a);
    可以是一个整型变量的地址
3、int *p=&a;
    pri§;
    可以是一个整型指针

只要是传参的值本质上是一个整型指针就行


2、void pri(int **p)

通过上面的例题我们就可以得知:只要传参本质是一个二级指针就行

1、int n = 10;
 int* p = &n; 	
 int** p1 = &p; 	
 pri(p1); 	
 pri(&p); 

2、指针数组的数组名也可以
    int*parr[10];
    pri(parr)


六、函数指针

1、概念

函数指针是一个指针,该指针指向一个函数,也就是指向函数的指针

2、代码

	int(*p1)[10];//这个是整型数组指针
	char(*p1)[10];//这个是字符数组指针
	int*(*p1)[10];//这个是一个指向存放10个整型指针数组的指针

	//重点来了
	
	int (*p2)(int ,int)//这个就是函数指针
	
#include
int add(int x, int y)
{
	return x + y;
}
void pri(int(*add)(int, int))
{
	int a = 5;
	int b = 5;
	int ret = add(a, b);
	printf("%d\n", ret);
}
int main()
{
	pri(add);
	return 0;
}

【C语言】指针进阶_第20张图片
上面就是函数指针的基础用法。
我们来仔细分析:
【C语言】指针进阶_第21张图片
以上就是函数指针的大体模板,只不过参数部分可以变得很复杂,小伙伴们一定要用心观察。

补充

函数名本质上并不是函数的地址。函数名可以当做函数地址来使用,这是因为发生了隐式转换,我们以后会讲到隐式转换我们可以拿着用。


3、两道例题

例题1

( * ( void ( * ) ( ) ) 0 )( )

哎呀!这是一个什么题啊,很多小伙伴直接懵逼了,别着急,我们一步步来:
【C语言】指针进阶_第22张图片

例题2

	void ( * arr ( int , void ( * ) ( int ) ) ) ( int )

可能又有一部分人不理解这行代码了,我们继续:
【C语言】指针进阶_第23张图片
以上代码有过多重复部分,我们可以进行简化:

	void ( * arr ( int , void ( * ) ( int ) ) ) ( int )
	typedef void(*p)(int);
	p arr(int, p);

这里我们用到了typedef重定义,可能有很多人问了,为什么不是【typedef void(*)(int) p】这样把p定义在最后呢?因为C语言的语法不是这样定义的。【typedef void(p)(int)】就相当于把【typedef void()(int)】重定义为了p。


4、计算器

函数指针有什么用呢?
接下来我们看看函数指针能怎么使用:
首先我们来看看最基础的一个计算器的实现:

#define _CRT_SECURE_NO_WARNINGS
#include
void menu()
{
	printf("*****0.exit*****\n");
	printf("*****1.add *****\n");
	printf("*****2.sub *****\n");
	printf("*****3.mul *****\n");
	printf("*****4.div *****\n");
}
int add(int i, int j)
{
	return i + j;
}
int sub(int i, int j)
{
	return i - j;
}
int mul(int i, int j)
{
	return i * j;
}
int div(int i, int j)
{
	return i / j;
}
int main()
{
	int n = 0;
	int i = 0;
	int j = 0;
	int ret = 0;
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &n);
		switch (n)
		{
		case 0:
				printf("退出程序\n");
				break;
			case 1:
				printf("请输入两个操作数:");
				scanf("%d %d", &i, &j);
				ret = add(i, j);
				printf("%d\n", ret);
				break;
			case 2:
				printf("请输入两个操作数:");
				scanf("%d %d", &i, &j);
				ret = sub(i, j);
				printf("%d\n", ret);
				break;
			case 3:
				printf("请输入两个操作数:");
				scanf("%d %d", &i, &j);
				ret = mul(i, j);
				printf("%d\n", ret);
				break;
			case 4:
				printf("请输入两个操作数:");
				scanf("%d %d", &i, &j);
				ret = div(i, j);
				printf("%d\n", ret);
				break;
			default:
				printf("选择错误,请重新选择\n");
				break;
		}
	} while (n);
	return 0;
}

【C语言】指针进阶_第24张图片
可以看到一个简单的计算器已经实现了,但是有很多代码重复了:
【C语言】指针进阶_第25张图片
能不能更简单一点呢?
答案是可以的!

#include
void menu()
{
	printf("*****0.exit*****\n");
	printf("*****1.add *****\n");
	printf("*****2.sub *****\n");
	printf("*****3.mul *****\n");
	printf("*****4.div *****\n");
}
int add(int i, int j)
{
	return i + j;
}
int sub(int i, int j)
{
	return i - j;
}
int mul(int i, int j)
{
	return i * j;
}
int div(int i, int j)
{
	return i / j;
}
void calc(int(*p)(int ,int ))//函数指针(计算器)
{
	int i = 0;
	int j = 0;
	int ret = 0;
	printf("请输入两个操作数:");
	scanf("%d %d", &i, &j);
	ret = p(i, j);
	printf("%d\n", ret);
}
int main()
{
	int n = 0;
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &n);
		switch (n)
		{
		case 0:
			printf("退出程序\n");
			break;
		case 1:
			calc(add);
			break;
		case 2:
			calc(sub);
			break;
		case 3:
			calc(mul);
			break;
		case 4:
			calc(div);
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (n);
	return 0;
}

【C语言】指针进阶_第26张图片
可以看出代码变得更简单了,函数变得不那么冗余了。当然还可以让这个代码变得更简洁,我们下面将


七、函数指针数组

1、概念

函数指针数组是一个数组,数组里面的元素都是函数指针。所以函数指针数组是一个存放函数指针的数组。


2、代码

int( * p [10] )( )

【C语言】指针进阶_第27张图片


3、小例子

#include
void menu()
{
	printf("*****0.exit*****\n");
	printf("*****1.add *****\n");
	printf("*****2.sub *****\n");
	printf("*****3.mul *****\n");
	printf("*****4.div *****\n");
}
int add(int i, int j)
{
	return i + j;
}
int sub(int i, int j)
{
	return i - j;
}
int mul(int i, int j)
{
	return i * j;
}
int div(int i, int j)
{
	return i / j;
}
int main()
{
	int(*p[4])(int, int) = { add,sub,mul,div };
	int i = 0;
	for (i = 0; i < 4; i++)
	{
		int ret = p[i](8, 4);
		printf("%d\n", ret);
	}
	return 0;
}

【C语言】指针进阶_第28张图片
可以看到将函数指针放到数组里面是很便捷的,接下来运用一下函数指针数组

4、转移表

上面我们做了一个简单的计算器,但是当计算器需要计算各种方法的时候(比如说取余,异或,按位,移位)难道要一个个的调用函数指针吗?
其实不用那么麻烦

#include
void menu()
{
	printf("*****0.exit*****\n");
	printf("*****1.add *****\n");
	printf("*****2.sub *****\n");
	printf("*****3.mul *****\n");
	printf("*****4.div *****\n");
	printf("*****5.qy  *****\n");
	printf("*****6.awy *****\n");
	printf("*****7.awh *****\n");
	printf("*****8.yh  *****\n");
	printf("*****9.ljy *****\n");
	printf("*****10.ljh*****\n");
	printf("*****11.zy *****\n");
	printf("*****12.yy *****\n");
}
int add(int i, int j)
{
	return i + j;
}
int sub(int i, int j)
{
	return i - j;
}
int mul(int i, int j)
{
	return i * j;
}
int div(int i, int j)
{
	return i / j;
}
int qy(int i, int j)
{
	return i % j;
}
int awy(int i, int j)
{
	return i & j;
}
int awh(int i, int j)
{
	return i | j;
}
int yh(int i, int j)
{
	return i ^ j;
}
int ljy(int i, int j)
{
	return i && j;
}
int ljh(int i, int j)
{
	return i || j;
}
int zy(int i, int j)
{
	return i << j;
}
int yy(int i, int j)
{
	return i >> j;
}
void calc(int (*pfarr)(int,int))
{
	int n = 0;
	int i = 0;
	int j = 0;
	int ret = 0;
	printf("请输入两个操作数:");
	scanf("%d %d", &i, &j);
	ret = pfarr(i, j);
	printf("%d\n", ret);
}
int main()
{
	int n = 0;
	int(*pfarr[])(int, int) = { 0,add,sub,mul,div,qy,awy,awh,yh,ljy,ljh,zy,yy };
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &n);
		if (n == 0)
		{
			printf("退出程序\n");
		}
		else if (n >= 1 && n <= 12)
		{
			calc(pfarr[n]);
		}
		else
		{
			printf("选择错误\n");
		}
	} while (n);
	return 0;
}

【C语言】指针进阶_第29张图片
【C语言】指针进阶_第30张图片
可以看到函数指针数组的使用很方便


八、指向函数指针数组的指针

很多人看到这个名字就已经晕了,其实我们仔细分析会发现不难理解

int(*p[10])()

int ( * ( * parr ) [5] )( ) = &p

【C语言】指针进阶_第31张图片

我们只需要了解指向函数指针数组的指针是什么样子就行,不用深究。当然,相信各位小伙伴们已经发现了,这个东西又是一个指针,我们又可以放到一个数组里面,像这样一直套娃下去…


九、回调函数

1、概念

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。


2、qsort函数

A、冒泡排序优化

#include
void bubble(int* arr, int sz)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < sz - 1; i++)//一共要排序多少躺
	{
		int flag = 1;//假设原来的数组内容已经是正确的顺序了
		for (j = 0; j < sz - 1 - i; j++)//一趟排序是怎么样的
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				flag = 0;//如果flag等于0那么就表示数组内容顺序有问题,已经排序完一次了
			}
		}
		if (flag == 1)//如果顺序没有问题就退出
		{
			break;
		}
	}
}
int main()
{
	int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble(arr, sz);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

上面的冒泡排序我们已经就行优化了,但是不管再怎么优化也只能排列整型数据,能排浮点型、字符、结构体类型的数据吗?
显而易见是不能的,那么就要用到我们的qsort函数了

B、qsort函数(重点)

qsort函数就是快速排序
【C语言】指针进阶_第32张图片
上图中是qsort函数的具体内容,需要引头文件stdlib.h
qsort函数4个内容:
1、排序内容的起始地址;
2、待排序的元素个数;
3、待排序元素字节大小;
4、排序的方法
注:qsort默认是排升序的
下面我们会用qsort来排序整型数据和结构体数据


void*指针

void*是无具体类型的指针,可以接受任意类型的地址
void*是无具体类型的指针,所以不能解引用操作和+-整数的操作

qsort排序整型数据类型

#include
#include
int cmp(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}
int main()
{
	int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

【C语言】指针进阶_第33张图片

可以看出用了qsort函数之后结果不仅正确了,而且还节约时间,空间,可以说是非常方便了。


qsort函数排序结构体数据类型

#include
#include
#include
struct stu
{
	char name[20];
	int age;
};
int cmp_by_name(const void* e1,const void* e2)
{
	return   strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
}
int cmp_by_age(const void* e1, const void* e2)
{
	return   ((struct stu*)e1)->age - ((struct stu*)e2)->age;
}
void test2()
{
	struct stu s[] = { {"zhangsan",15}, {"lisi",30} ,{"wangwu",20} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_by_name);
	qsort(s, sz, sizeof(s[0]), cmp_by_age);
}
int main()
{
	test2();//排序结构体数据
	return 0;
}

我们来看看结果:
名字排序:
【C语言】指针进阶_第34张图片
年龄排序:
【C语言】指针进阶_第35张图片
可以看到qsort把结构体的数据已经排序出来了,由此可见qsort的强大之处。


qsort实现冒泡函数

#include
void swap(char* b1, char* b2, int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *b1;
		*b1 = *b2;
		*b2 = tmp;
		b1++;
		b2++;
	}
}
void bubble(void*base,int sz,int width,int (*cmp)(const void* e1,const void* e2))
{
	int i = 0;
	int j = 0;
	int flag = 1;//假设原来的数组内容已经是正确的顺序了
	for (i = 0; i < sz - 1; i++)
	{
		for (j = 0; j < sz - 1 - i; j++)
		{
			//if (arr[j] > arr[j + 1])
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width)>0)
			{
				swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
				flag = 0;//如果flag等于0那么就表示数组内容顺序有问题,已经排序完一次了
			}
		}
		if (flag == 1)//如果顺序没有问题就退出
		{
			break;
		}
	}
}
int cmp(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}
void test3()
{
	int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble(arr, sz, sizeof(arr[0]), cmp);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
int main()
{
	test3();
	return 0;
}

【C语言】指针进阶_第36张图片


小结

到目前为止,我们的指针进阶的内容基本上完成了,但是可没有结束哦!下面有几组笔试指针题目,有许多小陷阱,欢迎大家挑战哦!我也会为大家进行讲解的!


十、指针数组笔试题+讲解

我们不多说废话,直接题目+答案+讲解

第一组

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

【C语言】指针进阶_第37张图片
【C语言】指针进阶_第38张图片


第二组

#include
int main()
{
	char a[] = { 'a','b','c','d','e','f' };
	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;
}

【C语言】指针进阶_第39张图片
【C语言】指针进阶_第40张图片


第三组(陷阱多)

补充知识点

strlen遇到\0才停止,\0不是字符串的内容,\0只是结束标志

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

这一组题有许多陷阱,不能直接编译出结果,我为大家一一讲解:
【C语言】指针进阶_第41张图片
可以看到还是有很多陷阱的,小伙伴们以后别像小编一样粗心大意哦!


第四组

补充知识点

sizeof计算字符串的时候会把\0算进去,因为\0也占了空间位置

#include
int main()
{
	char a[] = "abcdef";
	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));
	printf("%d\n", sizeof(&a + 1));
	printf("%d\n", sizeof(&a[0] + 1));
	return 0;
}

【C语言】指针进阶_第42张图片
【C语言】指针进阶_第43张图片


第五组

补充知识点

char a[]=“”;[]未表明个数,双引号定义字符串的时候会默认带上\0。前提是方括号【】内的数字也就是空间足够大

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

这一组代码也有陷阱,没有具体答案哦:
【C语言】指针进阶_第44张图片

其实只要找到双引号自带\0就很简单啦!


第六组

#include
int main()
{
	char* a = "abcdef";
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(a + 1));
	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[0] + 1));
	return 0;
}

}

【C语言】指针进阶_第45张图片
【C语言】指针进阶_第46张图片


第七组

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

直接分析:
【C语言】指针进阶_第47张图片


第八组

补充知识点

我们之前说过二维数组数组名代表的就是第一行数组的地址

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

【C语言】指针进阶_第48张图片
【C语言】指针进阶_第49张图片


第九组

#include
int main()
{
	int a[5] = { 1,2,3,4,5 };
	int* ptr = (int*)(&a + 1);
	printf("%d,%d", *(a + 1), *(ptr - 1));
	return 0;
}

【C语言】指针进阶_第50张图片
画个图就解决了:
【C语言】指针进阶_第51张图片


第十组

#include
struct stu
{
	int num;
	char* a;
	short date;
	char b[2];
	short arr[4];
}*p;
int main()
{
	p = (struct stu*)0x100000;
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);
	return 0;
}

【C语言】指针进阶_第52张图片


第十一组

#include
int main()
{
	int a[4] = { 1,2,3,4 };
	int* p1 = (int*)(&a + 1);
	int* p2 = (int*)((int)a + 1);
	printf("%x,%x", p1[-1], *p2);
	return 0;
}

【C语言】指针进阶_第53张图片


第十二组

#include
int main()
{
	int a[3][2] = { (0,1),(2,3),(4,5) };
	int* p;
	p = a[0];
	printf("%d\n", p[0]);
	return 0;
}

这个题其实很简单:
【C语言】指针进阶_第54张图片


第十三组

#include
int main()
{
	int a[5][5];
	int(*p)[4];
	p = a;
	printf("%p,%d\n",&p[4][2]-&a[4][2], &p[4][2] - &a[4][2]);
	return 0;
}

【C语言】指针进阶_第55张图片


第十四组

#include
int main()
{
	int a[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
	int* arr1 = (int*)(&a + 1);
	int* arr2 = (int*)(*(a + 1));
	printf("%d,%d\n", *(arr1 - 1), *(arr2 - 1));
	return 0;
}

【C语言】指针进阶_第56张图片


第十五组

#include
int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);
	return 0;
}

【C语言】指针进阶_第57张图片


第十六组

#include
int main()
{
	char* c[] = { "ENTER","NEW","POINT","FIRST" };
	char** cp[] = { c + 3,c + 2,c + 1,c };
	char*** cpp = cp;
	printf("%s\n", **++cpp);
	printf("%s\n", *--*++cpp+3);
	printf("%s\n", *cpp[-2]+3);
	printf("%s\n", cpp[-1][-1]+1);
	return 0;
}

这一题小编在本子上做了,有点乱,大家可以自己做做这道题:

【C语言】指针进阶_第58张图片
【C语言】指针进阶_第59张图片


总结

本章花费了小编好几天时间,干货还是有的,希望能够给各位小伙伴带来新的收获,同时希望各位观众能够点点赞,最后一道题可能一些观众不理解,如果不理解的话可以私信小编,小编为为你详细解答的,希望各位小伙伴能够与小编一起进步,我们下期见啦!

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