玩转指针(3)

一、字符指针变量

字符指针变量(如char* p)的两种赋值方式

①将字符类型地址赋值给字符指针变量
c 复制代码
int main()
{
	char a = 'w';
	char* p = &a;
	*p = 'm';
	return 0;
}
②将常量字符串赋值给字符指针变量
常量字符串的介绍:用" "引起来的就是常量字符串,常量字符串存放在只读数据区,这块区域的内容是可以用的,但是不能被修改的。
一道关于字符指针变量的面试题


二、数组指针变量

①何为数组指针变量

字符指针变量(如char * p),p中存放的是字符变量的地址,p指向的是字符;整型指针变量(如int * p),p中存放的是整型变量的地址,p指向的是整型。同理,数组指针变量存放的是数组的地址(&数组名),它指向的是数组。
小练习:正确书写数组指针变量

②数组指针变量的使用

但这种写法不常见,通常不会这么写

③区分指针数组与数组指针

三、二维数组传参的本质

①二维数组的数组名

二维数组的每一行可以看做是一个一维数组,即二维数组是由一维数组组成的数组。二维数组的首元素就是它的第一行,因此二维数组的数组名就是数组第一行的地址。

②二维数组中的元素在内存中是连续存放的

③二维数组传参

二维数组传参时,实参写数组名,形参既可以写成数组的形式(此时二维数组的行的大小可以省略),也可以写成指针的形式。
a、形参写成指针的形式
b、形参写成数组的形式
c、补充
arr[i]==*(arr+i)
arr[i][j]==* (*(arr+i)+j) 。

四、函数指针变量

①函数地址的介绍:

数组有地址,变量(如int a)也有地址,那么函数有地址吗?答案是有的。函数的地址是存放在函数指针变量中的。&(函数名)与函数名均表示函数的地址,两者没有区别。 这点与数组不同:&(数组名)表示取出整个数组的地址,数组名表示数组首元素的地址。

② 函数指针变量的创建

函数指针变量是用来存放函数的地址
c 复制代码
int Add(int x, int y)
{
	return x + y;
}

int main()
{
	int(*pa)(int, int) = Add;//或者写成int(*pa)(int x,int y)=Add;
	//*表示pa是指针变量(函数指针变量),存放的是函数Add的地址。pa指向的函数的返回类型为int,函数的两个参数也是int类型
	//pa的类型是int(*)(int, int)

    //*pa表示通过pa中Add的地址,调用Add函数
	int ret1 = (*pa)(3, 5);
	printf("%d\n", ret1);//8

	//一般调用Add函数的方式
	int ret2 = Add(3, 5);//这里的Add是函数名,也就是函数的地址。pa中存放的也是函数的地址,故可以将这里的Add换成pa
	ret2 = pa(3, 5);
	return 0;
}
总结:可以通过函数名(函数的地址)来调用函数,也可以通过对函数指针变量解引用来调用函数。

五、typedef关键字

①作用

用于对变量类型(如int、int*)重新命名,将复杂类型的名字简单化。
c 复制代码
//比如觉得unsigned int这个类型比较复杂,那么就可以使用typedef将该类型重命名为unit 
typedef unsigned int unit;
int main()
{
	unsigned int a = 1;//等价于unit a=1;
	return 0;
}

②typedef关键字的使用

c 复制代码
typedef int* ptr_t;
int main()
{
	ptr_t a;//等价于int* a;
	return 0;
}

③typedef在重命名数组指针类型和函数指针类型时,稍微有点不同

a.typedef在重命名数组指针类型
c 复制代码
typedef int(*parr)[5];//将数组指针类型int(*)[5]重命名为parr
//typedef int(*)[5]  parr    这种写法是错误的
int main()
{
	int arr[5] = { 0 };
	int(*p)[5] = &arr;//数组指针p的类型是int(*)[5]
	parr m = &arr;
	return 0;
}
b.typedef重命名函数指针类型
c 复制代码
typedef int (*pf)(int, int);//将函数指针类型int (*)(int, int)重命名为pf
//typedef int (*)(int, int)  pf   这种写法是错误的

int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int (*p)(int, int) = Add;//p是函数指针变量,它的类型是int (*)(int, int)
	pf p2 = Add;
	return 0;
}

