C语言 指针中的常见名称与用法

2023-05-16

目录

前言

一、指针是什么

二、指针与数组

数组指针

指针数组

三、指针与常量

指针常量

常量指针

四、指针与函数

指针函数

函数指针


前言

指针是C语言中大家接触的比较早但是也是内容比较多和实用的一块知识点,之前虽然也大概知道是什么用途,但是指针衍生出来的内容还是比较容易混淆的,这次在7哥的激励下写篇博客总结一下指针方面易混淆的内容,如有错误欢迎指正。


一、指针是什么

指针变量其实就是存放地址的变量,我们知道变量具有三部分信息,即

  1. 变量对应的名称
  2. 所表示的数据类型
  3. 存放的值。


大家都知道指针变量存放的是一个内存地址,但是有时候却忽略了指针类型的重要性,根据存放的地址值我们可以知道要从什么位置开始读取数据,而类型信息则向系统补充说明了当指针移动时进行读写的长度,确定我们要读取到什么位置结束。

因为指针变量是存放地址的变量,所以一个指针变量所占的地址空间是固定的,是根据我们程序的寻址空间来确定的(比如寻址空间 4GB = 2^32 Byte,也就是32位的CPU可以访问的最大内存空间,字节在计算机中是最小的可寻址单位,所以用 4 个字节即 2^32 bits 表示指针就已经能指向任何内存空间了,同理64位系统默认指针大小为8个字节。),所以指针的大小根据不同的操作系统为4个或8个字节
上面说明的是指针变量本身的所占的空间大小,而指针变量的值,也就是存放的地址信息,本质上都是一段地址而已,而指针的类型则确定了要将地址中的值按照 int 型变量还是 double 型等不同的数据类型变量进行解释

那么了解了指针,接下来要面对的就是 数组指针 指针数组 指针常量 常量指针 函数指针 指针函数这些牛鬼蛇神,虽然名字看起来很唬人非常容易混淆,接下来将一一进行说明,先总结一下它们各自的定义如下:
 

常见指针变量的定义
定义含义
int  i定义整形变量
int *p定义一个指向int的指针变量
int *const p定义一个指向int的指针常量指针常量
int const * p
const int * p
定义一个指向int的只读指针常量指针
int a[10]定义一个int数组
int *p[10]定义一个指针数组,其中每个数组元素指向一个int型变量的地址指针数组
int (*p)[10]定义一个数组指针,指向int [10]类型的指针变量数组指针
int func(  )定义一个函数,返回值为int型
int *func(  )定义一个函数,返回值为int *型指针函数
int (*p)(  )定义一个指向函数的指针,函数的原型为无参数,返回值为int函数指针
int **p定义一个指向int的指针的指针,二级指针


二、指针与数组

C语言规定,数组名代表数组中首个元素(即序号为 0 的元素)的地址,也就是说,如果 s 是一个数组,那么表达式 s 的值就与 s[0] 的地址,即 &s[0] 一致。所以当我们执行赋值语句 p = &s[0]  时,指针变量 p 与数组名 s 具有相同的值,可以写作 p = s ,指针 p 的行为就和数组 s 本身一样。p 在这里指向的是数组的首元素。

int s[3]={1,2,3};
int *p 
p = &s[0];

数组指针

数组指针就是指向数组的指针,声明形式为 类型(*变量名)[]
因为数组下标 [] 的优先级高于取值运算符 * ,所以必须用括号()将 * 与 arrPtr 先结合构成指针定义,然后指向一个数组。


第一种情况(指向二维数组名):

int a[4][10];  
int (*p)[10];  
p = a;

与一维数组的数组名是一个指针相似,二维数组的数组名是一个数组指针,若将二维数组名 a 赋值给数组指针 p ,则可以通过 p 直接控制数组 a

3ab4e13b406c408497d6870a8c3cf889.png

第二种情况(指向一维数组名的地址):

int a[10];  
int (*p)[10] = &a; //此处是&a,不是a, &a的类型是int(*)[]  
int *q = a;

