c++ 指针总结

概述

  • 内存地址
  • 在计算机内存中,每个存储单元都有一个唯一的地址(内存编号)。
  • 通俗理解,内存就是房间,地址就是门牌号

  • 指针和指针变量
  • 指针(Pointer)是一种特殊的变量类型,它用于存储内存地址。
  • 指针的实质就是内存“地址”
  • 指针变量就是存储这个地址的变量。

  • 指针作用
  • 可间接修改变量的值

指针变量的定义和使用

  • 指针也是一种数据类型,指针变量也是一种变量
  • 指针变量指向谁,就把谁的地址赋值给指针变量
  • 语法格式:

类型 变量;
类型 * 指针变量 = &变量;

  • & 叫取地址,返回操作数的内存地址
  • * 叫解引用,指操作指针所指向的变量的值
  • 在定义变量时,* 号表示所声明的变量为指针类型
  • 指针变量要保存某个变量的地址,指针变量的类型比这个变量的类型多一个*
  • 指针使用时,* 号表示操作指针所指向的内存空间

#include <stdio.h>int main() {// 定义一个int类型的变量,同时赋值为10int a = 10;// 打印变量的地址printf("&a = %p\n", &a);// 定义一个指针变量,int *保存int的地址// int *代表是一种数据类型,int *指针类型,p才是变量名int* p;// 指针指向谁,就把谁的地址赋值给这个指针变量p = &a;// 打印p, *p, p指向了a的地址,*p就是a的值printf("p = %p, *p = %d\n", p, *p);return 0;
}

通过指针间接修改变量的值

  • 指针变量指向谁,就把谁的地址赋值给指针变量
  • 通过 *指针变量 间接修改变量的值

#include <stdio.h>int main() {// 定义一个int类型变量a,同时赋值为0int a = 0;// 定义int *指针变量,同时赋值a的地址int *p = &a;// 通过指针间接修改a的值*p = 123;printf("a = %d\n", a);// 定义一个int类型变量b,同时赋值为5int b = 5;// p 保存 b的地址p = &b;// 通过指针间接修改b的值*p = 250;printf("b = %d\n", b);return 0;
}

指针与常量

  • 语法格式
int a = 1;
const int *p1 = &a;	// 等价于 int const *p1 = &a;
int * const p2 = &a;
const int * const p3 = &a;
  • 从左往右看,跳过类型,看修饰哪个字符
  • 如果是*, 说明指针指向的内存不能改变
  • 如果是指针变量,说明指针的指向不能改变,指针的值不能修改
#include <stdio.h>int main() {int a = 1;int b = 2;// p1 可以改,*p1不能改const int *p1 = &a; // 等价于 int const *p1 = &a;// p1 = &b;    // ok// *p1 = 555;  // err// p2 不能修改,*p2可以修改int *const p2 = &a;// p2 = &b;    //err// *p2 = 555;  // ok// p3 和 *p 都不能改const int *const p3 = &a;// p3 = &b;    // err// *p3 = 555;  // errreturn 0;
}

指针大小

  • 使用sizeof()测量指针的大小,得到的总是:4或8
  • sizeof()测的是指针变量指向存储地址的大小
  • 在32位平台,所有的指针(地址)都是32位(4字节)
  • 在64位平台,所有的指针(地址)都是64位(8字节)
#include <stdio.h>int main() {int *p1;int **p2;char *p3;char **p4;printf("sizeof(p1) = %llu\n", sizeof(p1));printf("sizeof(p2) = %llu\n", sizeof(p2));printf("sizeof(p3) = %llu\n", sizeof(p3));printf("sizeof(p4) = %llu\n", sizeof(p4));printf("sizeof(double *) = %llu\n", sizeof(double *));return 0;
}

指针步长

  • 指针步长指的是通过指针进行递增或递减操作时,指针所指向的内存地址相对于当前地址的偏移量。
  • 指针的步长取决于所指向的数据类型。
  • 指针加n等于指针地址加上 n 个 sizeof(type) 的长度
  • 指针减n等于指针地址减去 n 个 sizeof(type) 的长度
#include <stdio.h>int main() {char ch;char *p1 = &ch;printf("p1:%p, p1+1: %p\n", p1, p1 + 1); // 步长为1字节int a;int *p2 = &a;printf("p2:%p, p2+1: %p\n", p2, p2 + 1); // 步长为4字节double d;double *p3 = &d;printf("p3:%p, p3+1: %p\n", p3, p3 + 1); // 步长为8字节return 0;
}

