07-指针的概念与引用,索引

news2024/11/27 9:41:04

指针的概念与引用,索引

一、内存地址

字节

  • 定义: 字节(byte)是内存容量的一个单位,一个字节包含8个位(bit)。

地址

  • 定义: 内存地址是系统为了方便区分每一个字节的数据而对内存进行的逐一编号。该编号就是内存地址。

请添加图片描述

基地址

  • 单字节的数据:char 类型,其所在地址的编号就是该数据的地址。
  • 多字节的数据:int 类型,它占用4个连续的内存地址编号,其中最小的地址编号称为该变量的基地址。

在这里插入图片描述

取地址符号

  • 定义: 每一个变量实际上都对应了一片内存,可以通过取地址符号 &获取其地址

示例

#include <stdio.h>

int main() {
    int a;
    char c;

    // 输出变量的地址
    printf("a的地址为:%p\n", (void*)&a);
    printf("c的地址为:%p\n", (void*)&c);

    return 0;
}

运行结果

a的地址为:0x7fffd5595d84
c的地址为:0x7fffd5595d83

在这里插入图片描述

注意事项:

  • 地址大小: 虽然不同的数据类型占用的内存空间不同,但是它们的地址所占用的内存空间(即地址的大小)是恒定的,由系统的位数决定(32位系统或64位系统)。
  • 地址和数据类型: 不同地址在表面上看似相同,但它们所代表的内存尺寸不同(与存放的数据类型相关)。访问这些地址时需要严格区分它们的逻辑关系。

总结:

  • 每个变量在内存中都有一个地址,可以通过取地址符号 & 来获得。
  • 地址的大小取决于系统的位数,而不是数据类型
  • 需要严格区分不同数据类型的地址,以正确访问内存中的数据。

二、 指针基础

2.1 指针的概念

  • 地址: &a 表示变量 a 的地址,这也被称为指针。指针是专门用来存放地址的变量,其大小由系统的位数决定(例如,32位系统中指针大小为4字节,64位系统中为8字节)。
  • 指针变量: 用来存储内存地址的变量,称为指针。

指针的定义语法

int a;         // 定义一个整型变量 a--> 定义一片内存,名字为a,约定好该内存用来存放整型变量
int *p;        // 定义一个指向整型数据的指针 p --> 定义一片内存名字叫p,约定好该内存用来存放整形数据的地址
char *p1;      // 定义一个指向字符数据的指针 p1
double *p2;    // 定义一个指向双精度数据的指针 p2

注意事项

  • 指针类型: 不决定该指针的大写哦,指针的类型用来告诉编译器如何解读和访问指针所指向的内存地址的数据类型和大小。
  • 指针大小: 指针的大小取决于系统的位数,而不是指向的数据类型。

2.2 指针的赋值与初始化

#include <stdio.h>

int main() {
    int a = 100;
    int *p = &a;  // 定义并初始化指向整型数据的指针 p

    double d = 1024.1234;
    double *p1 = &d;  // 定义并初始化指向双精度数据的指针 p1

    float f;
    float *p2;  // 定义但未初始化指向浮点数据的指针 p2

    p2 = &f;  // 给指针 p2 赋值

    // 打印指针和指向的值
    printf("地址 p 指向的值: %d\n", *p);
    printf("地址 p1 指向的值: %f\n", *p1);

    return 0;
}

注意事项

  • 类型匹配: 不同类型的指针应该指向相应类型的变量地址。例如,int * 应该指向 int 类型的变量,double * 应该指向 double 类型的变量。
  • 初始化: 指针在定义时最好初始化,否则其默认值是未定义的,可能会指向不合法的内存地址,导致程序错误。
    在这里插入图片描述
示例代码解析
#include <stdio.h>

int main() {
    int a = 100;
    int *p = &a;  // p 是指向 a 的指针,存储 a 的地址

    double d = 1024.1234;
    double *p1 = &d;  // p1 是指向 d 的指针,存储 d 的地址

    float f;
    float *p2;  // p2 是未初始化的指针
    p2 = &f;  // 给 p2 赋值,使其指向变量 f

    // 打印地址和指向的值
    printf("a 的地址: %p, 值: %d\n", (void*)p, *p);
    printf("d 的地址: %p, 值: %f\n", (void*)p1, *p1);
    printf("f 的地址: %p\n", (void*)p2);

    return 0;
}

运行结果:

