C语言 之 理解指针(4)
文章目录
- 1. 字符指针变量
- 2. 数组指针变量
- 2.1 对数组指针变量的理解
- 2.2 数组指针变量的初始化
- 3. 二维数组传参的本质
- 4. 函数指针变量
- 4.1 函数指针变量的创建
- 4.2 函数指针变量的使用
- 5. 函数指针数组
1. 字符指针变量
我们在前面使用的主要是整形指针变量,现在要学习的是字符指针变量。
一般使用:
int main()
{char ch = 'a'; //字符变量char *pc = &ch; //字符指针变量*pc = 'b';return 0;
}
除了上面这种用法外,还有用于字符串。
如:
#include<stdio.h>
int main()
{const char* pstr = "hello world";printf("%s\n", pstr);return 0;
}
输出结果为:

代码 const char* pstr = "hello world"; 要注意:并不是把字符串hello world放入了字符指针变量pstr中,其本质是把字符串hello world的首个字符的地址放到了pstr中。

上面的代码如图所示,即把常量字符串的首字符h的地址存到了pstr中
相关例题:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{char str1[] = "hello world";char str2[] = "hello world";const char* str3 = "hello world";const char* str4 = "hello world";if (str1 == str2)printf("str1 and str2 are same\n");elseprintf("str1 and str2 are not same\n");if (str3 == str4)printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");return 0;
}
输出结果为:

首先就像之前所说的,数组名是首元素的地址,str1和str2两个数组的内容虽然相同,但是使用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块,所以他们的地址是不同的。而对于str3和str4来说,它们是字符指针,它们指向的是同⼀个常量字符串。C语言中会把常量字符串存储到单独的⼀个内存区域,当⼏个指针指向同⼀个字符串的时候,实际上指向的是同⼀块内存。
2. 数组指针变量
2.1 对数组指针变量的理解
之前我们学习了指针数组,所以我们知道指针数组是用来存放指针的数组
那么数组指针变量是指针变量?还是数组?
答:指针变量
结合我们之前所学:
整形指针变量:int * p; 存放的是整形变量的地址,能够指向整形数据的指针。
字符指针变量:char * p; 存放的是字符变量的地址,能够指向字符数据的指针。
由此可得:数组指针变量应该是存放数组的地址,能够指向数组的指针变量。
数组指针变量:
int (*p)[10];
解释: p和*结合,说明了p是一个指针类型的变量,然后指针指向的是一个大小为10个整形的数组。所以
p是⼀个指针,指向⼀个数组,叫作数组指针。
要注意的是:[]的优先级要⾼于*号,所以必须加上()来保证p先和 * 结合。
不能写成int *p[10];
2.2 数组指针变量的初始化
首先我们需要知道,数组指针变量是用来存放数组的地址的。
要想获得数组的地址,就得使用我们之前所学的操作符&
我们也知道,除了两个特殊情况,数组名就是首元素的地址,而这两个特殊情况中,&arr就是取整个数组的地址。
这里的&arr就是取了整个数组的地址,我们之前所学的指针存的都是一个地址,所以现在要想存一整个数组的地址,我们就得用到数组指针了。
int arr[10] = {0};
&arr;//得到的就是数组的地址
使用数组指针变量存放整个数组的地址:
int(*p)[10] = &arr;

