王里解扌旨钅十(三)

发布于:2023-10-25 ⋅ 阅读:(105) ⋅ 点赞:(0)

1.字符指针变量

我们知道字符指针是存放字符的指针,那么字符指针是否能存放字符串呢?我们来看一下

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	char* p = "asdfghjkl";

	printf("%c\n", *p);

	return 0;
}

会输出字符串吗?
在这里插入图片描述

可以看到,并不能输出字符串,只输出了字符a
所以得出结论:不是把整一个字符串存入指针变量p中,而是将首元素字符a的地址存储到p中。

既然字符指针在存放字符串的时候存放的是首元素字符的地址,那用指针变量是不是就无法打印出整个字符串呢?我们来看看下面代码

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	char* p = "asdfghjkl";

	printf("%s\n", p);
    //复习:%s的作用:输出字符串中的字符直至字符串中的空字符(字符串以'\0‘结尾,这个'\0'即空字符)

	return 0;
}

运行结果如下
在这里插入图片描述

可以看到,是可以输出整个字符串的

为什么可以仅凭一个首元素字符的地址,就能打印整个字符串呢?
那是因为:字符指针指向字符串的本质是因为字符串是连续存放的,实际上字符指针还是指向首元素"a"的地址,但是因为字符串在内存中是连续存放的,所以当字符指针指向a的时候也能访问字符串中a后面的字符

接下来,再看看下面的代码

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	char* p = "asdfghjkl";

	*p = 'f';
	printf("%s\n", p);

	return 0;
}

这段代码输出了什么?
答案是什么都没输出。
因为“asdfghjkl"是常量字符串,既然是常量,那么就无法被修改,无法被修改但是你指针还要修改他,那么是不是就会出问题,为了防止这个问题出现,我们通常可以在前面加个const,这样就能限制*p无法被修改了

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	const char* p = "asdfghjkl";

	*p = 'f';
	printf("%s\n", p);

	return 0;
}

如下图所示(*p无法被修改):
在这里插入图片描述

2.数组指针

什么是数组指针?数组指针就是存放数组的指针,是一种指针

2.1数组指针变量及其初始化

一、什么是数组指针变量?

数组指针变量就是能够存放数组的指针,能够指向数组的指针变量

int (*p)[10];

这个是什么意思呢?

int (*p)[10]一个一个拆解

* p:p是数组指针变量名,前面带个*,代表p是一个指针
[10]:代表p指向数组的元素个数为10,即p指向数组的元素个数
int :代表p指向的数组元素类型是整型,即p指向的数组的元素类型

注意:为什么不能写成int *p[10],而要写成int (*p)[10]呢?

因为:[]的优先级比*高,那么p会先和[]结合,此时p[]就是一个数组,此时p就是数组名,数组的元素类型是int * 类型,他是一个存放指针的数组,叫做数组指针。
int (*p)[10],此时()优先级最高,那么(*p)代表p是一个指针,(*p)[10]证明p指向的数组的元素个数为10,int (*p)[10]代表p指向的的是一个大小为10的整型数组

二、数组指针变量的初始化

数组指针变量应该如何初始化呢?前面我们说过,&arr,取出的是整个数组的地址,所以我们只需要&arr,然后赋给数组指针变量即可

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	int arr[10] = { 0 };

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


	return 0;
}

通过调试来看:
在这里插入图片描述

可以看到,p存放的是整个arr数组的地址
在这里插入图片描述

2.2二维数组传参的本质

理解了数组指针,就能学习二维数组传参的本质了

首先我们先来复习一下二维数组

2.2.1二维数组

先看图片
在这里插入图片描述

二维数组的每一行都是一个一维数组,我们可以把一维数组看作是二维数组的元素,所以我们也可以认为,二维数组是一个数组,是存放一维数组的数组。

2.2.2二维数组的地址

在这里插入图片描述

