前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >深度刨析程序中的指针

深度刨析程序中的指针

作者头像
Yui_
发布于 2024-10-16 00:11:32
发布于 2024-10-16 00:11:32
8900
代码可运行
举报
文章被收录于专栏:Yui编程知识Yui编程知识
运行总次数:0
代码可运行

前面我们已经学习过了指针的一下性质:

  • 指针就是个变量,用来存放地址,地址唯一标识的一块内存空间
  • 指针的大小是固定的4/8个字节(32位平台/64位平台)
  • 指针是有类型,指针的类型决定了指针的加减整数的步长,指针解引用操作时的权限。
  • 两个指针相减返回的是两指针间元素的个数(同类型指针)

1.字符指针

在指针的类型中我们知道有一种指针类型为字符指针char* 一般使用情况

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int main()
{
	char c = 'a';
	char* pc = &c;
	*pc = 'y';
	return 0;
}

还有一种情况

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int main()
{
	const char* str = "hello world";//把"hello world"的首元素的地址给了str
	//但是不能单纯的理解为数组,这里的"hello world"是存放代码区中的不可修改,是常量字符串,所以我们在前面加了const修饰
	printf("%s\n",str);
	return 0;
}
指针
指针

本质就是把常量字符串hello world的首元素的地址放到了str当中,也就是将常量字符串的首元素h的地址放到str中 练习

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int main()
{
	char str1[] = "hello world";
	char str2[] = "hello world";

	const char* str3 = "hello bit";
	const char* str4 = "hello bit";

	if(str1==str2)
		printf("same\n");
	else
		printf("not same\n");
	if(str3==str4)
		printf("same\n");
	else
		printf("not same\n");
	return 0;
}

//打印结果:
/*
not same
same
*/

这里比较的都是地址。 str1和str2都是数组,当用相同的常量字符串去初始化不同的数组的时候就会开辟不同的空间。而str3和str4指向的同一个常量字符串。在c/c++中会把常量字符串单独存储在一个内存区域(代码段),当我们用几个指针去指向同一个字符串时,它们实际会指向同一块内存的。 可以这么理解:str1和str2是可以修改数组中的元素的,如果不同数组间的修改会相互影响,那岂不是乱遭了。而str3和str4是不可以被修改的,那么让它们两指向同一块空间也是完全没有问题的。

2.指针数组

指针数组就是存放指针的数组。 我们可以进行类比: 整型数组是存放整型的数组,字符数组是存放字符的数组。那么指针数组肯定就是存放指针的数组咯。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int* arr1[10];//整型指针的数组
char* arr2[4];//一级字符指针数组
char** arr3[10];//二级字符指针数组

3.数组指针

3.1 数组指针的定义

我们知道整型指针是指向整型的指针(存放整型变量的地址的指针变量) 还有字符指针是指向字符的指针(存放字符变量的地址的指针变量) 如此类比的话 数组指针就是指向数组的指针(存放数组变量的地址的指针变量) 数组指针的正确写法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int *p1[10];//错
int (*p2)[10];//对
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int (*p)[10];
//p与*结合,说明p是一个指针变量,然后指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针。
//加()的原因是因为,根据操作符的优先性,[]的优先级是要高于*的,为了保证*与p的结合需要添加括号

3.2 &数组名与数组名

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int arr[10];

arr&arr分别是什么呢? arr是数组名,数组名又表示数组首元素的地址。 &arr表示的整个数组的地址。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int main()
{
	int arr[10];
	printf("%p\n",arr);
	printf("%p\n",&arr);
	return 0;
}
//打印结果:
/*
00DCFBDC
00DCFBDC
*/

打印它们的地址可以发现是一样的。但其实又不完全一样。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int main()
{
	int arr[10];
	printf("%p\n",arr);
	printf("%p\n",arr+1);
	
	printf("%p\n",&arr);
	printf("%p\n",&arr+1);
	return 0;
}
//打印结果:
/*
004FF970
004FF974
004FF970
004FF998
*/