8a07ee1ff3474180bd8b7f3a7b42affa.png

p 与 q 虽然都指向数组的第一个元素,但由于 p 的类型和 q 的类型不同 ,数组指针 p 是指向10个元素整形数组的指针, *p 的大小是40个字节,所以 p+1 跳过40个字节;q 是指向整形的指针,*q 的大小是4个字节,所以 q+1 跳过4个字节。


指针数组

int * arrPtr[10]; //声明一个指针数组arrPtr,该数组有10个int类型的指针

元素为指针类型的数组,声明形式为 类型名 * 数组名[数组长度]
由于指针也是变量,所以指针也可以像其他变量一样存储在数组中。指针数组的每一个元素都是一个指针类型的数据,即元素的值为地址,可以指向某一个字符串常量。

指针数组最频繁的用处是存放具有不同长度的字符串,作为二维数组的一种便捷替代方式,适合用来存放多个字符串作为字符串数组来使用。
我们在遇到需要处理多个字符串的情况时,可以选择将它们存储在一个二维数组中,二维数组的元素 —— 一维数组 的大小必须足够存储下可能出现的最长字符串,如下表示:

#define ARRAY_LEN 12
#define STRLEN_MAX 25
char pStrings[ARRAY_LEN][STRLEN_MAX] = 
{
	"It's a wonderful day!",
	"do you like it?",
	"Yes"
};

for(i=0;i<ARRAY_LEN;i++)
{
	puts(pstr[i]);
}

但是,这个方式造成内存浪费,一方面,短字符串会让大部分的行是空的,另一方面,有些行根本没有使用到,但却得为它预留内存,使得分配的12*25=300 个字节只有一小部分被实际使用到。
对于这个问题,一个简单的解决方案就是使用指针数组,让指针指向字符串,然后只给实际存在的对象分配内存,未用到的数组元素则默认是空指针。

#define ARRAY_LEN 12
char *pStrings[ARRAY_LEN] =
{
	"It's a wonderful day!",
	"do you like it?",
	"Yes"
};

指针数组让各个指针内容可以按需要动态生成,避免了空间浪费,并且各个指针呈数组形式排列,索引起来非常方便。

指针数组另一个常见作用是作为main函数的形式参数

int main(int argc, char * argv[]);

argc 和 argv 主要用途为程序运行时,将命令行中的输入参数传递给调用函数。char * argv[] 是一个存储字符串的指针数组,会以字符串的形式保存用户调用程序时传入的参数,存放着指向每一个参数的指针。


三、指针与常量

const 是一个C语言的类型限定符,任何变量只要其类型限定符为 const ,则表示对于这些变量,我们无法在后续的程序中修改其对应或指针指向的值。因此,我们常称它们为常量,但其实应该说是个“只读变量”而非常量,只读变量和常量的共同点在于它们的值在第一次出现时便被确定,且无法在后续程序中被修改。但是只读变量和常量的一个最重要的不同点在于,要注意使用 const 修饰的只读变量不具有“常量表达式”的属性,因此无法用来表示定长数组大小,或者是使用在case语句中。常量表达式本身会在程序编译时被求知,而只读变量的值只能够在程序实际运行时才被得知。所以这边大家要知道他们之间是有一定的区别的,但是下面仍用常量来指代只读变量。

#include <stdio.h>
int main(void)
{
	const int temp = 10;
	int a;
	scanf("%d",&a);
	int s[temp] = {1,2,3} /* 错误,使用非常量表达式定义定长数组 */
	switch(a){
	case temp: printf("you have a trouble"); break; /* 错误:非常量表达式应用于case语句 */
	}
}

const 限定一个变量不允许被改变,使用在指针变量中可以用来限定指针本身的类型,或者是限定指针所指对象的类型,分别对应着我们的指针常量和常量指针。


指针常量

int * const p;