a 的地址: 0x7ffee4b96f5c, 值: 100
d 的地址: 0x7ffee4b96f58, 值: 1024.123400
f 的地址: 0x7ffee4b96f54

2.3 指针的解引用与索引

**解引用(Dereferencing)**指针是通过指针获得它所指向的数据,即通过指针访问或修改指针所指向的变量的值。解引用操作符是 *

2.3.1 通过指针解引用与索引示例
#include <stdio.h>

int main() {
    int a = 100;  // 定义一个整型变量 a 并赋值为 100
    int *p = &a;  // 定义一个指针 p,指向变量 a 的地址

    // 通过指针 p 修改 a 的值
    *p = 250;  // 解引用 p,将 a 的值修改为 250

    // 打印解引用指针 p 后的值
    printf("*p: %d\n", *p);  // 输出 *p 的值,即 a 的新值 250

    // 打印变量 a 的值
    printf("a: %d\n", a);  // 输出 a 的值,应该是 250

    return 0;
}
  1. 定义与初始化:

    int a = 100;
    int *p = &a;
    

    这里定义了一个整型变量 a 并赋值为 100,然后定义一个指针 p,并将 p 初始化为 a 的地址。

  2. 通过指针修改变量的值:

    *p = 250;
    

    解引用指针 p,即访问 p 所指向的内存地址,并将该地址的值修改为 250。这相当于直接将变量 a 的值修改为 250

  3. 打印指针解引用后的值:

    printf("*p: %d\n", *p);
    

    打印 *p 的值,即指针 p 所指向地址的值。因为前一步将 a 的值改为 250,所以 *p 的值也是 250

  4. 打印变量 a 的值:

    printf("a: %d\n", a);
    

    打印变量 a 的值,确认 a 的值已经被修改为 250

运行结果:

*p: 250
a: 250

重要注意事项

  • 指针的类型: 指针的类型决定了解引用时访问内存的方式和数据类型。例如,int *p 表示指向一个整型数据的指针,通过 *p 可以访问到一个整型变量。
  • 指针初始化: 在使用指针前应确保其已经被初始化。如果指针未初始化就解引用,可能会导致未定义行为(访问非法内存)。
  • 解引用操作符 *: 解引用操作符 * 用于获取指针指向地址的值,即通过指针访问内存中存储的数据。

2.4 野指针

野指针指的是一个指向未知或未分配内存区域的指针。使用野指针可能会导致程序崩溃、数据损坏,甚至系统崩溃。通常会出现段错误(Segmentation fault)。

2.4.1 野指针的危害
  • 段错误(Segmentation fault): 程序试图访问非法内存区域,导致崩溃。
  • 数据损坏: 野指针可能修改关键数据,导致数据不一致或程序行为异常。
  • 系统崩溃: 在极端情况下,野指针可能修改系统关键数据,导致系统崩溃。
2.4.2 产生原因
  1. 未初始化指针:

    int *p;
    
  2. 指向已释放的内存:

    int *p = malloc(sizeof(int));
    free(p);
    *p = 10;  // p 已经指向被释放的内存
    
  3. 指针越界:

    int arr[5];
    int *p = arr + 10;  // 越界访问
    
2.4.3 防止野指针的措施
  1. 指针初始化: 定义指针时进行初始化。

    int *p = NULL;
    
  2. 避免访问已释放的内存: 释放指针后,将指针置为 NULL

    free(p);
    p = NULL;
    
  3. 检查数组边界: 确保指针访问不越界。

2.5 空指针

空指针是指保存了地址值为零的指针。使用空指针可以避免一些野指针问题。

2.5.1 空指针的定义和使用
int *p = NULL;  // 定义一个指针并初始化为空指针
  • 访问空指针会导致段错误:

    *p = 250;  // 段错误
    
2.5.2 打印空指针
printf("%p - %d\n", NULL, NULL);  // 输出: (nil) - 0

2.6 指针运算

指针可以进行加法和减法操作,这意味着地址的移动。

2.6.1 指针加法和减法
  • 指针加法: 地址向上移动若干个目标类型的单位。
  • 指针减法: 地址向下移动若干个目标类型的单位。

示例代码

#include <stdio.h>

int main() {
    long l;
    long *p = &l;
    int i;
    int *p1 = &i;

    printf("p: %p\n", p);
    printf("p+1: %p\n", p + 1);  // 向上移动一个 long 类型的大小

    printf("p1: %p\n", p1);
    printf("p1+1: %p\n", p1 + 1);  // 向上移动一个 int 类型的大小

    return 0;
}

