C—指针的进阶(上)


一、字符指针

1.指针就是个变量,用来存放地址,地址唯一标识一块内存空间。
2.指针的大小是固定的4/8个字节(32位平台/64位平台)。
3.指针是有类型,指针的类型决定了指针的±整数的步长,指针解引用操作的时候的权限。
4.指针的运算。

1.字符指针示例

#include<stdio.h>
int main()
{
	char ch = 'w';
	char* pc = &ch;//pc就是字符指针
	char* p = "abcdef";//是把字符串首字符的地址放在p中;这里abcdef是常量字符串不能修改
	*p = 'w';//这种是erro常量字符串不可被修改
	//abcdef这是7个字节了而32平台下字符指针是4个字节所以放不下
	char arr[] = "abcdef";
	char* p = arr;//p指向的是数组的首元素arr数组是可以修改的
	*p = 'w';
	printf("%s", arr);
	return 0;
}

在这里插入图片描述

2.字符指针例题

#include<stdio.h>
int main()
{
	char str1[] = "hello word.";
	char str2[] = "hello word.";
	const char* str3 = "hello word.";
	const char* str4 = "hello word.";
	if (str1 == str2)
	{
		printf("str1 and str2 are same\n");
	}
	else
	{
		printf("str1 and str2 are not same\n");
	}
	if (str3 == str4)
	{
		printf("str3 and str4 are same\n");
	}
	else
	{
		printf("str3 and str4 are not same\n");
	}
	return 0;
}

答案
在这里插入图片描述
解析:因为str1 str2分别是两个不同的空间中hello word.的首元素地址,所以他们的地址肯定也不同所以st1!=str2;假设hello word放在地址0x0012ff40,str3和str4都指向这个地址所以相同,但是&str3!=&str4因为取到的地址是两个不同空间的地址所以就不同了

二、指针数组

对指针数组来说,首先它是一个数组,数组的元素都是指针,也就是说该数组存储的是指针,数组占多少个字节由数组本身决定;

对于语句“intp1[5]”,因为“[]”的优先级要比“”要高,所以 p1 先与“[]”结合,构成一个数组的定义,数组名为 p1,而“int*”修饰的是数组的内容,即数组的每个元素。也就是说,该数组包含 5 个指向 int 类型数据的指针,如图 1 所示,因此,它是一个指针数组。
在这里插入图片描述

在这里插入图片描述
指针数组 - 是数组 - 是一种存放指针的数组

1.示例一:

下列代码就是一个指针数组
在这里插入图片描述

#include<stdio.h>
int main()
{
	char* arr[] = { "abcdef","hehe","qwer" };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		printf("%s\n",arr[i]);
	}
	return 0;
}

在这里插入图片描述

2.示例二

在这里插入图片描述

#include<stdio.h>
int main()
{
	int arr1[] = {1,2,3,4,5};
	int arr2[] = {6,7,8,9,3};
	int arr3[] = { 3,4,5,6,7 };
	//arr是一个存放整形指针的数组
	int* arr[] = { arr1,arr2,arr3 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

在这里插入图片描述

三、数组指针

对数组指针来说,首先它是一个指针,它指向一个数组,也就是说它是指向数组的指针,在 32 位系统下永远占 4 字节,至于它指向的数组占多少字节,这个不能够确定,要看具体情况。
在这里插入图片描述

数组指针 - 是指针 - 是一种指向数组的指针 - 存放的是数组的地址

1.示例一

#include<stdio.h>
int main()
{
	int arr[5];
	int(*p)[5] = &arr;
	return 0;
}

“()”的优先级比“[]”高,“*”号和 p 构成一个指针的定义,指针变量名为 p而 int 修饰的是数组的内容,即数组的每个元素。也就是说,p 是一个指针,它指向一个包含 5 个 int 类型数据的数组

2.示例二

#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int(*p)[10] = &arr;
	int i = 0;
	//p --- &arr
	//*p --- *&arr
	//*p --- arr
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *((*p) + i));
		printf("%d ", (*p)[i]);
	}
	return 0;
}

四、判断指针数组or数组指针

在这里插入图片描述
解析:第一个是整型数组;第二个是指针数组;第三个是数组指针;而第四个parr3是数组,数组中存放的指针,该指针指向的又是数组;也就是说parr3是一个可以存放10个元素的数组,每个元素是一个指针可以指向另一个数组(这个数组是5个元素,每个元素都是int 类型)所以第四个是一个可以存放数组指针的数组
在这里插入图片描述

五、数组传参 、指针参数

1.一维数组的传参

(1).形参为数组

#include<stdio.h>
void print(int arr[10],int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	print(arr, sz);
	return 0;
}

(2).形参为指针(一级指针传参)

当一个函数的参数部分为[级指针的时候,函数能接收什么参数
int a;
print(&a,10);
int
pl = &a;
print(p1,10);
int arr[10];
print(arr,10);
*

#include<stdio.h>
void print(int* str, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(str+i));
	}
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	print(arr, sz);
	return 0;
}

2.二维数组的传参

参数可以是指针,也可以是数组如果是数组,行可以省略,但是列不能省略
如果是指针,传过去的是第一行的地址,形参就应该是数组指针

(1).形参为数组

#include<stdio.h>
void print(int arr[3][5], int row, int col)
{
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j=0;
		for (j = 0; j < 5; 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 };
	print(arr, 3, 5);
	return 0;
}