直译是指针类型的常量,联系我们刚刚提到的“只读变量”,我们可以理解成指针类型的“只读变量”,它是一个指针变量但是这个变量是“只读变量”。

而变量是只读的说明了指针其本身存放的内容(值)也就是指向的位置(地址)不能改变,指针本身是一个常量,但是指针所指向的内容(值)是不受限制可以发生改变的。

int a = 1, b = 2;
int * const p = &a; //指针常量
*p = 3; // 可以赋值,指针指向的内容可以修改 
p = &b; /* 错误,指针常量本身的内容不可改变,其值即指向的地址是固定的 */

常量指针

//两种方式都可
const int *p = &a; 
int const *p = &a;

直译是指向常量的指针,同样的我们可以理解成指向“只读变量”的指针,首先是一个指针,其次这个指针是一个指向“只读变量”(具有const限定的变量)的指针,所以可以修改该指针本身的值,但是只能使用这样的指针来读取所指向的对象,不能修改所指向的对象,因此指向常量的指针也常常被称为“只读指针”。

int a = 1, b = 2;
const int *p1 = &a; //常量指针
p = &b; // 可以赋值,因为指针本身是变量,其本身存放的内容即指向的地址是可以改变的
*p = 3; /* 错误,不能修改指向的对象内容 */


四、指针与函数

指针函数

int * function(int x);

返回指针类型的函数,我们知道一个函数的返回值可以是各种数据类型的,我们常见的是整型的当然也可以是返回的指针类型的数据,即返回一个地址。


函数指针

指向函数的指针,声明形式为 函数返回值类型名(* 指针变量名)(函数参数列表)
与数组名代表数组首个元素地址类似,函数名会被隐式的转换成函数指针,可以说函数名本身就可以表示该函数的入口地址,赋值语句 p = function 将函数function()的地址赋值给指针变量 p ,然后就可以利用该指针调用这个函数。

int function(int a, int b);//假设这里定义了一个函数
int (* p)(int, int); //声明一个函数指针,该函数具有两个int类型的参数和int类型的返回值
p = function;        //把函数名赋值给函数指针 *p
int ret = function(10,100);//调用函数的方式1:通过函数名直接调用
int ret2 = (* p)(10,100);  //调用函数的方式2:通过函数指针调用 

函数指针的定义其实就是将“函数声明”中的“函数名”改成“(*指针变量名)”。但是这里需要注意的是:“(*指针变量名)”两端的括号不能省略,括号改变了运算符的优先级。如果省略了括号,就不是定义函数指针而是一个返回值类型为指针型的函数声明了。
函数指针变量既然是一个变量,当然也可以作为某个函数的参数来使用的,这就是我们函数指针的一个常见用法:回调函数
如果把函数指针作为参数传递给另一个函数,当这个函数指针被用来调用其所指向的函数时,就是一个回调函数。它使得用户可以把需要调用的方法的指针作为参数传递给一个函数,我们只要改变传进另一个函数的参数,就能够让另外这个函数实现不同的功能,相比普通的函数调用灵活很多。 

int Callback_1(int a)   ///< 回调函数1
{
    printf("Hello, this is Callback_1: a = %d ", a);
    return 0;
}

int Callback_2(int b)  ///< 回调函数2
{
    printf("Hello, this is Callback_2: b = %d ", b);
    return 0;
}

int Callback_3(int c)   ///< 回调函数3
{
    printf("Hello, this is Callback_3: c = %d ", c);
    return 0;
}

int Handle(int x, int (*Callback)(int)) ///< 注意这里用到的函数指针定义
{
    Callback(x);
}

int main()
{
    Handle(4, Callback_1);
    Handle(5, Callback_2);
    Handle(6, Callback_3);
    return 0;
}


 参考链接:

C语言-数组指针,指针数组与数组名的指针操作

C语言回调函数详解(全网最全)_小熊coder的博客-CSDN博客_c语言回调函数

