当前位置: 首页 > news >正文

10.指针进阶

这里写目录标题

  • 1. 字符指针
  • 2. 指针数组
  • 3. 数组指针
    • 3.1 int (\*p)\[10\];
    • 3.2 arr; &arr\[ \]; &arr.
    • 3.3 数组指针的使用
  • 4. 数组传参和指针传参
    • 4.1 一维数组传参
    • 4.2 二维数组传参
    • 4.3 一级指针传参
    • 4.4 二级指针传参
  • 5. 函数指针

1. 字符指针

int main()  
{  
	char ch = 'w';  
	char *pc = &ch;//pc就是字符指针
	*pc = 'a';  
	return 0;  
}
int main()
{
	char arr[] = "abcdef";
	//[a b c d e f \0]
	const char* p = "abcdef";//常量字符串
	//把首字符a的地址赋值给p
	//p指向a的地址
	printf("%s\n", p);
	printf("%c\n", *p);
	return 0;
}
abcdef
a

分析代码

int main()
{
	char str1[] = "hello RuaRua.";
	char str2[] = "hello RuaRua.";
	const char* str3 = "hello RuaRua.";
	const char* str4 = "hello RuaRua.";
	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 and str2 are not same
str3 and str4 are same
  • C/C++会把常量字符串存储到单独的一个内存区域,str3str4 是指向常量字符串的指针,它们指向的是存储在静态存储区只读部分的字符串常量 "hello RuaRua.",这个字符串常量与 str1str2 中存储的字符串虽然内容相同,但在内存中是不同的存储位置。

2. 指针数组

int* arr1[10]; //存放  整形指针  的数组  
char *arr2[10]; //存放  一级字符指针  的数组  
char **arr3[10];//存放  二级字符指针  的数组

eg.模拟二维数组

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };
	int* arr[3] = { 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;
}
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7

3. 数组指针

3.1 int (*p)[10];

int (*p)[10];
//p是数组指针变量,指向的是数组

3.2 arr; &arr[ ]; &arr.

int main()
{
	int arr[10] = { 0 };
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);
	printf("%p\n", &arr);
	printf("%d\n", sizeof(arr));
	return 0;
}
008ff858    arr     是数组首元素地址
008ff858    &arr[0] 是数组首元素地址
008ff858    &arr    是整个数组地址
40          sizeof(arr)   计算整个数组大小,arr表示整个数组
名称类型
arr0x008ff858 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}int[10]
&arr[0]0x008ff858 {0}int *
&arr0x008ff858 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}int(*)[10]
int main()
{
	int arr[10] = { 0 };
	printf("%p\n", arr);
	printf("%p\n", arr+1);
	printf("%p\n", &arr[0]);
	printf("%p\n", &arr[0]+1);
	printf("%p\n", &arr);
	printf("%p\n", &arr+1);
	return 0;
}
00F3F840
00F3F844
00F3F840
00F3F844
00F3F840
00F3F868-->0x28-->40
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	//把数组arr的地址赋值给数组指针变量p 
	//int[10] * p = &arr;//err
	int(*p)[10] = &arr;//p是数组指针,存放数组地址
	return 0;
}
arr   的类型是 int [10]
p     的类型是 int(*)[10]
&arr  的类型是 int(*)[10]

3.3 数组指针的使用

一般在二维数组中使用,常规写法:

void Print(int arr[3][5], int r, int c)//row,column
{
	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;
}

二维数组,每一行可以理解为数组的一个元素
每一行是一个一维数组
二维数组是 一维数组的数组

arr -->首元素地址
    -->第一行地址
    -->一维数组地址
void Print(int(*p)[5], int r, int c)
{
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			printf("%d ", *(*(p + i) + j));
		}
		printf("\n");
	}
}
(p + i):指针移动到i数组
*(p + i):i数组的地址
(*(p + i) + j):i数组j元素的地址
*(*(p + i) + j):得到元素

4. 数组传参和指针传参

4.1 一维数组传参

void test1(int arr[5], sz)
{}
void test2(int* p, sz)
{}
int main()
{
	int arr[5] = { 0 };
	test1(arr, 5);
	test2(arr, 5);
	return 0;
}

4.2 二维数组传参

void test1(int arr[3][5], int r, int c)
{}
void test2(int(*p)[5], int r, int c)
{}
int main()
{
	int arr[3][5] = {0};
	test1(arr, 3, 5);
	test2(arr, 3, 5);
	return 0;
}