arr+1跳过的4个字节的地址。而&arr跳过的是40个字节的地址。 正如前面所说&arr是整个数组的地址,整个数组大小就是40个字节。 本例中&arr的类型就是int(*)[10],是一种数组指针类型。 数组地址+1,跳过整个数组的大小,所以&arr+1相对于&arr的差值就是40.

3.3 数组指针的使用

了解到数组指针指向的数组,那么数组指针中存放的就是数组的地址。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int main()
{
	int arr[10] = {1,2,3,4,5,6,7,8,9,0};
	int(*p)[10] = &arr;
	//把整个数组的地址存放在数组指针变量当中
	//但是很少这么写
	return 0;
}

数组指针的使用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
void print1(int arr[3][5],int row,int col)
{
	for(int i = 0;i<row;++i)
	{
		for(int j = 0;j<col;++j)
		{
			printf("%d ",arr[i][j]);
		}
		printf("\n");
	}
}

void print2(int (*arr)[5],int row,int col)
{
	for(int i = 0;i<row;++i)
	{
		for(int j = 0;j<col;++j)
		{
			printf("%d ",arr[i][j]);
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = {1,2,3,4,5,6,7,8,9,0};
	print1(arr,3,5);
	//arr是数组的数组名,表示数组首元素的地址。而这又是一个二维数组,二维数组的首元素地址就是第一行的地址,所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址,可以利用数组指针接收。
	print2(arr,3,5);
	
	return 0;
}

区分

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int arr[5];//整型数组
int* parr1[10];//整型指针数组
int (*parr2)[10];//数组指针
int (*parr3[10])[5];//数组指针数组

4.数组传参、指针参数

在写代码时不可避免的要把【数组】或者【指针】传递给函数,那么函数的参数设计要怎么做呢?

4.1 一维数组传参

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
void test(int arr[])//可行,最容易理解的写法([]内的数字可以随便写,不影响系统的判断)该传参的本质就是int* arr
{}
void test(int arr[10])//可行,最容易理解的写法。([]内的数字可以随便写,不影响系统的判断)该传参的本质就是int* arr
{}
void test(int* arr)//可行,实参传递的是arr代表数组首元素的地址,利用整型指针接收合情合理
{}
void test2(int *arr[20])//可行,本质是int** arr
{}
void test2(int **arr)//可行,实参传递的是arr2也代表首元素的地址,因为arr2是指针数组,一维指针的地址要有二级指针接收,合情合理
{}

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

4.2 二维数组传参

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>

void test(int arr[3][5])//可行,最容易理解的写法
{}
void test(int arr[][])//不可行,
{}
void test(int arr[][5])//可行
{}
//二维数组传参,函数形参的设计只能省略第一个[]的数字。
//对一个二维数组,可以不知道又多少行,但是必须知道要有多少列。
//因为在内存的二维数组的存放也是线性的,全存一行。知道列数才能知道有多少行。
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);
	return 0;
}

4.3 一级指针传参

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
void print(int* arr,int sz)
{
	for(int i = 0;i<sz;++i)
	{
		printf("%d ",*(arr+i));
	}
}
int main()
{
	int arr[10] = {1,2,3,4,5,6,7,8,9,0};
	int sz = 10;
	int* p = arr;
	print(arr,sz);
	return 0;
}
//打印结果:1 2 3 4 5 6 7 8 9 0

当函数的参数部分为1级指针的时候,函数能接受的的参数为该一级指针对应类型的地址。

4.4 二级指针传参

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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;
}

当函数的参数部分为二级指针的时候,函数能接受的的参数为该二级指针对应一级指针类型的地址。

5.函数指针

其实函数也是有地址的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
void test()
{
	printf("hello\n");
}
int main()
{
	printf("%p\n",test);
	printf("%p\n",&test);
	return 0;
}
//打印结果
/*
00A41267
00A41267
*/