3. 二维数组传参的本质
在之前我们有⼀个⼆维数组的需要传参给⼀个函数的时候,我们可能是这样写的:
#include <stdio.h>
void test(int a[3][5], int r, int c)
{int i = 0;int j = 0;for (i = 0; i < r; i++){for (j = 0; j < c; j++){printf("%d ", a[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} };test(arr, 3, 5);return 0;
}
这里的实参是二维数组,形参部分也写成了二维数组的形式,结合刚才所学,是否还有其它写法?
首先让我们再来回忆一下我们对数组的了解,假如有一个整形数组,那么它的每一个元素就是一个整形变量,那么二维数组呢?其实二维数组就可以看作是每个元素都是一维数组的数组,即二维数组的每个元素都是一维数组。那么一维数组的首元素就是第一个变量,二维数组的首元素就是二维数组的第一行,即第一个一维数组。

所以,根据数组名是数组首元素的地址这个规则,⼆维数组的数组名表示的就是第⼀行的地址,是⼀维数组的地址。根据上面的例子,第⼀行的⼀维数组的类型就是 int [5] ,所以第⼀行的地址的类
型就是数组指针类型 int(*)[5](注:对于数组,去掉数组名就是类型) 我们也知道,数组传参的本质是传首元素的地址,那就意味着⼆维数组传参本质上也是传递地址,传递的是第⼀行这个⼀维数组的地址,由于这个二维数组的首元素地址是一整个数组,那么形参也是可以写成指针形式的,即数组指针变量的形式。代码如下:
#include <stdio.h>
void test(int(*p)[5], int r, int c)
{int i = 0;int j = 0;for (i = 0; i < r; i++){for (j = 0; j < c; j++){printf("%d ", *(*(p + 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} };test(arr, 3, 5);return 0;
}
总结:二维数组传参,形参的部分可以写成数组,也可以写成指针形式。
4. 函数指针变量
4.1 函数指针变量的创建
经过我们前面的学习,通过类比
整形指针变量:int * p; 存放的是整形变量的地址,能够指向整形数据的指针。
字符指针变量:char * p; 存放的是字符变量的地址,能够指向字符数据的指针。
以及刚才的数组指针变量,所以我们就可以知道
函数指针变量是能够存放函数的地址,能够指向函数数据的指针啦。
所以,函数也是有地址的喔,我们可以来看看:
#include <stdio.h>
void test()
{printf("hehe\n");
}
int main()
{printf("test: %p\n", test);printf("&test: %p\n", &test);return 0;
}
输出结果为:

上面的例子中打印出来了地址,所以函数是有地址的,并且函数名就是函数的地址,当然也可以通过 &函数名的方式获得函数的地址。
如果我们要将函数的地址存放起来,就得创建函数指针变量
函数指针变量的写法和数组指针变量的写法类似
如下:
例1:无参型
void test()
{printf("hehe\n");
}
void (*pf1)() = &test;
void (*pf2)() = test;
例2:带参型
int Add(int x, int y)
{return x + y;
}
int (*pf3)(int, int) = Add;
int (*pf3)(int x, int y) = &Add; //x和y写上或者省略都是可以的
解析:

4.2 函数指针变量的使用
通过函数指针调⽤指针指向的函数
#include <stdio.h>
int Add(int x, int y)
{return x + y;
}
int main()
{int(*pf3)(int, int) = Add;printf("%d\n", (*pf3)(1, 2));printf("%d\n", pf3(10, 20));return 0;
}
输出结果:

5. 函数指针数组
我们前面已经学习了指针数组了,即所存放的每个元素是指针的数组。
如:
int *arr[10];
//数组的每个元素是int*
那么如果我们想要把每个函数的地址存放到数组中,这个数组就叫作函数指针数组
函数指针数组的定义:
int (*parr[3])();
parr 先和 [ ] 结合,说明 parr是数组,数组的内容是什么呢?是 int (*)() 类型的函数指针。
函数指针数组的使用 可以点击此处查看
相关文章:
C语言 之 理解指针(4)
文章目录 1. 字符指针变量2. 数组指针变量2.1 对数组指针变量的理解2.2 数组指针变量的初始化 3. 二维数组传参的本质4. 函数指针变量4.1 函数指针变量的创建4.2 函数指针变量的使用 5. 函数指针数组 1. 字符指针变量 我们在前面使用的主要是整形指针变量,现在要学…...
Java设计模式—单例模式(Singleton Pattern)
目录 一、定义 二、应用场景 三、具体实现 示例一 示例二 四、懒汉与饿汉 饿汉模式 懒汉模式 五、总结 六、说明 一、定义 二、应用场景 单例模式的应用场景主要包括以下几个方面: 日志系统:在应用程序中,通常只需要一个日…...
AV1帧间预测(二):运动补偿
运动补偿(Motion Compensation,MC)是帧间预测最基础的工具,AV1支持两种运动补偿方式,一种是传统的平移运动补偿,另一种是仿射运动补偿。下面分别介绍这两种运动补偿方法。 平移运动补偿 平移运动补偿是最传统的运动补偿方式,H.26…...
数学建模(5)——逻辑回归
一、二分类 import numpy as np import matplotlib.pyplot as plt from sklearn import datasets from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklea…...
【C++高阶】:深入探索C++11
✨ 心似白云常自在,意如流水任东西 🌏 📃个人主页:island1314 🔥个人专栏:C学习 🚀 欢迎关注:👍点赞 Ǵ…...
6. 自定义Docker镜像
如何自定义Docker镜像:从基础到实践 Docker作为一个容器化平台,使得应用的打包、分发和运行变得更加高效和便捷。本文将详细介绍如何自定义一个Docker镜像,包括镜像的构成、分层原理、创建自定义镜像的具体步骤,并演示如何打包和…...
「12月·长沙」人工智能与网络安全国际学术会议(ISAICS 2024)
人工智能与网络安全国际学术会议(ISAICS 2024)将于2024年12月20日-2024年12月22日在湖南长沙召开。会议中发表的文章将会被收录,并于见刊后提交EI核心索引。会议旨在在为国内与国际学者搭建交流平台,推进不同学科领域的融合发展,就当今人工智能与网络安全范畴内各学…...
【技术支持案例】使用S32K144+NSD8381驱动电子膨胀阀
文章目录 1. 前言2. 问题描述3. 理论分析3.1 NSD8381如何连接电机3.2 S32K144和NSD8381的软件配置 4.测试验证4.1 测试环境4.2 测试效果4.3 测试记录 1. 前言 最近有客户在使用S32K144NSD8381驱动电子膨胀阀时,遇到无法正常驱动电子膨胀阀的情况。因为笔者也是刚开…...
第二期:集成电路(IC)——智能世界的微观建筑大师
嘿,小伙伴们!👋 我是你们的老朋友小竹笋,一名热爱创作和技术的工程师。上一期我们聊了聊AI芯片,这次我们要深入到更微观的层面,来探究集成电路(IC)的世界。准备好一起探索了吗&#…...
基于物联网的区块链算力网络,IGP/BGP协议
目录 基于物联网的区块链算力网络 IGP/BGP协议 IGP(内部网关协议) BGP(边界网关协议) 内部使用ISP的外部使用BGP的原因 一、网络规模和复杂性 二、路由协议的特性 三、满足业务需求 四、结论 基于物联网的区块链算力网络 通 过 多个物联网传感器将本地计算…...
每日一题~960 div2 A+B+C(简单奇偶博弈,构造,观察性质算贡献)
A题意: N 长的数组。 一次操作: 最开始的mx 为零。 选出一个数(使得这个数>mx) ,之后将mx 更新为这个数,将这个数置为零。 不能做这个操作的,输。 问是否有先手赢的策略。有的话,输出yes 否则no 当时一…...
音视频入门基础:H.264专题(17)——FFmpeg源码获取H.264裸流文件信息(视频压缩编码格式、色彩格式、视频分辨率、帧率)的总流程
音视频入门基础:H.264专题系列文章: 音视频入门基础:H.264专题(1)——H.264官方文档下载 音视频入门基础:H.264专题(2)——使用FFmpeg命令生成H.264裸流文件 音视频入门基础&…...
Aboboo一些操作
常用快捷键⌨ 快捷键/操作方式 功能 鼠标中键/Esc 进入/退出全屏 空格/Tab 暂停/恢复播放 左/右箭头 快退/快进 Ctrl-左/右箭头 30秒快退/快进 Alt-左/右箭头 60秒快退/快进 Ctrl-Alt-左/右箭头 播放速率调节 PageUp/PageDown 上一句/下一句 上下箭头/滚轮 …...
获取行号LineNumberReader
(每日持续更新)jdk api之LineNumberReader基础、应用、实战-CSDN博客...
python数据结构与算法
0.时间复杂度和空间复杂度 快速判断算法时间复杂度:算法运行时间 1.确定问题规模n 2.循环减半 logn 3.k层关于n的循环 n^k 空间复杂度:评估算法内存占用大小 使用几个变量 O(1) 使用长度为n的一维列表 O(n)…...
大数据学习之Flink基础(补充)
Flink基础 1、系统时间与事件时间 系统时间(处理时间) 在Sparksreaming的任务计算时,使用的是系统时间。 假设所用窗口为滚动窗口,大小为5分钟。那么每五分钟,都会对接收的数据进行提交任务. 但是,这里有…...
C++基础语法:友元
前言 "打牢基础,万事不愁" .C的基础语法的学习."学以致用,边学边用",编程是实践性很强的技术,在运用中理解,总结. 以<C Prime Plus> 6th Edition(以下称"本书")的内容开展学习 引入 友元提供了一种特别的方式,访问对象私有数据. 友元有三…...
【大模型系列】Video-LaVIT(2024.06)
Paper:https://arxiv.org/abs/2402.03161Github:https://video-lavit.github.io/Title:Video-LaVIT: Unified Video-Language Pre-training with Decoupled Visual-Motional TokenizationAuthor:Yang Jin, 北大&#x…...
【总结】nacos作为注册中心-应用启动失败:NacosDiscoveryProperties{serverAddr=‘127.0.0.1:8848‘……
问题现象 启动springboot应用时报错,能够读取到nacos配置,但是使用nacos作为注册中心,应用注册到nacos失败。 应用配置bootstrap.properties如下: # 应用编码,安装时替换变量 spring.application.namedata-center #…...
C语言——数组和排序
C语言——数组和排序 数组数组的概念数组的初始化数组的特点 排序选择排序冒泡排序插入排序 二分查找 数组 数组的概念 数组是一组数据 ; 数组是一组相同类型的数据或变量的集合 ; 应用场景: 用于批量的处理多个数据 ; 语法&…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...
搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
小木的算法日记-多叉树的递归/层序遍历
🌲 从二叉树到森林:一文彻底搞懂多叉树遍历的艺术 🚀 引言 你好,未来的算法大神! 在数据结构的世界里,“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的,它…...
