【C语言进阶(3)】高阶指针1

news2025/1/21 9:25:08

文章目录

  • 字符指针
  • 指针数组
    • 指针数组的使用
  • 数组指针
    • 数组指针的使用
  • 数组传参和指针传参
    • 一维数组传参
    • 二维数组传参
    • 一级指针传参
    • 二级指针传参
  • 函数指针

指针的概念

  1. 内存单元是有编号的,编号 == 地址 == 指针
  2. 指针本质上是个用来存放地址的变量,地址是唯一的用来标识一块内容空间。
  3. 指针(变量)的大小固定为 4/8 个字节(32位系统/64位系统)。
  4. 指针也是有类型的,指针的类型决定好了指针 ± 整数的步长,以及指针解引用操作时的能操控的字节数。

字符指针

字符指针的形式一般为 char*

  • 将一个 char 类型变量的地址赋给 char* 类型的指针。
char  ch = 'a';
char* pc = &ch;

有时候也可以让字符指针指向字符串

  1. 字符指针指向的字符串为常量字符串。
  2. 字符指针此时存储的是,指向的是字符串首字符的地址
  3. 字符指针指向的常量字符串不可通过指针解引用来修改
char* p = "abcdef";//此时 p 里存着的是 a 的地址

在这里插入图片描述

  • 因为 p 指向的是个常量字符串,为了避免指向的串被修改,指针需要加上 const。
const char* p = "abdef";//这样指向的字符串就不能通过 *p 进行修改了。

字符指针例题

  • 下面代码的输出结果为什么会是这样?
  • 注:代码中比较的是串之间的地址。str1234 指向的都是各个串的首元素的地址。

在这里插入图片描述

  • str1 和 str2 分别创建了两块独立的数组空间,这两块空间的起始地址肯定不会相同,只不过这两块空间正好都存储子着 hello word! 这串数据罢了。

在这里插入图片描述

  • 因为 str3 和 str4 指向的是同一个常量字符串,常量字符串因为没人能改它,所以这个串在内存中只会创建一份,即 str3 和 str4 指向的是同一块空间的 h 的地址。

在这里插入图片描述

指针数组

指针数组是数组

  • 字符数组:存放字符的数组。
  • 整型数组:存放整型的数组。
  • 指针数字:存放指针的数组,存放在数组中得元素都是指针类型。
int*  arr[5];	//存放整型指针的数组
char* str[5];	//存放字符指针的数组

指针数组的定义格式

  • 存储的元素类型 数组名 [常量表达式]
int* p1[5];
  • [] 操作符的优先级要比 * 运算符的优先级高,所以 数组名先和 [5] 结合,p1 就被定义为一个具有 5 个元素的数组。
  • 再看 int* 说明数组 p1 里存着的 5 个是 int* 类型的指针变量。

指针数组的使用

1. 模拟二维数组

  • 二维数组每行的元素个数是一样的,创建多个一维数组,将这几个一维数组当成二维数组的每一行。
  • 使用指针数组存储这多个一维数组的首元素地址。
int arr1[] = {1,2,3,4};
int arr2[] = {2,2,3,4};
int arr3[] = {3,2,3,4};

int* parr[] = {arr1,arr2,arr3};//parr 数组就是指针数组

在这里插入图片描述

  • 这样子想要拿出对应位置的元素的方式和二维数组就没两样了。

在这里插入图片描述

2. 指向字符指针

  • 可以用来存储多个字符串的首字符地址。

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

数组指针

数组指针是指针

  • 数组指针是一个指针,它指向一个数组

数组名的理解

  • 除了下面两个例外之外,数组名都表示的是数组首元素的地址。
  1. sizeof(数组名):这里的数组名表示整个数组,计算整个数组的大小。
  2. &数组名:这里的数组名表示取出整个数组的地址。

数组指针的定义

  • 将一整个数组的地址取出来赋给数组指针。
int arr[10] = {0};
int (*parr)[10] = &arr;//parr 用来存放数组的地址,parr 就是数组指针。
  • 先看 parr,数组名 parr 先和 * 结合,说明 parr 是一个指针;
  • 往后一看,跟着一个 [10],说明 parr 指向的这个数组具有 10 个元素。
  • 往前一看,这个 int 说明了 parr 指向的这个数组的 10 个元素每个都是 int 类型的变量。

数组指针的使用

  • 一般情况下,使用数组指针去访问数组其实是很不方便的。