从这里可以看出,函数不仅有地址,而且函数的函数名就代表了函数的地址,&函数名同样也表示函数的地址。 既然函数有地址,那么也就说明可以利用变量来存储。这个存储函数地址的变量就是函数指针。 函数指针的正确写法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
void test()
{
	printf("hello\n");
}
int main()
{
	void (*pf1)() = test;//正确写法
	void *pf2() = test;//错误写法
	return 0;
}

pf1可以存储,和数组指针类似,这里的*要先和pf1结合,确定pf1是一个指针,()的优先级有比较高。因此需要用()将*pf1括起来。pf1指向的是一个函数,指向函数无参数,返回类型为void。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
int Add(int x,int y)
{
	return x+y;
}
int main()
{
	int (*pf)(int int) = Add//指向有参数的函数指针
	return 0;
}

练习

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//代码1
(*(void(*)())0)();
/*
解释:
先看void(*)()这是一个函数指针类型。再往外看,这个函数指针类型被括号括住了(void(*)())
一个类型被()住就是表示强制类型转换的意思。也是说明0被强制类型转换成了函数指针类型。然后*表示对一个函数指针类型进行解引用取出指向的函数*(void(*)())0,最后再调用这个函数。
总结:调用0地址处的函数(实际是无法调用的)
*/

//代码2
void (*signal(int,void(*)(int)))(int);//signal为函数名
/*
解释:signal是函数名,那signal()中的就是函数的参数类型,类型分别为整型和函数指针类型,现在一个函数有了函数名和函数的参数,就差函数的返回类型,如果我们把signal(int,void(*)(int))删除就得到了void (*)(int)这不就是函数指针类型吗,那也就是说signal的函数的返回类型就是void(*)(int)
总结:这是一个函数的声明,找到其函数参数和函数返回类型就可以了。
*/

简化代码2

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef void (*pf)(int);
pf signal (int,pf);//利用typedef将类型重命名,来简化代码

6.函数指针数组

数组是存放相同类型数据的存储空间 前面我们已经学习了指针数组

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int* arr[10];
//数组的每个元素类型是int*

同样的我们也可以把函数指针存放进数组,就叫做函数指针数组,那函数指针数组的是如何定义的呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int (*pf)();//这是一个函数指针
//我们将[]添加到变量名后面就可以了
int (*pf[10])();//这就是函数指针数组

pf[]结合说明pf是一个数组,然后数组存放的类型就是int(*)()函数指针数组的运用 下面以实现一个简单的计算器为例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
void menu()
{
	printf("***************************\n");
	printf("**** 1.Add   2.Sub     ****\n");
	printf("**** 3.Mul   4.Div     ****\n");
	printf("**** 0.exit            ****\n");
	printf("***************************\n");
}
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 input = 0;
	int a = 0,b = 0;
	int ret = 0;
	do
	{
		menu();
		printf("选择你所要用到的功能>\n");
		scanf("%d",&input);
		switch(input)
		{
			case 1:
				printf("请输入两数>");
				scanf("%d %d",&a,&b);
				ret = Add(a,b);
				printf("ret = %d\n",ret);
				break;
			case 2:
				printf("请输入两数>");
				scanf("%d %d",&a,&b);
				ret = Sub(a,b);
				printf("ret = %d\n",ret);
				break;
			case 3:
				printf("请输入两数>");
				scanf("%d %d",&a,&b);
				ret = Mul(a,b);
				printf("ret = %d\n",ret);
				break;
			case 4:
				printf("请输入两数>");
				scanf("%d %d",&a,&b);
				ret = Div(a,b);
				printf("ret = %d\n",ret);
				break;
			case 0:
				printf("退出\n");
				break;
			default:
				printf("输入错误\n");
				break;
		}
	}while(input);
	return 0;
}