C 语言中的指针与数组

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言 指针中的常见名称与用法 的相关文章

  • 【机器学习实战 Task1】 (KNN)k近邻算法的应用

    1 背景 1 1 k近邻算法的概述 xff08 1 xff09 k近邻算法的简介 k 近邻算法是属于一个非常有效且易于掌握的机器学习算法 xff0c 简单的说就是采用测量不同特征值之间距离的方法对数据进行分类的一个算法 xff08 2 xf
  • 【Python量化分析100例】Day1-使用Tushare获取数据

    1 背景 Tushare平台是目前使用python学习量化投资比较好用的而且是免费的一个数据获取平台 主要实现对金融数据从数据采集 清洗加工 到 数据存储的过程 xff0c 能够为金融分析人员提供快速 整洁 和多样的便于分析的数据 xff0
  • python报错:TypeError: Cannot interpret ‘<attribute ‘dtype‘ of ‘numpy.generic‘objects>‘as a data type

    原因 xff1a pandas和matplotlib版本不匹配 方案1 conda更新一下所有包 conda update n base conda 方案2 pip 更新最新版pandas pip install pandas upgrad
  • 【阿里云天池算法挑战赛】零基础入门NLP - 新闻文本分类-Day2-数据读取与数据分析

    一 赛题解析 阿里云天池算法挑战赛 零基础入门NLP 新闻文本分类 Day1 赛题理解 202xxx的博客 CSDN博客 二 数据读取 下载完成数据后推荐使用anaconda xff0c python3 8进行数据读取与模型训练 首先安装需
  • 【阿里云天池算法挑战赛】零基础入门NLP - 新闻文本分类-Day3-基于机器学习的文本分类

    一 赛题解析 阿里云天池算法挑战赛 零基础入门NLP 新闻文本分类 Day1 赛题理解 202xxx的博客 CSDN博客 二 数据读取与数据分析 阿里云天池算法挑战赛 零基础入门NLP 新闻文本分类 Day2 数据读取与数据分析 202xx
  • 【清华大学】2021元宇宙研究报告

    关于元宇宙的详细介绍 xff1b 来源 xff1a 软件定义世界 xff08 SDX xff09
  • MAC OS M1 安装MySQL

    xff08 1 xff09 进入mysql官网下载mysql http www mysql com downloads xff08 2 xff09 选择对应下载版本 xff08 3 xff09 选择直接下载 xff08 4 xff09 下载
  • PX4开源飞控位置控制解析

    位置控制的总体思路为串级PID控制算法 xff0c 内环为对速度的PID控制 xff0c 外环为对位置的比例控制 xff0c 被控对象为四旋翼无人机 xff0c 被控量为四旋翼无人机输出的推力矢量和 xff0c 将测量到的位置与速度进行反馈
  • ONOS意图框架

    1 意图基本概念 Intent是用于描述应用需求的不可变模型对象 xff0c ONOS核心根据其改变网络行为 在最低级别上 xff0c 可以用以下方式描述意图 即意图的组成 xff1a 1 Network Resource xff1a 一组
  • prometheus-4种metric类型说明

    前提了解 prometheus中存储的数据都是时序型 xff0c 其数据模型都是如下 xff1a metric name label 61 value value timestamp 下文中说的数据类型只是客户端的封装 prometheus
  • ROS2 中常用坐标系

    ROS2 中常用坐标系 frame id xff1a 用来告诉你 xff0c 发布的数据是来自哪一个坐标系的 在使用ROS进行定位导航等操作时 xff0c 我们经常会遇到各种坐标系 每种坐标系都有明确的含义 理论上坐标系的名称可以是随意的
  • 国密SM2算法

    目录 1 前言 2 基础参数 3 密钥对生成 4 签名算法 4 1 预处理1 4 2 预处理2 4 3 生成签名 4 4 签名验证 4 5 签名验证原理 5 参考资料 1 前言 比原链的智能合约支持国密算法的函数 SM2是国密标准的椭圆曲线
  • STM32——ARM与STM32之间的联系

    ARM与STM32之间的联系 stm32是基于ARM内核的一种控制器 xff0c 是包含与被包含的关系 ARM xff08 STM32 xff09
  • VTK坐标转换

    VTK坐标转换
  • 软件工程师校招面试救急包

    LeetCode牛人总结 xff08 手撕代码前看看 xff0c 抱佛脚 xff09 https github com labuladong fucking algorithm blob master README md 剑指offer x
  • unix环境高级编程——UNIX体系架构

    本期主题 xff1a unix环境高级编程 UNIX体系架构 文件IO 0 初始UNIX1 系统调用2 库函数2 1 C语言的运行库 3 shell 0 初始UNIX 这里略过unix的历史不讲 xff0c 网上有比较详细的资料 我们可以将
  • CVPR2019:无监督深度追踪

    本文提出了一种无监督的视觉跟踪方法 与使用大量带注释数据进行监督学习的现有方法不同 xff0c 本文的CNN模型是在无监督的大规模无标签视频上进行训练的 动机是 xff0c 强大的跟踪器在向前和向后预测中均应有效 xff08 即 xff0c
  • 各种智能优化算法比较与实现(matlab版)

    各种智能优化算法比较与实现 xff08 matlab版 xff09 一 方法介绍 1免疫算法 xff08 Immune Algorithm xff0c IA xff09 1 1算法基本思想 免疫算法是受生物免疫系统的启发而推出的一种新型的智
  • 我与人工智能的故事

    本文作者 xff1a 诸葛越 前 言 人工智能的三次浪潮 2018年年初 xff0c 招聘季正如火如荼地进行 xff0c 而 数据科学家 和 算法工程师 绝对算得上热门职业 人工智能 机器学习 深度学习 建模 卷积神经网络 等关键词 xff

