IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> C语言指针的进阶知识详细讲解你一定会有所收获! -> 正文阅读

[游戏开发]C语言指针的进阶知识详细讲解你一定会有所收获!

C语言指针的进阶内容


前言

上一篇文章讲解了<指针>的基础内容,建议大家先打牢地基,再来阅读这篇进阶文章
本篇主要讲解了比较复杂难懂的指针类型如何定义,使用方法以及应用场景;
内容较为复杂,各种操作符嵌套的较为复杂,希望大家可以细品这篇文章!


本人是一个刚刚上路的IT新兵!分享一点自己的见解,如果有错误的地方欢迎各位大佬莅临指导,如果这篇文章可以帮助到你,劳请大家点赞转发支持一下! 下面图片的双重水印是我对这篇文章进行了修改后二次上传的图片,请大家放心,不是偷的,大家放心观看!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 下面就要发车喽!!

一、字符指针

在指针的类型中我们知道有一种指针类型为字符指针 char* ;

int main()
{
    char ch = 'w';
    char *pc = &ch;
    *pc = 'w';
    return 0;
}

这是一种使用情况:指针指向一个字符
还有一种使用情况:指针指向一个字符串

#include<stdio.h>
int main()
{
	const char* p0 = "hello";
	printf("%c", *p0);
	return 0;
}

在这里插入图片描述
指针只有一个字节的大小,"hello"这个字符串,再加上’\0’,一共6个字节;肯定不能全都存进去;那么这个指针里存的是什么呢?

实际上指针里存储的是首字符的地址;可以通过指针来打印整个字符串;
在这里插入图片描述

#include <stdio.h>
int main()
{
	char arr1[] = "hello";
	char arr2[] = "hello";
	const char* arr3 = "hello";
	const char* arr4 = "hello"
	if (arr1 == arr2)//如果arr1与arr2相等
	{				//返回"arr1==arr2"
		printf("arr1==arr2\n");
	}
	else if(arr1!=arr2)//不相等返回"arr1!=arr2"
	{
		printf("arr1!=arr2\n");
	}
	if (arr3 == arr4) //同理
	{
		printf("arr3==arr4\n");
	}
	else if(arr3!=arr4)//同理
	{
		printf("arr3!=arr4\n");
	}
	return 0;
}

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

为什么呢?
这里arr3和arr4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针。指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以arr1和arr2不同,arr3和str4相同。

内存就好像是一个自动贩卖机;
字符串常量是自动贩卖机里的一个货物;
指针是指向货物的地址,也就是指针知道去哪可以买到,所以指针相同,都指向贩卖机里的那个货物
字符串是切切实实的买到了这个货物,虽然都是一样的货物,但是被两个不同的人买去,一个是我的货物,一个是你的货物,就不同了,所以字符数组不同;

二、数组指针

1.数组指针的定义

在指针的基础内容里讲到了指针数组
int* arr1[10]; //整形指针的数组
那是存放指针的数组;

整形指针是存放整形变量的地址的;
字符指针是存放字符变量的地址的;
那么数组指针是什么呢?
答案是:存放数组地址的指针

指针数组,数组指针;
他俩名字相似,定义方式也能相似
int *p1[10];
int (*p2)[10];
p1, p2分别是什么?
p1是指针数组,上篇已经讲过了;
p2是数组指针,这里就涉及到了优先级的问题,[]是比*的优先级高的,所以如果没有括号,p2会先与[10]结合组成数组p2[10]类型是int *;就又变成指针数组了;
所以要用括号()将*和p2括起来,保证*和p2先结合成一个指针,类型是int [10];这才是数组指针;

2.数组名的两种用法

那么数组指针肯定是要存放整个数组的地址;
上篇讲过数组名就是首元素地址;
在sizeof()里与(&数组名)时数组名就表示整个数组,计算的整个数组的大小,单位是字节

那么arr与&arr有什么区别呢?在这里插入图片描述

他们两个打印出来的地址相同;那他们难 道一样吗?
在这里插入图片描述

由此可见并不一样;
arr+1;只跳过了四个字节
&arr+1;跳过了四十个字节,也就是整个arr数组;

虽然arr与&arr打印出来的地址一样;
但是意义不同,
arr就只是arr[0]的地址;
&arr虽然打印出来是也是arr[0]的地址,但是他取出的是整个数组的地址;

但是,假设pa是一个数组指针,存储了整个数组arr的地址;
*pa就相当于数组名即首元素地址;(*pa==arr);

3.数组指针的用法