我们知道,数组名表示首元素的地址,那么arr是不是就是二维数组的首元素地址呢?
答案是正确的,arr表示首元素地址,我们刚刚讲过,二维数组是存放一维数组的数组,所以arr表示首元素地址,就是第一行一维数组的地址,存放一维数组的地址,我们用指针来存放,既然是数组,我们就用数组指针来存放,一维数组的类型是int [5],那么数组指针类型就是int (*) [5]。这样我们就得到了二维数组传参的本质:二维数组传参本质上传递是地址,这个地址是一维数组的地址,也就是首元素的地址,我们可以将二维数组写成指针的形式,便于我们理解

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void test(int(*arr)[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", *(*(arr + 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} };
	int row = 3;
	int col = 5;
	
	test(arr, row, col);

	return 0;
}

3.函数指针

3.1函数指针变量

我们先来类比一下
整型指针是指向整型的指针,是存放整型地址的指针
数组指针是指向数组的指针,是存放数组地址的指针
那么,
函数指针就是指向函数的指针,是存放函数地址的指针

3.1.1函数指针的创建

既然我们知道函数指针是存放函数的地址的,那么存放函数的地址,就要用到函数指针变量,那么函数指针变量应该如何创建呢?

函数指针的创建:

int (*pf) (int x, int y);
int (*pf) (int, int);
  • (*pf):代表函数指针变量
  • int:函数指针所指向的函数的返回类型
  • (int x, int y):函数指针pf所指向的函数的参数类型以及参数个数的交代
    • 里面的x和y是可以省略的,只需要知道参数类型以及参数个数即可

函数指针的类型:把变量去掉就是函数指针的类型

int (*)(int , int)

3.1.2函数指针的初始化

我们知道了函数指针是怎么创建的,那么接下来我们来看看函数指针是如何初始化的

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int x = 3;
	int y = 4;

	int (*pf)(int, int) = Add;

	int ret = pf(x, y);
	int ret2 = (*pf)(x, y);

	printf("%d\n", ret);
	printf("%d\n", ret2);



	return 0;
}

我们先看这个

int (*pf)(int, int) = Add;

这个就是函数指针的初始化,我们可以直接把Add传给pf,因为Add函数名就代表函数的地址,
我们还可以这样写

int (*pf)(int, int) = &Add;

这样也可以取出函数的地址

然后我们来看一下这段代码的运行结果
运行结果如下:
在这里插入图片描述

我们可以看到,ret和ret2返回的结果都是7,那么就代表这两种用法都是可以通过指针来调用到函数的,(*pf)(x,y)会更清晰,我们一看就知道(*pf)是一个指针变量,解引用一下就可以访问函数的地址,实际上编译器只要知道函数的地址就能调用

3.1.3 typedef关键字

用处:用来类型重命名,可以将复杂的类型简单化

我们可以把函数指针的类型给简单化
如果我们要把上述的int (*)(int, int)类型重命名为pf_t,可以这样写

typedef int (*pf_t)(int, int);
//将int (*)(int, int)重命名为pf_t

然后把上述代码改编一下

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
typedef int (*pf_t)(int, int);
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int x = 3;
	int y = 4;

	pf_t pf = Add;

	int ret = pf(x, y);

	printf("%d\n", ret);

	return 0;
}

3.2函数指针数组

3.2.1函数指针数组的定义

函数指针数组:就是存放函数指针的数组

int (*parr[4])(int ,int);
  • parr先跟[]结合,那么parr[3]就是数组,这个数组的元素类型就是函数指针类型:int(*)(int ,int)

3.2.2函数指针数组初始化

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int Add(int x, int y)
{
	return x + y;
}

int Sub(int x, int y)
{
	return x - y;
}
int main()
{
	int x = 6;
	int y = 4;

	int(*parr[4])(int, int) = { Add, Sub };



	return 0;
}

放在数组里每个元素类型是一样的,所以这个函数指针数组里面的元素类型必须都是int(*)(int , int)

本文含有隐藏内容,请 开通VIP 后查看