这样写的话其实是很繁琐的。实现这种简单的功能都写了这么长的代码,而且如果后续在添加什么函数功能的话,代码又要增加好的。所以我们要简化。 通过观察,这4个函数的参数和返回类型都是相同的,那么不就说明了可以写成函数指针数组吗。数组中存放这个函数指针类型就可以了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
void menu()
{
	printf("***************************\n");
	printf("**** 1.Add   2.Sub     ****\n");
	printf("**** 3.Mul   4.Div     ****\n");
	printf("**** 0.exit            ****\n");
	printf("***************************\n");
}
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 input = 0;
	int a = 0,b = 0;
	int ret = 0;
	do
	{
		menu();
		printf("选择你所要用到的功能>\n");
		scanf("%d",&input);
		int(*pf[5])(int,int) = {NULL,Add,Sub,Mul,Div};//存入NULL是为了可以和菜单对应
		if(input>0&&input<5)
		{
			printf("请输入两数>");
			scanf("%d %d",&a,&b);
			ret = pf[input](a,b);
			printf("ret = %d\n",ret);
		}
		else if(input == 0)
			printf("退出\n");
		else
			printf("输入有误\n");
	}while(input);
	return 0;
}

利用函数指针数组我们将该程序充分简化,而且如果后续还要添加类似的函数功能的话,我们只需要将新写的函数添加进数组,在改变一下判断条件即可。

7.指向函数指针数组的指针

指向函数指针数组的指针是一个指针。 指针指向一个数组,数组的元素都是函数指针;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void test(const char* str)
{
	printf("%s\n",str);
}
int main()
{
	//函数指针pfun
	void(*pfun)(const char*) = test;
	//函数指针的数组pfunarr
	void(*pfunarr[5])(const char* str);
	//指向函数指针数组pfunarr的指针ppfunarr
	void(*(*ppfunarr)[5])(const char*) = &pfunarr;
}

还可以再绕下去的

8.回调函数

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

首先演示一下qsort函数的使用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//对整型数组进行排序
#include<stdio.h>
int int_cmp(const void* a,const void* b)
{
	return (*(int*)a) - (*(int*)b);
}
int main()
{
	int arr[10] = {1,3,5,7,9,2,4,6,8,0};
	qsort(arr,10,sizeof(int),int_cmp);
	for(int i = 0;i<10;++i)
	{
		printf("%d ",arr[i]);
	}
	printf("\n");
	return 0;
}
//打印结果:
//0 1 2 3 4 5 6 7 8 9

//对结构体数组进行排序
#include <stdio.h>
#include <string.h>
struct stu
{
	int age;
	char name[10];
};
int struct_cmp_age(const void* a, const void* b)//利用年龄排序
{
	return ((struct stu*)a)->age - ((struct stu*)b)->age;
}
int struct_cmp_name(const void* a, const void* b)//利用名字排序,因为字符串无法相减
//所以这里利用了strcmp进行字符串的比较
{
	return strcmp(((struct stu*)a)->name,((struct stu*)b)->name);
}
int main()
{
	struct stu s[3] = { {17,"yui"},{14,"anna"},{20,"hua"} };
	qsort(s, 3, sizeof(s[0]), struct_cmp_age);
	printf("调用struct_cmp_age\n");
	for (int i = 0; i < 3; ++i)
	{
		printf("%d %s\n", s[i].age, s[i].name);
	}
	qsort(s, 3, sizeof(s[0]), struct_cmp_name);
	printf("调用struct_cmp_name\n");
	for (int i = 0; i < 3; ++i)
	{
		printf("%d %s\n", s[i].age, s[i].name);
	}
	return 0;
}
//打印结果:
/*
调用struct_cmp_age
14 anna
17 yui
20 hua
调用struct_cmp_name
14 anna
20 hua
17 yui

*/

qsort 打开cplusplus网站->qsort