int arr[] = {1,2,3,4,5};
int (*p)[5] = &arr;

printf("%d\n",(*p)[2]);//*p <==> arr
  • 所以,在一维数组上基本不会使用数组指针,在二维数组上才有使用数组指针的意义。

管理二维数组

  • 数组名是首元素的地址,那么函数的形参就可以写成指针的形式。
  • 使用数组指针做形参的时候,数组指针就是用来接收二维数组第一行的地址的。
//parr 存储第一行的地址,[4] 表示每行有 4 列
void print(int(*parr)[4],int row,int col)
{
	int i = 0;
	int j = 0;

	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			//printf("%d ", parr[i][j]);
			printf("%d ", *(*(parr + i) + j));//这两种写法等价
		}
		putchar('\n');
	}
}

int main()
{
	int arr[4][4] = { {1,2,3,4},{2,2,3,4},{3,2,3,4},{4,2,3,4} };

	print(arr, 4, 4);//传第一行的地址过去

	return 0;
}

在这里插入图片描述

在这里插入图片描述

分析下面代码的的意思

int (*parr[10])[5];
  • parr 先和 [10] 结合,说明 parr 是一个具有 10 个元素的数组。
  • 将 parr[10] 拿掉之后,剩下了 int (*) [5],这是个数组指针,该指针指向的数组具有 5 个元素,每个元素为 int。
  • 所以,int (*parr[10])[5] 的意思就是,parr 是个拥有 10 个元素的数组,每个元素都是一个指向 int [5] 数组的数组指针。

在这里插入图片描述

数组传参和指针传参

  • 很多时候,难免需要把(数组)或者(指针)作为参数传给函数,此时函数的参数又应该如何设计?

一维数组传参

  • 下面代码的所有函数中,形参是否设计合理?
void test(int arr[])	//1:√
{}
void test(int arr[10])	//2:√
{}
void test(int* arr)		//3:√
{}
void test2(int* arr[20])//4:√
{}
void test2(int** arr)	//5:√
{}

int main()
{
	int arr[10] = { 0 };	//每个元素都是 int 类型的变量
	int* arr2[20] = { 0 };	//每个元素都是 int* 类型的变量

	test(arr);
	test2(arr2);

	return 0;
}
  1. 数组传参,形参的是可以写成数组形式的。
  2. 数组传参,作为形参的数组是可以写上数组大小的,反正也不会去用它。
  3. 数组传参的本质是传递数组首元素的地址,所以形参可以是指针类型。
  4. 数组传参,传了个指针数组给函数,自然可以用指针数组的形式接收。
  5. 传了个首元素的地址过去,arr2 的首元素是个 一级指针 ,一级指针的地址自然得用二级指针接收。

二维数组传参

void test(int arr[3][5])	//1:√
{}
void test(int arr[][])		//2:×
{}
void test(int arr[][5])		//3:√
{}
void test(int* arr)			//4:×
{}
void test(int* arr[5])		//5:×
{}
void test(int(*arr)[5])		//6:√
{}
void test(int** arr)		//7:×
{}

int main()
{
	int arr[3][5] = { 0 };
	test(arr);
}
  1. 传递二维数组过去,自然可以用二维数组的形式接收。
  2. 二维数组作为参数不能和正常的定义二位数组的形式一样,只能省略行,不能省略列。
  3. 二维数组作为形参,可以省略行数。
  4. 二维数组的首元素是第一行的地址,也就是传了个一维数组的地址给函数,不能用 int* 这种整形指针接收一个数组的地址。
  5. arr 是个指针数组,不能用来接收传过来的第一行的地址。
  6. arr 是个数组指针,可以用来接收传过来的二维数组第一行的地址。
  7. arr 是个二级指针,只能接收一级指针的地址,不能用来接收数组的地址。

一级指针传参

  • 一级指针传参时,形参部分写成一级指针即可。
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]);

	print(p, sz);//一级指针p,传给函数

	return 0;
}

二级指针传参

void test(int** ptr)	//ptr 是用来接收一级指针的地址的
{
	printf("num = %d\n", **ptr);
}

int main()
{
	int n = 10;
	int* p = &n;
	int** pp = &p;

	test(pp);	//将 pp 里存着的 p 的地址传过去
	test(&p);	//直接将 p 的地址传过去

	return 0;
}

函数指针

  • 指向函数的指针,称之为函数指针。

函数指针的定义格式