野指针和空指针

  • 指针变量也是变量,是变量就可以任意赋值
  • 任意数值赋值给指针变量没有意义,因为这样的指针就成了野指针
  • 此指针指向的区域是未知(操作系统不允许操作此指针指向的内存区域)
  • 野指针不会直接引发错误,操作野指针指向的内存区域才会出问题
  • 为了标志某个指针变量没有任何指向,可赋值为NULL
  • NULL是一个值为0的宏常量
#include <stdio.h>int main() {int *p;p = 0x12345678; // 给指针变量p赋值,p为野指针, ok,不会有问题,但没有意义// *p = 1000;      // 操作野指针指向未知区域,内存出问题,errprintf("111111111111111111\n");int *q = NULL;  // 空指针return 0;
}

多级指针

  • C语言允许有多级指针存在,在实际的程序中一级指针最常用,其次是二级指针。
  • 二级指针就是指向一个一级指针变量地址的指针
#include <stdio.h>int main() {int a = 100;// 一级指针int* p1 = &a;printf("&a=%p\n", &a);printf("p1=%p\n", p1);printf("&p1=%p\n", &p1);// 二级指针,可以存储一级指针变量的地址int** p2 = &p1;printf("p2=%p\n", p2);printf("&p2=%p\n", &p2);// 三级指针,可以存储二级指针变量的地址int*** p3 = &p2;printf("p3=%p\n", p3);printf("&p3=%p\n", &p3);printf("---------------------\n");// 通过一级指针访问100,打印出来printf("*p1=%d\n", *p1);// 通过二级指针访问100,打印出来printf("**p2=%d\n", **p2);// 通过三级指针访问100,打印出来printf("***p3=%d\n", ***p3);return 0;
}

函数参数传值


●传值是指将参数的值拷贝一份传递给函数,函数内部对该参数的修改不会影响到原来的变量

示例代码:

// 函数参数传值,函数内部交换2个变量的值,验证函数外部的变量有没有改变
#include <stdio.h>// 函数定义
void func(int m, int n) {// 函数内部交换2个变量的值int temp = m;m = n;n = temp;printf("函数内部 m = %d, n = %d\n", m, n);
}int main() {int a = 10;int b = 20;// 调用函数,值传递func(a, b);printf("函数外部 a = %d, b = %d\n", a, b);return 0;
}

运行结果:

函数内部 m = 20, n = 10
函数外部 a = 10, b = 20

函数参数传址

  • 传址是指将参数的地址传递给函数,函数内部可以通过该地址来访问原变量,并对其进行修改。

示例代码:

// 函数参数传地址,函数内部交换2个指针指向内存的值,验证函数外部的变量有没有改变
#include <stdio.h>// 函数定义
void func(int *m, int *n) {// 函数内部交换2个指针指向内存的值int temp = *m;*m = *n;*n = temp;printf("函数内部 *m = %d, *n = %d\n", *m, *n);
}int main() {int a = 10;int b = 20;// 调用函数,地址传递func(&a, &b);printf("函数外部 a = %d, b = %d\n", a, b);return 0;
}

运行结果:

函数内部 *m = 20, *n = 10
函数外部 a = 20, b = 10

函数参数传址

  • 传址是指将参数的地址传递给函数,函数内部可以通过该地址来访问原变量,并对其进行修改。
// 函数参数传地址,函数内部交换2个指针指向内存的值,验证函数外部的变量有没有改变
#include <stdio.h>// 函数定义
void func(int *m, int *n) {// 函数内部交换2个指针指向内存的值int temp = *m;*m = *n;*n = temp;printf("函数内部 *m = %d, *n = %d\n", *m, *n);
}int main() {int a = 10;int b = 20;// 调用函数,地址传递func(&a, &b);printf("函数外部 a = %d, b = %d\n", a, b);return 0;
}

运行结果:

函数内部 *m = 20, *n = 10
函数外部 a = 20, b = 10

函数指针

函数名

  • 一个函数在编译时被分配一个入口地址,这个地址就称为函数的指针,函数名代表函数的入口地址
#include <stdio.h>void func(int a) {printf("func a = %d\n", a);
}int main() {// 函数名字,就是代表函数的入口地址,函数地址printf("%p, %p, %p\n", func, &func, *func);// 3种调用方法都可以func(1); // 最简便,最常用(&func)(2);(*func)(3);return 0;
}