运行结果

p: 0x7fffcb862610
p+1: 0x7fffcb862618  // p 向上移动 8 字节(long 的大小)
p1: 0x7fffcb86260c
p1+1: 0x7fffcb862610  // p1 向上移动 4 字节(int 的大小)

在这里插入图片描述

注意事项:

  • 指针类型决定了指针运算的单位: 指针在加减运算中,实际移动的大小取决于指针类型。
  • 避免使用未初始化的指针: 未初始化的指针可能指向任意位置,导致不可预测的行为。
  • 指针的类型和数据类型一致: 确保指针类型和所指向的数据类型一致,以避免错误的内存访问。

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

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

相关文章

物流装备企业太多,恶性竞争,2024年的新出路在哪里?

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》 之前写过一篇文章&#xff0c;关于中国有N多家物流装备企业&#xff0c;从列表中可猜测&#xff0c;行业内竞争惨烈。可以点击查看此篇 中国物流…

当代中国获奖的知名作家信息管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;用户管理&#xff0c;作家管理&#xff0c;作品管理&#xff0c;论坛管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;论坛&#xff0c;公告&#x…

上海亚商投顾:微盘股指数大跌超6% 全市场仅500余只个股上涨

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日震荡调整&#xff0c;创业板指午后一度跌超1%&#xff0c;微盘股指数盘中跌逾7%&#xff0c;小市值个…

HTML+CSS+JS 动态展开式菜单

效果演示 实现了一个可展开菜单按钮的效果,点击按钮会弹出一个菜单列表,菜单列表中包含多个选项。按钮的样式为一个圆形背景,中间有三条横线,表示可以展开。当按钮被点击后,三条横线会变成一个叉号,表示可以收起。菜单列表的样式为一个白色背景,四周有阴影,包含多个选项…

【JavaEE】Spring Boot 日志详解

一 日志概述 日志是用于记录系统运行状态、用户操作和重大事件的工具。 1.日志的用途 系统监控 监控现在几乎是一个成熟系统的标配, 我们可以通过日志记录这个系统的运行状态, 每⼀个方法的响应时间, 响应状态等, 对数据进行分析, 设置不同的规则, 超过阈值时进行报警. 比如统…

数据库资源评估:构建高效数据架构的基础

前言 这篇文章主要是描述在平时开发的过程中怎么进行合理的资源评估&#xff0c;包括数据量预估、用户行为建模、资源预估、资源预览等等。 存储架构设计三步骤 性能估算步骤 用户预估常见方式 用户行为建模 存储性能需求计算 存储性能需求计算案例 案例 用户行为模型:每天使…

【二进制部署k8s-1.29.4】十三、k8s的dashboard安装部署【完结】

文章目录 简介 一.kubernetes-dashboard-7.5.0的安装1.1 查看helm安装的参数1.2 安装命令 二.验证安装结果2.1.验证2.2.配置访问&#xff1a; 三.创建BearerToken来进行登录3.1.创建 ServiceAccount 和 Secret3.2.创建集群绑定3.3.查看token 四.登录注意事项 简介 本章节主要讲…

通过fiftyone按分类下载open-images-v7数据集,并转成yolov5可直接训练的格式