qsort
qsort
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void qsort(void* base,//需要排序的数组首元素地址
		  size_t num,//需要排序的数组的元素个数
		  size_t size,//需要排序数组的单个元素的大小
		  int (*compar)(const void*,const void*)//传递函数指针,需要自己写
		  }

可以看到的时,这里接受数组首元素的地址是用void*来接收。 提问:为什么呢? 回答:Void*指针 是无具体类型的指针。Void* 类型的指针可以接任意类型的地址(这种类型的指针是不能直接解引用操作的,也不能直接进行指针运算的)。 所以用void*接收是没问题的。然后,这个qsort函数不仅可以对整型数组排序,还可以对字符数组,浮点型数组,甚至是结构体数组。这也就造成了不能使用特定类型指针来接收的情况,如果使用了特定的类型,那其它类型就不能被接收了,所以才会选择使用void*来接收。 模拟实现qsort,但是因为目前还没有学快速排序,所以这里我们利用冒泡排序替代。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//主要逻辑
void swap(char* a, char* b, int size)
{
	char tmp = 0;
	for (int i = 0; i < size; ++i)//交换的实质其实就是指针所指向内容的交换.
	//因为char只能指向一个字节,所以我们需要传递size了解到要交换的字节大小,然后一个字节一个字节的交换。
	{
		tmp = *a;
		*a = *b;
		*b = tmp;
		a += 1;
		b += 1;
	}
}
void bubble_sort(void* base, int num, int size, int(*cmp)(const void*, const void*))
{
	for (int i = 0; i < num - 1; ++i)
	{
		for (int j = 0; j < num - i - 1; ++j)
		{
			if (cmp((char*)base + j * size, (char*)base + (j + 1) * size)>0)//因为void类型的指针是不能直接解引用操作的,也不
			//能直接进行指针运算的。为了拿到比较位置的地址,我们需要将base强转为(char*),因为char*的加减整数时只会跳过一个字节,
			//这是最小的位移距离了。所以我们可以通过强转后的base拿到base[j]和base[j+1]的地址进行比较。
			{
				swap((char*)base + j * size, (char*)base + (j + 1) * size, size);//开始交换
			}
		}
	}
}