*pa==arr所以,他用在打印一维数组就和直接应用数组名或一级指针没什么区别,甚至还要繁琐一点;所以一般数组指针应用在二维数组上;
![在这里插入图片描述](https://img-blog.csdnimg.cn/1a44a753d2ce493b8137a30926b75ed0.png在这里插入图片描述

应用在二维数组的方法:
在这里插入图片描述
可以把二维数组arr[n][]看成是n个一维数组构成的;
假设第一个一维数组名为arr1;

假设第i个一维数组名为arri;

pa是第一个一维数组的数组名(arr1)的地址; 友情提示:数组名是数组首元素地址!!!
pa+i是第i个一维数组的数组名(arri)的地址;
*pa得到第一个一维数组的数组名(arr1);
*(pa+i)得到第i个一维数组的数组名(arri);
*(pa+i)+j是第一个一维数组的第j个元素的地址;

所以要得到第i行第j个元素要怎么做呢?

答案是:*(*(pa+i)+j);

在这里插入图片描述
在这里告知大家一个错误的使用方法:希望大家可以避开;
主要错误原因是不了解二维数组在内存中的存储方式和数组指针的概念;

在这里插入图片描述
咱们先来讲二维数组的存储方式:
在这里插入图片描述
在这里插入图片描述
二维数组在内存中的存储方式是第二种,并不是第一种!!!

那么指针是如何存储二维数组数据的呢?
在这里插入图片描述
因为上述代码定义的数组指针的数组元素个数为5;
所以不管你是第几行的,都会强行存储5个元素,
而输出就只输出了这个指针数组里的前四个元素,
就跳到下一组的五个元素了;所以会造成数据丢失,
也导致了后面的数据不够存储最后一组前四个,而导致了越界访问,生成随机数;

三、函数指针

1.函数名的意义

各种类型的变量,一二维数组,就连自定义的结构体都有指针,那函数肯定有啊,肯定要雨露均沾啊;
咱们也先从函数名的意义开始讲;
在这里插入图片描述

函数就没数组他们那么讲究;函数名和&函数名是等价的;即test==&test
在传参的时候要传函数地址,就传函数名就ok

2.函数指针的定义

那么函数指针的书写格式是什么呢;
咱们先来看一下其他类型的指针是如何定义的;
intp;
char
p;

(struct Stu)*p;(结构体指针)
int (*p)[5];(整形数组指针)
总结一条规律:
除了*p其他的结合到一起就是指针的类型;
函数指针也不例外;

在这里插入图片描述
定义函数指针的公式是:xx(*n)(i,j,…);
在这里插入图片描述

3.函数指针的使用方法

在这里插入图片描述

在这里插入图片描述

四、数组参数,指针参数

在写代码时,肯定会将数组或者指针等参数传给函数,那函数的该用什么来接受呢?

1.一维数组传参

1.接收普通数组

传数组名就是传过去了首元素的地址;
我可以用指针接收

在这里插入图片描述

我也可以用数组去接收:

在这里插入图片描述

为什么放数也许不放数也行
你传过来的只是首元素的地址,你接收数组首元素地址时,内存不会再专门为你开辟一块空间去存放元素,他只会根据你传过来的地址去寻找相应的元素;
这时arr[i]==*(p+i);
也就是这个数组只是用来接收首元素地址的,不是用来存储数据的;

2.接收指针数组

与上述相同,你传给我指针数组,我就可以用指针数组接收
在这里插入图片描述

因为指针数组,里面存放的都是指针,传过来的是首元素的地址即指针的地址,所以要用一个二级指针去接收

在这里插入图片描述

*(p+1)==arr[1];*(p+i)==arr[i];
**(p+1)==*arr[1]==2;

2.二维数组传参

1.用二维数组去接收比如arr[i][j]

在这里插入图片描述

这里要注意i可以不填但是j一定要填上即arr[i][],arr[i][j]这两种;
二维数组可以不知道有多少行,但是一定要知道一行有多少个元素;

2.用指针去接收

二维数组的数组名是首行的地址,因此不能用一级指针去接收,要用数组指针去接收;

具体方法请转到本文数组指针的用法

3.一级指针传参

用一级指针去接收一级指针
在这里插入图片描述

p0+i==下标为i的元素的地址.

一级指针可以接收哪些参数呢?
答:地址,一级指针变量;

4.二级指针传参

#include <stdio.h>
void print(int** p0)
{
	printf("%d\n", **p0);
}
int main()
{
	int a = 6;
	int* p = &a;
	int** pp = &p;
	print(pp);
	print(&p);
	return 0;
}

在这里插入图片描述

二级指针可以接收哪些参数呢?
答:一级指针变量的地址,一级指针数组的数组名,二级指针变量;

5.函数指针传参

#include <stdio.h>
int test(int n, int m)
{
return n + m;
}
void print(int i, int j, int (*test)(int, int))//或者直接用函数接收int test(int,int)
{
	int c = test(i, j); //如果是用函数指针接收,可以解引用(*test)(i,j)
	printf("%d", c);//也可以不解引用直接正常使用test(i, j)
}
int main()
{
	int a = 1, b = 2;
	print(a, b, test);
	return 0;
}

在这里插入图片描述

函数指针就只能接收函数的地址了(函数名==函数的地址)

五、函数指针数组

int*arr[5]
数组名是arr;类型是int*;元素个数为5;
先让arr(数组名)和[5]结合组成数组,然后再去填类型

函数指针数组,类型肯定是函数指针;
定义函数指针的公式是:xx(*n)(i,j,…);
拿int(*add)(int,int)这个函数指针举例,返回类型是int,指针名是add,接收两个int类型的参数;

int(*add[5])(int,int)
add先与[5]组成数组,那剩下的就是该数组的类型了;即int(*)(int,int)是数组add[5]的类型
函数指针数组的定义公式:()(*N[])()
在这里插入图片描述
使用方法:

#include <stdio.h>
int add(int a, int b)
{
	return a + b;
}
int sub(int a, int b)
{
	return a - b;
}
int mul(int a, int b)
{
	return a * b;
}
int div(int a, int b)
{
	return a / b;
}
int main()
{
	int x, y;
	int input = 1;
	int ret = 0;
	int(*p[5])(int x, int y) = {0, add, sub, mul, div };
	while (input)
	{
		printf("************************\n");
		printf(" 1:add           2:sub \n");
		printf(" 3:mul           4:div \n");
		printf("	0:退出		   \n");
		printf("*********************** \n");
		printf("请选择:");
		scanf("%d", &input);
		if ((input <= 4 && input > 0))
		{
			printf("输入操作数:");
			scanf("%d %d", &x, &y);
			ret = (*p[input])(x, y);
			printf("ret = %d\n", ret);
		}
		else if(input >5&&input<0)
		{
			printf("输入有误\n");
		}
	}
	return 0;
}

在这里插入图片描述

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

六、指向函数指针数组的指针

如何定义:
函数指针数组:int(*add[])(int,int)
以这个函数指针数组为例;
也就是说除了函数名add之外其他的东西就是该函数指针数组的类型;

那么这个指向函数指针数组的指针的类型就是: int(*[])(int,int)
所以指向函数指针数组的指针是int(*(*p)[])(int,int);
*p声明p是一个指针,剩下的就是p的类型;

定义公式:
在这里插入图片描述

#include <stdio.h>
int add(int a,int b)
{
	return a + b;
}
int sub(int a, int b)
{
	return a - b;
}
int mul(int a, int b)
{
	return a * b;
}
int div(int a, int b)
{
	return a / b;
}
int main()
{
	int (*p1)(int, int) = &add;//函数指针
	int (*p2)(int, int) = &sub;
	int (*p3)(int, int) = &mul;
	int (*p4)(int, int) = &div
	int (*pp[5])(int, int) = { p1,p2,p3,p4 };
	int(*(*pp0)[5])(int, int) = &pp;
	//pp0+i==pp[i]==p1/p2/p3/p4==&add/&sub/&mul/div
	//(*pp0+i)==*pp[i]==*p1/*p2/*p3/p4==add/sub/mul/div;
	printf("%d\n", (*(*pp0 + 0))(9, 3));
	printf("%d\n", (*(*pp0 + 1))(9, 3));
	printf("%d\n", (*(*pp0 + 2))(9, 3));
	printf("%d\n", (*(*pp0 + 3))(9, 3));
	return 0;
}

在这里插入图片描述

在这里插入图片描述

七、回调函数

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

#include <stdio.h>
int add(int n, int m)
{
	return n + m;
}
void print(int i, int j, int (*pf)(int, int))
{
	int c = pf(i, j); 
	printf("%d", c);
}
int main()
{
	int a = 1, b = 2;
	print(a, b, add);
	return 0;
}

在这里插入图片描述

在这里插入图片描述
这就是回调函数;

总结

以上就是今天要讲的内容,本文仅仅简单介绍了指针的进阶内容,而指针是很复杂精妙的知识,需要大家去理解去反复咀嚼;
欢迎大家批评指正,也希望大家动动小手点赞转发支持一下!

知识需要咀嚼_沉淀

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章           查看所有文章
加:2022-11-05 00:54:29  更:2022-11-05 00:55:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/7 18:05:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码