(2).形参为指针

二维数组的数组名,也表示首元素的地址
二维数组的首元素是第一行
首元素的地址就是第一行的地址,是一个一维数组的地址

*(arr+0) - arr[0][0]

#include<stdio.h>
void print(int (*arr)[5], int row, int col)
{
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; 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 };
	print(arr, 3, 5);
	return 0;
}**

3.二级指针的传参

当函数的参数为二级指针的时候,可以接收什么参数?
test(二级指针变量);
test(一级指针变量的地址);
int
arr[10];test(arr) ;
*


#include<stdio.h>
void test(int** ptr)
{
	printf("num=%d\n", **ptr);
}
int main()
{
	int n = 10;
	int* p = &n;
	int** pp = &p;
	test(pp);
	//test(&p);
	return 0;
}

六、函数指针

(1).函数指针的写法

pf()这是函数,所以要先和 * 结合成为一个指针(*pf)外面再加一个()意思是这个指针指向的是一个函数,而指向这个函数的参数是int,所以就写成了(*pf)(int,int),指向这个函数的返回类型是int,所以最终为int(*pf)(int,int)

(2).调用及代码示例

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	printf("%p\n", &Add);//&函数名得到的就是函数的地址
	printf("%p\n", Add);
	//函数的地址要存起来,就得放在【函数指针变量】中
	int (*pf)(int, int) = Add;//函数名表示函数地址
	//pf是函数指针的变量名
	int ret = (*pf)(3, 5);//这种形式是对的
	//int ret = Add(3, 5);
	int ret = pf(3, 5);//这种形式是对的
	printf("%d\n", ret);
	return 0;
}

根据上述代码可以知道&Add和Add地址一样的和数组是不同的;

(3).示例

1.将0强制类型转换为void ( * )()类型的函数指针
2.这就意味着0地址处放着一个函数,函数没参数,返回类型是void
3.调用0地址处的这个函数

int main()
{
	(*(   void (*)())0   )();
	//void (*)())是一个函数指针类型类似上个代码int (*pf)(int, int)去掉函数指针变量名和函数参数
	//在函数指针类型外面加上()是强制类型转换(void (*)()0)意思是将0强制类型转换
	//加上*意思是对强制类型转换后的解引用
	//最后的()调用时候传参
}

(4).示例

上述的代码是一个函数的声明
函数的名字是signal
signal函数的参数第一个是int类型,第二个是void(
)(int)类型的函数指针,该函数指针指向的函数参数是int,返回类型是void
signal函数的返回类型也是一个函数指针
该函数指针指向的函数参数是int,返回类型是void
*

#include<stdio.h>
int main()
{
void (* signal(int, void(*)(int) ) )(int);
//把这个去掉signal(int, void(*)(int) )
//就变成了void (*  )(int);所以说signal的返回类型也是一个函数指针
return 0
}

七、函数指针数组

(1).代码示例

数组的每个元素是一个函数指针

#include<stdio.h>
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 (*pf[4])(int, int) = { Add,Sub,Mul,Div };
	//pf[4]先和[]结合变成一个数组,数组元素是4个,去掉pf[4]后int (*)(int, int)这是一个函数指针类型
	int i = 0;
	for (i = 0; i < 4; i++)
	{
		int ret = pf[i](8, 4);//pf[i];i为0的时候拿到Add依次往后拿到的是Sub,Mul,Div,然后调用传参。
		printf("%d\n", ret);
	}
	return 0;
}

(2).用函数数组写一个计算器

当不用函数指针数组写的时候:

#include<stdio.h>
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("************************\n");
	printf("**  1.add  **  2.sub  **\n");
	printf("**  3.mul  **  4.div  **\n");
	printf("****0.exit**************\n");
	printf("************************\n");
}
int main()
{
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入两个操作数:>");
			scanf("%d %d", &x, &y);
			ret = Add(x, y);
			break;
		case 2:
			printf("请输入两个操作数:>");
			scanf("%d %d", &x, &y);
			ret = Sub(x, y);
			break;
		case 3:
			printf("请输入两个操作数:>");
			scanf("%d %d", &x, &y);
			ret = Mul(x, y);
			break;
		case 4:
			printf("请输入两个操作数:>");
			scanf("%d %d", &x, &y);
			ret = Div(x, y);
			break;
		case 0:
			printf("退出程序\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
		printf("%d\n", ret);
	} while (input);
	return 0;
}

当用函数指针数组写的时候:

相较于第一种它更简洁

#include<stdio.h>
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("************************\n");
	printf("**  1.add  **  2.sub  **\n");
	printf("**  3.mul  **  4.div  **\n");
	printf("****0.exit**************\n");
	printf("************************\n");
}
int main()
{
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;
	//转移表
	int (*pfArr[5])(int, int) = { NULL,Add,Sub,Mul,Div };
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		if (input >= 1 && input <= 4)
		{
			printf("请输入两个操作数:>");
			scanf("%d %d", &x, &y);
			ret = pfArr[input](x, y);
			printf("%d\n", ret);
		}
		else if (input == 0)
		{
			printf("退出程序\n");
			break;
		}
		else
		{
			printf("选择错误\n");
		}
	} while (input);
	return 0;
}

总结

以上就是对C-指针的进阶中的一部分的简单了解

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小沈YO.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值