函数指针

  • 函数指针:它是指针,指向函数的指针
  • 语法格式:
返回值 (*函数指针变量)(形参列表);

函数指针变量的定义,其中返回值、形参列表需要和指向的函数匹配 

#include <stdio.h>void func(int a) {printf("a = %d\n", a);
}int main() {// 函数指针变量的定义,同时初始化void (*p1)(int a) = func;// 通过函数指针变量调用函数p1(10);// 先定义函数指针变量,后面再赋值void (*p2)(int);p2 = func;// 通过函数指针变量调用函数p2(20);return 0;
}

回调函数 

  • 函数指针变量做函数参数,这个函数指针变量指向的函数就是回调函数
  • 回调函数可以增加函数的通用性
  • 在不改变原函数的前提下,增加新功能
#include <stdio.h>// 定义函数,函数指针做形参
int calc(int a, int b, int (*p)(int, int)){// 通过函数指针变量调用函数,获取返回值int res = p(a, b);return res;
}// 定义加法函数
int add(int x, int y) {return x + y;
}// 定义减法函数
int sub(int x, int y) {return x - y;
}int main() {int result;// 回调加法函数result = calc(1, 2, add);printf("result = %d\n", result);// 回调减法函数result = calc(10, 5, sub);printf("result = %d\n", result);return 0;
}

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

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

相关文章

机器学习_PySpark-3.0.3随机森林回归(RandomForestRegressor)实例

机器学习_PySpark-3.0.3随机森林回归(RandomForestRegressor)实例 随机森林回归 (Random Forest Regression): 任务类型: 随机森林回归主要用于回归任务。在回归任务中, 算法试图预测一个连续的数值输出, 而不是一个离散的类别。 输出: 随机森林回归的输出是一个连续的数值,…

算力租赁费用包括哪些

相比于企业自购设备、自建机房、自己运营&#xff0c;服务器租赁是绝大数企业的首先&#xff0c;租赁服务器从一定程度上解决了企业资金预算不足、AI芯片难买的局面。 随着文生视频大模型Sora、大语言模型Grok-1的相继出现&#xff0c;对高新能算力资源和服务的需求不断提高&a…

暴力枚举法

虽然暴力枚举法有时候效率低&#xff0c;时间复杂度高&#xff0c;但是在面对小规模数据集的时候&#xff0c;暴力枚举法往往是很好的思维利器。 B: 01 串的熵&#xff08;5分&#xff09; 问题描述 #include <iostream> #include <cmath> #include <algorithm…

什么是云HIS?云HIS的优点是什么?云HIS适用于什么医院?

什么是云HIS&#xff1f;云HIS的优点是什么&#xff1f;云HIS适用于什么医院&#xff1f; 一、什么是云HIS&#xff1f; 云HIS系统是一个运用云计算、大数据、物联网等新兴信息技术的业务和技术平台。它旨在按照现代医疗卫生管理要求&#xff0c;以数字化形式提供医疗卫生行业…

Mybatis generate xml 没有被覆盖

添加插件即可 <plugin type"org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/>

Andorid OTA A/B升级

参考 A/B&#xff08;无缝&#xff09;系统更新 升级后的显著变化是 ro.build.date.utc 、和 版本号 发生变化。 ro.odm_dlkm.build.dateThu Mar 28 01:09:45 UTC 2024 ro.odm_dlkm.build.date.utc1711588185ro.odm.build.dateThu Mar 28 01:09:45 UTC 2024 ro.odm.build.dat…

排序算法-桶排序

桶排序是一种基于计数的排序算法&#xff0c;它的核心思想是将待排序的元素分到不同的桶中&#xff0c;然后对每个桶中的元素进行排序&#xff0c;最后将所有桶中的元素依次取出来就得到了有序的结果。 具体的实现步骤如下&#xff1a; 创建一个固定大小的桶数组&#xff0c;…

epic免费游戏在哪里领 epic免费游戏怎么领取 图文教程一看就会

Epic Games是一家位于美国北卡罗来纳州卡里的视频游戏和软件开发商&#xff0c;由Tim Sweeney于1991年创立。该公司最著名的作品包括《堡垒之夜》和虚幻引擎&#xff0c;后者是一种广泛用于游戏开发的商用游戏引擎。Epic Games在2020年和2024年分别与索尼和迪士尼达成财务合作及…