import osimport fiftyone as fo import fiftyone.zoo as foz import yamlclasses [Person, # 人 - 0Car, # 轿车 - 1Taxi, # 出租车 - 2Ambulance, # 救护车 - 3Bus, # 公共汽车 - 4Bicycle, # 自行车 - 5Motorcycle, # 摩托车 - 6Dog, # 狗 - 7Cat, # 猫 - 8M…

Django里的ModelForm组件

ModelForm组件 自动生成HTML标签 自动读取关联数据表单验证 错误提示数据库进行&#xff1a;新建&#xff0c;修改 步骤如下&#xff1a; 创建类 # 在 views.py 文件里# 创建一个类 class AssetModelForm(forms.ModelForm):class Meta:model models.AssetSet #fields [n…

Python Flask实现蓝图Blueprint配置和模块渲染

Python基础学习&#xff1a; Pyhton 语法基础Python 变量Python控制流Python 函数与类Python Exception处理Python 文件操作Python 日期与时间Python Socket的使用Python 模块Python 魔法方法与属性 Flask基础学习&#xff1a; Python中如何选择Web开发框架&#xff1f;Pyth…

《大道平渊》· 拾 —— 身心的“肥胖”与我们不知饥渴的病:追求中的丰盈与节制

《平渊》 拾 "水满则溢&#xff0c;月盈则亏。" 《道德经》有言&#xff1a;"水满则溢&#xff0c;月盈则亏"。 意思是&#xff1a;水满了就会溢出&#xff0c;月亮最圆的时候就会走向亏的状态。 这揭示了自然界和人类社会中一切事物的内在规律 —— 任…

经典算法 - 回溯法

文章目录 1. 基本概念2. 组合问题3. 组合总和Ⅲ4. 电话号码的字母组合5. 分割回文串6. 复原IP地址7. 子集8. 全排列9. 全排列Ⅱ10. N皇后11. 解数独 1. 基本概念 递归和回溯相辅相成。只要有递归&#xff0c;就会有回溯。 回溯法是一种纯暴力的搜索&#xff0c;并不是一种高效…

特征选择|模型解释|Pearson相关系数|JS散度|SHAP算法

文章目录 1 特征工程2 特征选择3 相关性分析3.1 皮尔逊相关系数3.2 皮尔逊相关系数 - python实现3.3 JS散度3.4 JS散度 - python实现 4 模型解释算法4.1 SHAP4.2 SHAP - python实现4.3 SHAP值解读4.4 SHAP 瀑布图4.5 SHAP 柱状图4.6 SHAP 蜂巢图4.7 SHAP其他图像形式4.7.1 单点…

selenium非全新的方式同时启动多个浏览器又互不影响的一种实现方法,欢迎讨论!

最近在做模拟浏览器批量定时自动点击实现批量操作功能&#xff0c;主要使用selenium&#xff0c;但是发现selenium直接调用本地浏览器&#xff0c;启动的是一个全新的&#xff08;与手动打开的不一致&#xff09;&#xff0c;网站可以检测到&#xff0c;每次都要双重验证(密码登…

Elasticsearch 管道查询语言 ES|QL 现已正式发布

作者&#xff1a;Costin Leau, George Kobar 今天&#xff0c;我们很高兴地宣布 ES|QL&#xff08;Elasticsearch 查询语言&#xff09;全面上市&#xff0c;这是一种从头开始设计的动态语言&#xff0c;用于转换、丰富和简化数据调查。在新的查询引擎的支持下&#xff0c;ES|Q…

14_Node.js和NPM入门指南

文章目录 NodeJS1.nodejs下载2.NPM的配置和使用3.NPM对一个项目进行初始化操作4.NPM本地仓库进行依赖下载5.查看当前项目有哪些依赖 https://www.npmjs.com/package NodeJS JS代码运行在哪里 1.浏览器2.nodejs 内置谷歌浏览器v8引擎 nodejs具有io磁盘 读写能力。类似java代码和…

找嵌入式软件工作,freertos要掌握到什么程度?

对于嵌入式软件工程师来说&#xff0c;掌握RTOS&#xff08;实时操作系统&#xff09;的程度并不是决定性因素&#xff0c;而更重要的是工程思维和解决问题的能力。我这里有一套嵌入式入门教程&#xff0c;不仅包含了详细的视频讲解&#xff0c;项目实战。如果你渴望学习嵌入式…

AI炒股:用kimi获取美股实时行情数据并保存到Excel

在kimi中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个编写Python脚本的任务&#xff0c;具体步骤如下&#xff1a; 获取美股实时美股行情数据&#xff0c;然后保存在F盘的Excel文件中&#xff0c;Excel文件名为&#xff1a;usstock20240605.xlsx 实…

创新实训2024.06.03日志:完善Baseline Test框架、加入对Qwen-14B的测试

1. Baseline Test框架重构与完善 在之前的一篇博客中&#xff08;创新实训2024.05.29日志&#xff1a;评测数据集与baseline测试-CSDN博客&#xff09;&#xff0c;我介绍了我们对于大模型进行基线测试的一些基本想法和实现&#xff0c;包括一些基线测试的初步结果。 后来的一…

双指针问题1

文章目录 1. 移动零&#xff08;283&#xff09;2. 复写零&#xff08;1089&#xff09;3. 快乐数&#xff08;202&#xff09;4. 盛最多水的容器&#xff08;11&#xff09; 1. 移动零&#xff08;283&#xff09; 题目描述&#xff1a; 算法原理&#xff1a; 设置两个指针…