测试

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
#include <string.h>
struct stu
{
	int age;
	char name[10];
};
int int_cmp(const void* a, const void* b)
{
	return (*(int*)a) - (*(int*)b);
}
int struct_cmp_age(const void* a, const void* b)//利用年龄排序
{
	return ((struct stu*)a)->age - ((struct stu*)b)->age;
}
int struct_cmp_name(const void* a, const void* b)//利用名字排序,因为字符串无法相减
//所以这里利用了strcmp进行字符串的比较
{
	return strcmp(((struct stu*)a)->name,((struct stu*)b)->name);
}
void swap(char* a, char* b, int size)
{
	char tmp = 0;
	for (int i = 0; i < size; ++i)//交换的实质其实就是指针所指向内容的交换,因为char只能指向一个字节,所以我们需要传递size了解到要交换的字节大小,然后一个字节一个字节的交换。
	{
		tmp = *a;
		*a = *b;
		*b = tmp;
		a += 1;
		b += 1;
	}
}
void bubble_sort(void* base, int num, int size, int(*cmp)(const void*, const void*))
{
	for (int i = 0; i < num - 1; ++i)
	{
		for (int j = 0; j < num - i - 1; ++j)
		{
			if (cmp((char*)base + j * size, (char*)base + (j + 1) * size)>0)//因为void类型的指针是不能直接解引用操作的,也不能直接进行指针运算的。为了拿到比较位置的地址,我们需要将base强转为(char*),因为char*的加减整数时只会跳过一个字节,这是最小的位移距离了。所以我们可以通过强转后的base拿到base[j]和base[j+1]的地址进行比较。
			{
				swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
			}
		}
	}
}
int main()
{
	int arr[10] = { 1,3,5,7,9,2,4,6,8,0 };
	bubble_sort(arr, 10, sizeof(int), int_cmp);//冒泡排序
	printf("对arr排序:\n");
	for (int i = 0; i < 10; ++i)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	struct stu s[3] = { {17,"yui"},{14,"anna"},{20,"hua"} };
	bubble_sort(s, 3, sizeof(s[0]), struct_cmp_age);
	printf("调用struct_cmp_age:\n");
	for (int i = 0; i < 3; ++i)
	{
		printf("%d %s\n", s[i].age, s[i].name);
	}
	bubble_sort(s, 3, sizeof(s[0]), struct_cmp_name);
	printf("调用struct_cmp_name:\n");
	for (int i = 0; i < 3; ++i)
	{
		printf("%d %s\n", s[i].age, s[i].name);
	}
	return 0;
}
//打印结果:
/*
对arr排序:
0 1 2 3 4 5 6 7 8 9
调用struct_cmp_age:
14 anna
17 yui
20 hua
调用struct_cmp_name:
14 anna
20 hua
17 yui
*/

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-07-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
【C语言】指针进阶知识终章
其实这看起来是难以理解的,所以我们可以用typedf(起别名)来简化一下,更加容易认识代码:
平凡的人1
2022/11/15
5210
【C语言】指针进阶知识终章
C语言进阶——指针
str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域, 当几个指针,指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4值相同,地址不同
小李很执着
2024/06/15
1630
C语言进阶——指针
指针进阶详解
理论上字符串第一个字符被改为w,实际上代码无法正常运行,直接挂掉。所以避免被修改,我们const修饰字符指针,避免其被改。
用户10517932
2023/10/07
2300
指针进阶详解
指针总结
代码 char pstr = “hello bit.”; 特别容易让人以为是把字符串 hello bit 放到字符指针 pstr 里了,但是/本质是把字符串 hello bit. 首字符的地址放到了pstr中。*
海盗船长
2020/08/27
3140
【C指针进阶】(C精髓)——对指针的更进一步深入剖析(图文近2w详解)
本文承接了上文:初阶指针——全面了解指针,在此基础上对指针进行更深一步的剖析,相信我,也请相信你自己!
诺诺的包包
2023/02/17
6050
【C指针进阶】(C精髓)——对指针的更进一步深入剖析(图文近2w详解)
手撕指针(四)
int (*parr1[3])(); int *parr2[3](); int (*)() parr3[3];
用户11367247
2024/11/20
1040
抽丝剥茧C语言(高阶)指针的进阶
数组指针是指针?还是数组? 答案是:指针。 我们已经熟悉: 整形指针: int * pint; 能够指向整形数据的指针。 浮点型指针: float * pf; 能够指向浮点型数据的指针。 那数组指针应该是:能够指向数组的指针。 下面代码哪个是数组指针?
有礼貌的灰绅士
2023/03/28
4340
抽丝剥茧C语言(高阶)指针的进阶
深入浅出C语言指针(进阶篇)
在C语言中,指针是至关重要的一部分,掌握指针的用法对于编写高效、简洁的代码具有极大帮助。本文将带您深入了解C语言指针的高级用法,助您迈向编程高手之路。
平凡之路.
2024/10/09
1620
深入浅出C语言指针(进阶篇)
C语言指针深度解剖
指针是C语言的灵魂,深入理解指针,是学好学会C语言的重要前提。因此,本文将重点讲解C语言指针的深度内容。
二肥是只大懒蓝猫
2023/03/30
5040
C语言指针深度解剖
【简介指针】
1·可想而知便或有个相似的名字出现在我们脑海中,那便就是指针数组,它和整型数组或者字符型数组一样是个数组;如:
羑悻的小杀马特.
2025/01/23
700
【简介指针】
C语言被指针手撕
这里对第二种使用方法简单介绍一下:虽然我们把常量字符串"hi boy "作为初始值赋给字符指针pstr,但是**实际上pstr只是把这个常量字符串的首地址,即’h’的地址给存储起来了。**后续我们可以用%s的方式打印整个字符串。
始终学不会
2023/03/28
4150
C语言被指针手撕
带你深入了解c语言指针后续
以数组指针为例: 数组指针示例:写一个指向 int arr[10] 数组的数组指针;
初阶牛
2023/03/01
3920
【指针合集】全方位理解C语言指针
内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的。 所以为了有效的使用内存,就要把内存划分成一个个小的内存单元,每个内存单元的大小都是一个字节。 为了能够有效的访问到内存的每个单元,就要给内存单元进行编号,这些编号被称为内存单元的地址。 在写程序时,创建的变量、数组等都要在内存上开辟空间。 每个内存都有唯一的编号,这个编号也被称为地址 地址 == 编号
Yui_
2024/10/16
3070
【指针合集】全方位理解C语言指针
C语言进阶——指针进阶
指针就是地址,而凡是存储在内存中的值都会有属于自己的地址,指针指向地址,这样我们就能通过指针间接操作变量。我们在指针初阶中介绍了指针的基本概念:如指针大小、野指针问题、指针间的关系运算等,在我们的指针进阶中,将会对指针进行进一步剖析,见识更深的指针!🎊🎊
北 海
2023/07/01
1950
C语言进阶——指针进阶
C语言——I /深入理解指针(三)
代码 const char* p = "hello bit."; 字符串 hello bit 放到字符指针 p ⾥了,但是本质是把字符串 hello bit. ⾸字符的地址放到了p中(类似于数组)。
用户11015888
2024/03/11
1420
C语言——I /深入理解指针(三)
【C指针(五)】6种转移表实现整合longjmp()/setjmp()函数和qsort函数详解分析&&模拟实现
本小节,我们将继续学习C语言转移表,什么是回调函数,回调函数又是什么?qsort函数怎么使用,怎么理解处理,要注意的细节,当然qsort使用举例,最后我们进行qsort函数的模拟实现!文章干货满满,走起!
学习起来吧
2024/02/29
4980
【C指针(五)】6种转移表实现整合longjmp()/setjmp()函数和qsort函数详解分析&&模拟实现
指针进阶(C语言)
*pp 通过对 pp 中的地址进行解引用,这样找到的是 p , *pp 其实访问的就是 p .
薄荷冰
2024/01/22
1740
指针进阶(C语言)
C语言高级指针理解及应用(下)
出品|https://blog.csdn.net/ningningmingming/article/details/78688031
C语言中文社区
2022/05/30
7230
C语言高级指针理解及应用(下)
【C语言】指针总结3
注:代码 const char pstr = “hello.”; 特别容易让人以为是把字符串 hello 放 到字符指针 pstr 里了,但是本质是把字符串 hello. 首字符的地址放到了pstr中。*
用户11290673
2024/09/25
960
【C语言】指针总结3
C语言之指针详解(3)
上述的代码const char* pstr = "hello bit.";特别容易让大家以为是把字符串hello bit.放到字符指针pstr里了,但是本质是把字符串hello bit.首字符的地址放到了pstr中。所以说,上面的代码是把常量字符串的首字符h的地址放到指针变量pstr中。
Crossoads
2024/10/21
910
C语言之指针详解(3)
相关推荐
【C语言】指针进阶知识终章
更多 >
LV.2
这个人很懒,什么都没有留下~
目录
  • 1.字符指针
  • 2.指针数组
  • 3.数组指针
    • 3.1 数组指针的定义
    • 3.2 &数组名与数组名
    • 3.3 数组指针的使用
  • 4.数组传参、指针参数
    • 4.1 一维数组传参
    • 4.2 二维数组传参
    • 4.3 一级指针传参
    • 4.4 二级指针传参
  • 5.函数指针
  • 6.函数指针数组
  • 7.指向函数指针数组的指针
  • 8.回调函数
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档