返回类型 (*指针变量名)(指向的函数的参数类型)

如何得到函数的地址?

在这里插入图片描述

  • &函数名就是函数的地址;
  • 函数名也是函数的地址。
  • 函数名 == &函数名 == 函数的地址

定义函数指针

int (*pf)(int,int) = &add;
int (*pf)(int,int) =  add;
//这两种形式都能将 add 的地址赋给函数指针 pf
  • pf 先和 * 结合,说明 pf 是个指针;
  • 第一个 int 表示 pf 指向的函数的返回类型是个 int;
  • (int,int) 表示 pf 指向的函数的形参为两个 int 类型。

函数指针的使用

  • 对函数指针解引用就相当于找到了原来的函数,
    • 如:*pf 等价于 add。
  • 所以也可以使用函数指针来调用函数。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/883796.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

k-d Tree KD 树 交替建树

这个算法文字不太容易说明白&#xff0c;建议大家看视频&#xff0c;我只是抄下来做个笔记&#xff0c;方便回忆。 视频地址&#xff1a;141 k-d Tree KD 树 交替建树_哔哩哔哩_bilibili KD树的应用 kd树主要应用于多维空间关键数据的搜索&#xff1a; 最邻近搜索&#xff1…

动态规划:最大正方形

题目 在一个由 ‘0’ 和 ‘1’ 组成的二维矩阵内&#xff0c;找到只包含 ‘1’ 的最大正方形&#xff0c;并返回其面积。 示例 1&#xff1a; 输入&#xff1a;matrix [[“1”,“0”,“1”,“0”,“0”],[“1”,“0”,“1”,“1”,“1”],[“1”,“1”,“1”,“1”,“1”]…

Django实现音乐网站 ⑾

使用Python Django框架制作一个音乐网站&#xff0c; 本篇主要是前端开发前的一些必要配置和首页展示开发。 目录 配置应用路由 创建应用路由文件 应用路径加入项目路径 创建项目模板 创建项目及应用模板路径 设置模板路径 设置静态资源路径 创建静态资源路径 配置静态…

ubuntu16编译内核源码并替换

文章目录 1.找到和ubuntu内核版本相同的内核源码包2.下载下面三个文件3.相关步骤4.安装编译环境软件5.报错解决参考&#xff1a; 1.找到和ubuntu内核版本相同的内核源码包 4.15.0-112.113 : linux package : Ubuntu (launchpad.net) 2.下载下面三个文件 3.相关步骤 uname -r …