ARM架构麒麟操作系统安装配置Mariadb数据库

、安装配置JDK (1)检查机器是否已安装JDK 执行 java -version命令查看机器是否安装JDK,一般麒麟操作系统默认安装openjdk 1.8。 (2)安装指定版本JDK 如果麒麟操作系统默认安装的openjdk 1.8不符合需求的话,可以卸载机器安装的openjdk 1.8并按需安装所需的openjdk版本…

Mybatis 执行批量插入

首先,创建一个简单的 insert 语句: <insert id”insertname”>insert into names (name) values (#{value}) </insert>然后在 java 代码中像下面这样执行批处理插入: list < string > names new arraylist(); names.add(“fred”); names.add(“barney”)…

#esp8266模块通过AT指令获取网络时间(苏宁时间)

一、IDE&#xff1a;keil、cubemx、Arduino......... 二、记录&#xff1a; 1.依次发送以下指令&#xff08;发送新行&#xff09; AT ATCWMODE1 ATCWDHCP1,1 ATCWJAP"Redmi K40 Gaming","87654321" ATCIPSTART"TCP","quan.suning.com&quo…

Leetcode110_平衡二叉树

1.leetcode原题链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 2.题目描述 给定一个二叉树&#xff0c;判断它是否是 平衡二叉树 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;…

RabbbitMQ

初识MQ 同步通讯和异步通讯 什么是同步通讯呢&#xff1f;举个例子&#xff0c;你认识了一个小姐姐&#xff0c;聊的很火热&#xff0c;于是你们慢慢开始打电话&#xff0c;视频聊天&#xff0c;这种方式就成为同步通讯&#xff0c;那什么是一部通讯呢&#xff0c;同样的&…

【性能测试】接口测试各知识第3篇:Jmeter 基本使用流程,学习目标【附代码文档】

接口测试完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;接口测试&#xff0c;学习目标学习目标,2. 接口测试课程大纲,3. 接口学完样品,4. 学完课程,学到什么,5. 参考:,1. 理解接口的概念。学习目标&#xff0c;RESTFUL1. 理解接口的概念,2.什么是接口测试…

python知识点汇总(十一)

python知识点总结 1、当Python退出时&#xff0c;是否会清除所有分配的内存&#xff1f;2、Python的优势有哪些&#xff1f;3、什么是元组的解封装4、Python中如何动态获取和设置对象的属性&#xff1f;5、创建删除操作系统上的文件6、主动抛出异常7、help() 函数和 dir() 函数…

在vue3中使用pinia

在vue3项目中使用pinia 使用vite创建项目和安装pinia依赖 npm init vitelatest npm i pinia从pinia包中解构出defineStore函数创建store片段,这里有一个要注意的点是第一个参数是这个store的id,第二个参数类比vue2中的script内容,state对应data,actions对应methods import {…

mybatis05:复杂查询:(多对一,一对多)

mybatis05&#xff1a;复杂查询&#xff1a;&#xff08;多对一&#xff0c;一对多&#xff09; 文章目录 mybatis05&#xff1a;复杂查询&#xff1a;&#xff08;多对一&#xff0c;一对多&#xff09;前言&#xff1a;多对一 &#xff1a; 关联 &#xff1a; 使用associatio…

Java开发环境安装

Java开发环境安装 1、JDK安装2、Maven安装3、MySQL安装4、Tomcat安装5、Nodejs安装 1、JDK安装 java环境搭建问题之——此环境变量太大。此对话框允许将值设置为最长2047个字符。“ 解决方法: Windows下Java环境配置教程 2、Maven安装 Maven配置教程 3、MySQL安装 mysql8…

机器学习和深度学习常见算法

监督学习算法对比 线性回归&#xff08;Linear Regression&#xff09; vs 支持向量机&#xff08;Support Vector Machine, SVM&#xff09; 线性回归&#xff1a; 特点&#xff1a;简单、易于理解和实现&#xff0c;基于线性假设建立输入和输出之间的关系。应用场景&#…

SV-7042V 40W网络有源音柱 智慧灯杆广播音柱

SV-7042V 40W网络有源音柱 一、描述 SV-7042V是深圳锐科达电子有限公司的一款壁挂式网络有源音柱&#xff0c;具有10/100M以太网接口&#xff0c;可将网络音源通过自带的功放和喇叭输出播放&#xff0c;其采用防水设计&#xff0c;功率40W。 SV-7042V作为网络广播播放系统的终…