随机推荐

  • ovn-architecture

    参考 文章目录 1 Name2 Description2 1 Information Flow in OVN OVN中的信息流向 2 2 Chassis Setup2 3 Logical Networks2 4 Life Cycle of
  • IDEA创建maven项目添加jar包依赖出错

    Problem1 xff1a 由于网络原因无法下载jar包 解决方法 xff1a 在maven的settings xml文件的 lt mirrors gt 标签中配置阿里镜像 lt mirror gt lt id gt nexus aliy
  • 判断一个字符串是否为回文字符串

    题目 输入一个字符串 xff0c 判断该字符串中除去空格之后的字符串是否为回文字符串 要求 xff1a 不可使用 Java 已实现的方法替换空格 xff0c 不可消耗额外的空间 代码实现 此处为判断方法的实现 public static b
  • Spring中的 JdbcTemplate和声明式事务控制

    Spring中的 JdbcTemplate和声明式事务控制 JdbcTemplate概述 JdbcTemplate的作用 xff1a 他就是用于和数据库交互的 xff0c 实现CRUD操作 如何创建该对象 在dao的实现类中定义并用set方
  • SpringMVC(一)

    SpringMVC xff08 一 xff09 SpringMVC的基本概念 三层架构 表现层业务层持久层 MVC模型 Model xff08 模型 xff09 xff1a 通常就是指我们的数据模型 xff0c 一般情况下用于封装数据 Vi
  • SpringMVC(二)

    SpringMVC xff08 二 xff09 响应数据和结果视图 返回值分类 xff1a 字符串voidModelAndView 对象 xff1a 是 spring 提供的一个对象 xff0c 可以用来调整具体的 JSP 视图 span
  • SpringMvc(三)

    SpringMvc xff08 三 xff09 SSM 整合可以使用多种方式 xff0c 一般会选择 XML 43 注解 的方式 整合的思路 xff1a 搭建整合环境先把spring 的配置搭建完成再使用 spring 整合SpringMV
  • 工厂方法模式(Factory Method)--多态工厂的实现

    工厂方法模式 xff08 Factory Method xff09 多态工厂的实现 定义 xff1a 定义一个用于创建对象的接口 xff0c 让子类决定实例化哪一个类 xff0c 工厂方法使一个类的实例化延迟到其子类 类图 xff1a 外链
  • 无人机自主定位导航避障VINS+fast_planner实测~

    厦大研一研究的一个项目 xff0c 将项目开发用到的技术和难点在这记录一下 常更新 xff0c 先把框架写好 xff0c 有空的时候就过来更新 xff0c 要是有漏的或者有错误的地方 xff0c 请大佬指点 因为采用的是TX2 xff0c
  • rs_D455相机内外参标定+imu联合标定

    IMU标定 lt launch gt lt node pkg 61 34 imu utils 34 type 61 34 imu an 34 name 61 34 imu an 34 output 61 34 screen 34 gt lt
  • GVINS论文简明解读

    VIN与GNSS融合的必要性 VIN系统只工作在局部坐标系下 x y z yaw不可观 里程计存在不可避免的漂移 而GNSS系统可提供无漂移的全局定位 VIN与GNSS融合的难点 不同于cmaera与imu此类的外参标定 GNSS坐标与VI
  • onos2.5.2编译安装

    onos编译安装 Ubuntu18 04 1 前置下载安装 1 1 前置包安装 参考docker file sudo apt get install y ca certificates zip python python3 git bzip
  • C++和C的区别(汇总)

    1 C是面向过程的语言 xff0c 而C 43 43 是面向对象的语言 2 C和C 43 43 动态管理内存的方法不一样 xff0c C是使用malloc free函数 xff0c 而C 43 43 除此之外还有new delete关键字
  • PX4学习笔记—通过串口发送自定义数据

    最近因为项目需要实现一个通过pixhawk串口收发自定义数据的功能 搜索发现 xff0c 博客上大神们FantasyJXF FreeApe的博文已经详细介绍了通过pixhawk串口读取自定义数据 xff0c 这部分功能实现后就可以将自己开发
  • 一步步入门搭建SpringSecurity OAuth2(密码模式)

    什么是OAuth2 xff1f 是开放授权的一个标准 xff0c 旨在让用户允许第三方应用去访问改用户在某服务器中的特定私有资源 xff0c 而可以不提供其在某服务器的账号密码给到第三方应用 大概意思就是比如如果我们的系统的资源是受保护的
  • STM32驱动SG90舵机与HC_SR04超声波模块

    前言 一 项目涉及的内容 项目简介 二 模块实操 1 SysTick系统定时器模块 2 SG90 舵机模块 3 HC SR04 超声波模块 4 main函数 总结 前言 这篇文章的内容主要对一个超声波 43 舵机小项目进行总结 xff0c
  • STM32基于IIC协议的OLED模块的使用

    前言 一 项目涉及的内容 项目简介 二 模块实操 1 IIC模块 1 1 IIC协议格式 1 2 开始信号与停止信号 1 3 写数据 1 3 1 硬件IIC代码编写 1 3 2 软件模拟IIC代码编写 2 OLED板块 前言 本篇文章对使用
  • STM32DMA功能详解

    目录 一 DMA的基本介绍 1 什么是DMA xff08 DMA的基本定义 xff09 2 DMA传输参数 3 DMA的主要特征 二 DMA功能框图 1 DMA请求 2 通道 3 仲裁器 三 DMA 数据配置 1 从哪里来到哪里去 外设到存
  • STM32对FreeRTOS单片机实时操作系统的移植

    前言 一 FreeRTOS是什么 二 FreeRTOS的移植 1 资料下载 2 开始移植 2 1 移植Source源码文件 2 2 添加 FreeRTOSConfig h 2 3 添加SYSTEM文件夹 2 4 复制 main c 文件进行
  • C语言 指针中的常见名称与用法

    目录 前言 一 指针是什么 二 指针与数组 数组指针 指针数组 三 指针与常量 指针常量 常量指针 四 指针与函数 指针函数 函数指针 前言 指针是C语言中大家接触的比较早但是也是内容比较多和实用的一块知识点 xff0c 之前虽然也大概知道