int arr[3][5]:是二维数组类型的形参,虽然写成 int arr[3][5] ,但实际上会退化为指向包含 5int 类型元素的数组的指针,即 int (*)[5] 类型。
int (*p)[5]:是指针类型的形参,p 是一个指向包含 5int 类型元素的数组的指针。和 int arr[3][5] 本质上是等价的,都用于接收二维数组的首地址,即第一行的地址。

4.3 一级指针传参

void print(int* p, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d\n", *(p + i));
	}
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9 };
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	//一级指针p,传给函数
	print(p, sz);
	return 0;
}

当函数的参数为一级指针,函数能接收什么参数?

void test(int* p)//函数能接收什么参数?
{ }
int n = 0;
int *ptr = &n;
int arr[] = "abcdef";
test (ptr);
test (&n);
test (arr);

4.4 二级指针传参

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

当函数的参数为二级指针的时候,可以接收什么参数?

void test(int** p)
{ }
int main()
{
	int n = 10;
	int* p = &n;
	int** pp = &p;
	int* arr[10];
	test(&p);
	test(pp);
	test(arr);
	return 0;
}

5. 函数指针

void test()
{
	printf("hehe\n");
}
int main()
{
	printf("%p\n", test);
	printf("%p\n", &test);
	return 0;
}
006013B6
006013B6
test和&test都是函数地址

eg

void test(char* pc, int arr[10])
{ }
int main()
{
	void (*pf)(char*, int arr[]) = test;
	return 0;
}

eg

int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int arr[10] = { 0 };
	int(*pa)[10] = &arr;//类比
	int(*pf)(int, int) = &Add;
	//pf是函数指针变量
	return 0;
}

使用指针调用函数

int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int(*pf)(int, int) = &Add;
	int r = Add(3, 5);
	printf("%d\n", r);
	int m = (*pf)(4, 5);
	//--> int m = pf(4, 5);
	//pf和Add一回事
	printf("%d\n", m);
	return 0;
}

eg1.代码分析

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

void (*p)()-->p是函数指针
void (*)() -->函数指针类型
(void (*)())0-->强制类型转换, 0转换成 void (*)()0的地址中存放着这个函数
*(void (*)())0-->解引用,调用这个函数
(*(void (*)())0)()-->调用时无参数
(*(void (*)())0)();-->调用0地址处的函数

eg2.代码分析

void (*signal(int , void(*)(int)))(int);

void (*p)(int); -->函数指针
void(*)(int)-->函数指针指向一个int类型的参数,返回类型void
signal(int , void(*)(int))--> signal 函数(类型 int ,函数指针类型 void(*)(int))

简化

//typedef重定义
typedef unsigned int uint;
typedef int* ptr_t;

typedef int(*parr_t)[10];
typedef int(*pf_t)(int,int);

int main()
{
	uint u1;
	ptr_t p1;
	int* p2;
	return 0;
}
void (*signal(int , void(*)(int)))(int);
--->
	typedef void(*pf_yt)(int);
	//void (*signal(int, void(*)(int)))(int);
	pf_yt signal(int, pf_yt);

相关文章:

  • Ragflow与Dify之我见:AI应用开发领域的开源框架对比分析
  • 清华大学Deepseek第六版AIGC发展研究3.0(共186页,附PDF下载)
  • java项目之基于ssm的学籍管理系统(源码+文档)
  • leaflet扩展插件esri-leaflet.js
  • vue3中展示markdown格式文章的三种形式
  • Solana 核心概念全解析:账户、交易、合约与租约,高流量区块链技术揭秘!
  • kan与小波,和不知所云的画图
  • 【Python】使用Python合并多个CSV文件
  • 【算法学习之路】4.简单数论(4)
  • (转)SpringBoot和SpringCloud的区别
  • 总结前端常用数据结构 之 队列篇【JavaScript 】
  • 数据库操作命令详解:CREATE、ALTER、DROP 的使用与实践
  • 探秘《矩阵之美》:解锁矩阵的无限魅力
  • 【在线用户监控】在线用户查询、强退用户
  • 7.1.1 计算机网络的组成
  • Q-Former 的设计与应用
  • (十 三)趣学设计模式 之 模版方法模式!
  • C++动态与静态转换区别详解
  • games101 作业5
  • 软件工程---净室软件工程
  • 网站正在建设代码/seo薪酬
  • 零售网站建设/网络培训心得体会5篇
  • 网站建设有那些/百度小说排行榜前十名
  • 用html做网站代码/营销策划公司排名
  • 办公用品网站模板/营销软件排名
  • 做搜狗手机网站优化排/教育培训机构管理系统