六、函数指针数组

①函数指针数组是用来存放函数指针或者函数的地址。(函数指针也是用来存放函数的地址,但函数指针只能存放一个函数的地址,而函数指针数组可以存放多个相同类型函数的地址)

②函数指针数组该怎么写呢?

先写出函数指针变量,然后对函数指针变量进行使当的修改,就是函数指针数组。
c 复制代码
int Add(int x, int y)
{
	return x + y;
}

int Sub(int x, int y)
{
	return x - y;
}

int Mul(int x, int y)
{
	return x * y;
}

int Div(int x, int y)
{
	return x / y;
}
int main()
{
	int(*p)(int, int) = Add;//p是函数指针变量,p所指向的函数的返回类型是int,函数的两个参数的类型也是int
	int(* p1[4])(int, int) = { Add,Sub,Mul,Div };//p1是函数指针数组的数组名,数组有4个元素,每个元素的类型都是int(*)(int,int)
	return 0;
}

③函数指针数组的使用

c 复制代码
int Add(int x, int y)
{
	return x + y;
}

int Sub(int x, int y)
{
	return x - y;
}

int Mul(int x, int y)
{
	return x * y;
}

int Div(int x, int y)
{
	return x / y;
}

int main()
{
	int(*p1)(int, int) = Add;
	int(*p2)(int, int) = Sub;
	int(*p3)(int, int) = Mul;
	int(*p4)(int, int) = Div;
	//p1、p2、p3、p4是四个函数指针变量,分别存放四个函数的地址,比较麻烦。
	//观察到这四个函数的类型是一样的,因此可以使用函数指针数组来存放四个函数的地址
	int(*p[4])(int, int) = {Add,Sub,Mul,Div};//p是函数指针数组的数组名,数组有4个元素,每个元素都是int(*)(int,int)类型
	                      //p[0]=Add,p[1]=Sub,p[2]=Mul,p[3]=Div
	for (int i = 0; i < 4; i++)
	{
		printf("%d\n", p[i](6, 3));
	}
	return 0;
}

七、转移表

c 复制代码
/*设计一个简单的计算器,实现整数的加减乘除*/
int Add(int x, int y)
{
	return x + y;
}

int Sub(int x, int y)
{
	return x - y;
}

int Mul(int x, int y)
{
	return x * y;
}

int Div(int x, int y)
{
	return x / y;
}
void menu()
{
	printf("*****    1.Add   2.Sub   *****\n");
	printf("*****    3.Mul   4.Div   *****\n");
	printf("*****    0.exit          *****\n");
}
int main()
{
	int input = 0;
	int x = 0, y = 0, ret = 0;
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
	
		int(*p[5])(int, int) = { 0,Add,Sub,Mul,Div }; //转移表
		if (input >= 1 && input <= 4)
		{
			printf("请输入两个操作数:");
			scanf("%d %d", &x, &y);
			ret = p[input](x, y);
			printf("%d\n", ret);
		}
		else if (input == 0)
		{
			printf("退出计算器\n");
		}
		else
		{
			printf("输入错误,请重新输入\n");
		}

	} while (input);


	return 0;
}
相关推荐
EricWang13582 小时前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端
我是谁??2 小时前
C/C++使用AddressSanitizer检测内存错误
c语言·c++
希言JY3 小时前
C字符串 | 字符串处理函数 | 使用 | 原理 | 实现
c语言·开发语言
午言若3 小时前
C语言比较两个字符串是否相同
c语言
TeYiToKu4 小时前
笔记整理—linux驱动开发部分(9)framebuffer驱动框架
linux·c语言·arm开发·驱动开发·笔记·嵌入式硬件·arm
互联网打工人no15 小时前
每日一题——第一百二十四题
c语言
爱吃生蚝的于勒5 小时前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
羊小猪~~5 小时前
数据结构C语言描述2(图文结合)--有头单链表,无头单链表(两种方法),链表反转、有序链表构建、排序等操作,考研可看
c语言·数据结构·c++·考研·算法·链表·visual studio
洋2405 小时前
C语言常用标准库函数
c语言·开发语言
徐嵌6 小时前
STM32项目---畜牧定位器
c语言·stm32·单片机·物联网·iot