vue所有UI库通用)tree-select 下拉多选(设置 maxTagPlaceholder 隐藏 tag 时显示的内容,支持鼠标悬浮展示更多

如果可以实现记得点赞分享&#xff0c;谢谢老铁&#xff5e; 1.需求描述 引用的下拉树形结构支持多选&#xff0c;限制选中tag的个数&#xff0c;且超过制定个数&#xff0c;鼠标悬浮展示更多已选中。 2.先看下效果图 3.实现思路 首先根据API文档&#xff0c;先设置maxTagC…

机器人的运动范围

声明 该系列文章仅仅展示个人的解题思路和分析过程&#xff0c;并非一定是优质题解&#xff0c;重要的是通过分析和解决问题能让我们逐渐熟练和成长&#xff0c;从新手到大佬离不开一个磨练的过程&#xff0c;加油&#xff01; 原题链接 机器人的运动范围https://leetcode.c…

Air001外部中断/事件控制器功能

Air001外部中断/事件控制器 ✨对于外部中断&#xff0c;一般单片机基本标配的硬件功能&#xff0c;使用方法也没有什么特别的地方&#xff0c;对于事件控制器&#xff0c;用于停机模式下唤醒单片机功能&#xff0c;但是使用起来很简单,只需配置其引脚模式即可。 &#x1f516;目…

python+django+mysql项目实践五(信息搜索)

python项目实践 环境说明: Pycharm 开发环境 Django 前端 MySQL 数据库 Navicat 数据库管理 信息搜素 输入内容进行搜索,内容有文本类和时间类 文本类需要模糊搜索,包含即检索 时间类需要选取时间范围内的内容 views 利用Q完成对指定内容的检索 检索后按检索内容更新…

Linux简介--基础操作--文件传输(linux-Windows)

简介&#xff1a; 1、linux和windows都是操作系统&#xff0c;多任务&#xff0c;多用户&#xff0c;多线程… Linux免费使用&#xff0c;自由传播&#xff0c;开源 2、Linux 发行版&#xff08;都是基于linux内核穿的外套&#xff09; Ubuntu——嵌入式开发 fedora——早期嵌入…

编程小白的自学笔记十三(python办公自动化读写文件)

系列文章目录 编程小白的自学笔记十二&#xff08;python爬虫入门四Selenium的使用实例二&#xff09; 编程小白的自学笔记十一&#xff08;python爬虫入门三Selenium的使用实例详解&#xff09; 编程小白的自学笔记十&#xff08;python爬虫入门二实例代码详解&#xff09;…

【Linux】IO多路转接——poll接口

目录 poll初识 poll函数 poll服务器 poll的优点 poll的缺点 poll初识 poll也是系统提供的一个多路转接接口。 poll系统调用也可以让我们的程序同时监视多个文件描述符上的事件是否就绪&#xff0c;和select的定位是一样的&#xff0c;适用场景也是一样的。 poll函数 po…

首起针对国内金融企业的开源组件投毒攻击事件

简述 2023年8月9日&#xff0c;墨菲监控到用户名为 snugglejack_org (邮件地址&#xff1a;SnuggleBearrxxhotmail.com&#xff09;的用户发布到 NPM 仓库中的 ws-paso-jssdk 组件包具有发向 https://ql.rustdesk[.]net 的可疑流量&#xff0c;经过确认该组件包携带远控脚本&a…

Qt 之 QPushButton,信号与槽机制

文章目录 前言一、QPushButton二、信号与槽机制总结 前言 一、QPushButton 当我们开发基于Qt框架的图形用户界面&#xff08;GUI&#xff09;应用程序时&#xff0c;经常需要在界面上添加按钮来实现用户交互。Qt提供了一个名为 QPushButton 的类作为按钮控件的实现。QPushButt…

BIO、NIO和AIO

一.引言 何为IO 涉及计算机核心(CPU和内存)与其他设备间数据迁移的过程&#xff0c;就是I/O。数据输入到计算机内存的过程即输入&#xff0c;反之输出到外部存储&#xff08;比如数据库&#xff0c;文件&#xff0c;远程主机&#xff09;的过程即输出。 I/O 描述了计算机系统…

Steam 灵感的游戏卡悬停效果

先看效果&#xff1a; 再看代码&#xff08;查看更多&#xff09;&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Steam 灵感的游戏卡悬停效果</title><style>* {margin: …

云计算虚拟仿真实训平台

一、云计算虚拟仿真系统概述 云计算虚拟仿真系统是一种基于云计算技术和虚拟化技术的系统&#xff0c;用于实现各种仿真和模拟任务。它可以提供强大的计算能力和资源管理&#xff0c;为用户提供灵活、高效、可扩展的仿真环境。 该系统通常由一组服务器、网络和存储设备组成&am…

步入React正殿 - State进阶

目录 扩展学习资料 State进阶知识点 状态更新扩展 shouldComponentUpdate PureComponent 为何使用不变数据【保证数据引用不会出错】 单一数据源 /src/App.js /src/components/listItem.jsx 状态提升 /src/components/navbar.jsx /src/components/listPage.jsx src/A…

【AIGC】 快速体验Stable Diffusion

快速体验Stable Diffusion 引言一、安装二、简单使用2.1 一句话文生图2.2 详细文生图 三、进阶使用 引言 stable Diffusion是一款高性能的AI绘画生成工具&#xff0c;相比之前的AI绘画工具&#xff0c;它生成的图像质量更高、运行速度更快&#xff0c;是AI图像生成领域的里程碑…

【0815作业】搭建select的TCP客户端、poll客户端、tftp文件上传

IO多路复用&#xff08;重点&#xff01;&#xff01;&#xff01;&#xff09; 进程中如果同时需要处理多路输入输出流&#xff0c;在使用单进程单线程的情况下&#xff0c;同时处理多个输入输出请求。在无法用多进程多线程&#xff0c;可以选择用IO多路复用&#xff1b;由于不…

新手开抖店多久可以出单?

​开抖店是一种越来越流行的创业方式&#xff0c;在社交媒体平台上开店销售各种商品&#xff0c;比如服装、配饰、美妆和家居用品等等。对于新手来说&#xff0c;他们可能会很关心自己开抖店能够多久出单。虽然这个问题没有一个固定的答案&#xff0c;但是以下是一些关键的运营…