指针!!C语言(第一篇)

指针1

  • 指针变量和地址
    • 1.取地址操作符(&)
    • 2.指针变量和解引用操作符(*)
  • 指针变量的大小和类型
  • 指针的运算
  • 特殊指针
    • 1.viod*指针
    • 2.const修饰指针
    • 3.野指针
  • assert断言
  • 指针的使用和传址调用
    • 1.strlen的模拟实现
    • 2.传值调用和传址调用

指针变量和地址

在认识指针之前,我们先引入一个实际生活的例子,比如我们要找一个小区内的房子,如果我们知道它在具体的几号楼,房间编号是多少的话那我们就很容易找到。那么对照到计算机中,我们知道CPU读取数据也是在内存中读取,存储数据也同样在内存中,如果将内存也分成一个个编号和一个个空间,那我们寻找一个数据岂不是更快更便捷?

其实在计算机中我们同样也是将内存划分为一个个内存单元,一个内存单元取一个字节,也就是8个比特位,每个内存单元也都有一个编号(这个编号就相当于小区房间的门牌号),有了这个内存单元的编号,CPU就可以快速找到一个内存空间。生活中我们把门牌号也叫地址,在计算机中我们把内存单元的编号也称为地址。C语言中给地址起了新的名字叫:指针所以我们可以理解为:内存单元的编号 = 地址 = 指针。

1.取地址操作符(&)

理解了内存和地址的关系,我们再回到C语言,在C语言中创建变量其实就是向内存申请空间,比如:在这里插入图片描述

2.指针变量和解引用操作符(*)

指针变量:那我们通过取地址操作符(&)拿到的地址是⼀个数值,比如:0x006FFD70,这个数值有时候也是需要存储起来,方便后期再使用的,那我们把这样的地址值存放在哪里呢?答案是:指针变量中。下面展示一些 内联代码片

#include <stdio.h>
int main()
{
int a = 10;
int* p = &a;//取出a的地址并且存在指针变量p中
return 0}

指针变量也是一种变量,这种变量就是用来存放地址的,存放在指针变量中的值都会理解为地址在这里插入图片描述
解引用操作符: 当我们把一个变量存储在一个指针变量中,如果我们要使用这个指针变量的话,我们要怎样使用呢?
下面展示一些 内联代码片

#include <stdio.h>
int main()
{
int a=10;
int* pa=&a;
*pa=20;//将a中的数值改为20
printf("%d\n",a);
return 0;
}

在上面的代码中, *pa 的意思就是通过pa中存放的地址,找到指向的空间 *pa其实就是a变量了;所以 *pa = 20,这个操作符就是把a改成了20,也就是通过指针来修改a变量中存的数值。

指针变量的大小和类型

首先我们要知道指针变量也是有大小,指针变量的大小是通过字节来判断的,指针变量的大小取决于地址的大小:
比如:32位平台下地址是32个bit位(即4个字节),64位平台下地址是64个bit位(即8个字节)
在这里插入图片描述
虽然所占字节大小与类型无关,但是类型仍然是有意义的,决定了它解引用时候的权限,例如int* pa=&a;char* pc=&a;假如给a重新赋一个值0,就会发现通过调试int类型中的字节全部变为0,而char类型中的字节只有第一个字节变为0。

指针的运算

指针+ - 整数:指针也有运算,例如对于整型指针的加减&a→&a+1,就将指针的地址移动了4个字节,但如果是char类型的话,就只移动1个字节,也就是说不同类型的指针移动的字节大小是不相同的。
指针-指针:指针-指针的绝对值是指针和指针之间元素的个数,但是两个指针指向的是同一块空间才可以。

特殊指针

1.viod*指针

在指针类型中有⼀种特殊的类型是 void * 类型的,可以理解为无具体类型的指针(或者叫泛型指针),这种类型的指针可以用来接受任意类型地址。但是也有局限性, void* 类型的指针不能直接进行指针的±整数和解引用的运算。一般 void* 类型的指针是使用在函数参数的部分,用来接收不同类型数据的地址,这样的设计可以实现泛型编程的效果,使得⼀个函数来处理多种类型的数据。

2.const修饰指针

如果在一个程序中我们希望一个变量不能被随便修改,那我们应该怎么办呢?const就可以实现这个作用。
比如:int a=100; a=200;那么输出的a就等于200,但是如果我们在int前面加上const,那么此时的a就不能被修改了。但是如果我们通过指针也就是用地址来变:下面展示一些 内联代码片

#include <stdio.h>
int main()
{const int n = 0;printf("n = %d\n", n);int*p = &n;*p = 20;printf("n = %d\n", n);return 0;
}

通过上面的代码,即使我们用const来修饰但是通过指针变量我们还是能把变量改变,那么有没有什么办法始终不能改变量里面的值呢?给大家放一张图:在这里插入图片描述

3.野指针

概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
如何避免野指针呢?

  1. 指针初始化(如果不知道指向哪里,就赋值NULL空指针)
  2. 不要越界访问(例如我们访问一个数组,当超过数组的范围还要继续访问,将成为野指针)
  3. 指针变量不再使用时,及时置NULL,指针使用之前检查有效性。
  4. 避免返回局部变量的地址

assert断言

assert.h 头文件定义了宏 assert() ,用于在运行时确保程序符合指定条件,如果不符合,就报错终止运行。这个宏常常被称为“断言”。
eg:assert(p!=NULL);
上面代码在程序运行到这一行语句时,验证变量 p 是否等于 NULL 。如果确实不等于 NULL ,程序继续运行,否则就会终止运行,并且给出报错信息提示。assert() 宏接受一个表达式作为参数。如果该表达式为真(返回值非零), assert() 不会产生任何作用,程序继续运行。如果该表达式为假(返回值为零), assert() 就会报错,在标准错误流 stderr 中写入⼀条错误信息,显示没有通过的表达式,以及包含这个表达式的文件名和行号。
使用assert的好处也有很多,它不仅能自动标识文件和出问题的行号,还有一种无需更改代码就能开启或关闭 assert() 的机制。如果已经确认程序没有问题,不需要再做断言,就在 #include <assert.h> 语句的前面,定义一个宏 NDEBUG 。
在这里插入图片描述
assert() 的缺点是,因为引入了额外的检查,增加了程序的运行时间。
一般我们可以在 Debug 中使用,在 Release 版本中选择禁用 assert 就行,在 VS 这样的集成开发环境中,在 Release 版本中,直接就是优化掉了。这样在debug版本写有利于程序员排查问题,在 Release 版本不影响用户使用时程序的效率。

指针的使用和传址调用

1.strlen的模拟实现

库函数strlen的功能是求字符串长度,统计的是字符串中 \0 之前的字符的个数。
函数原型如下:下面展示一些 内联代码片

#include <assert.h>
size_t my_strlen(const char* s)//保证s不被改变
{int count = 0;assert(s != NULL);//保证s不能是空指针while (*s){count++;s++;}return count;
}
int main()
{char arr[] = "abcdef";size_t len = my_strlen(arr);printf("%zd\n", len);return 0;
}

const保证了字符串内容不被改变。

2.传值调用和传址调用

写一个函数交换两个变量的值:下面展示一些 内联代码片

#include <stdio.h>
void Swap1(int x, int y)
{int tmp = x;x = y;y = tmp;
}
int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);printf("交换前:a=%d b=%d\n", a, b);Swap1(a, b);printf("交换后:a=%d b=%d\n", a, b);return 0;
}

在这里插入图片描述
通过上面的代码我们可以看出来,即使我们使用函数交换两个变量的数值,但是输出的结果仍然不是我们想要的结果,那么问题到底出现在哪呢?这个时候我们就要知道一个叫做传值调用,也就是如果直接将数值传过去,就是传值调用。实参传递给形参的时候,形参会单独创建一份临时空间,对形参的修改不影响实参。那么有没有什么办法呢?我们可以想到使用指针传址的办法,也就是传址调用
下面展示一些 内联代码片

#include <stdio.h>
void Swap2(int*px, int*py)
{int tmp = 0;tmp = *px;*px = *py;*py = tmp;
}
int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);printf("交换前:a=%d b=%d\n", a, b);Swap2(&a, &b);printf("交换后:a=%d b=%d\n", a, b);return 0;
}

在这里插入图片描述
传址调用,可以让函数和主调函数之间建立真正的联系,在函数内部可以修改主调函数中的变量;所以未来函数中只是需要主调函数中的变量值来实现计算,就可以采用传值调用。如果函数内部要修改主调函数中的变量的值,就需要传址调用。

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

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

相关文章

Iceberg概念和特性

1. 快照 Iceberg会随着时间的推进,跟踪表生命周期中的所有数据集变化,并使用快照(Snapshots)来表示每一次变化后的数据集合,每一次数据操作的事务提交均会产生一个快照,并将其记录在元数据文件(Metadata)中。 基于快照的概念,Iceberg有以下特性: 事务性:写入快照成…

26.6 Django模型层

1. 模型层 1.1 模型层的作用 模型层(Model Layer)是MVC或MTV架构中的一个核心组成部分, 它主要负责定义和管理应用程序中的数据结构及其行为. 具体职责包括: * 1. 封装数据: 模型层封装了应用程序所需的所有数据, 这些数据以结构化的形式存在, 如数据库表, 对象等. * 2. 数据…

昇思25天学习打卡营第7天 | MindNLP ChatGLM-6B StreamChat

本案例基于MindNLP和ChatGLM-6B实现一个聊天应用。 1 环境配置 %%capture captured_output # 实验环境已经预装了mindspore2.2.14&#xff0c;如需更换mindspore版本&#xff0c;可更改下面mindspore的版本号 !pip uninstall mindspore -y !pip install -i https://pypi.mi…

前端:Vue学习-1

前端:Vue学习-1 1. 指令1. 指令修饰符2. v-bind对样式控制的增强3. v-model应用于其他表单元素 2. 计算属性3. watch侦听器&#xff08;监视器&#xff09; 1. 指令 就是带有v-前缀的特殊属性&#xff0c;不同属性对应不同的功能 v-html&#xff1a;动态设置页面的html标签内容…

超时导致SparkContext构造失败的问题探究

文章目录 1.前言2. 基于事故现场对问题进行分析2.1 日志分析2.2 单独测试Topology代码试图重现问题 3. 源码解析3.1 Client模式和Cluster模式下客户端的提交和启动过程客户端提交时在两种模式下的处理逻辑ApplicationMaster启动时在两种模式下的处理逻辑 3.2 两种模式下的下层角…

08-8.4.1 简单选择排序+8.4.2 堆排序

&#x1f44b; Hi, I’m Beast Cheng &#x1f440; I’m interested in photography, hiking, landscape… &#x1f331; I’m currently learning python, javascript, kotlin… &#x1f4eb; How to reach me --> 458290771qq.com 喜欢《数据结构》部分笔记的小伙伴可以…

Adminer-CVE-2021-21311

在其4.0.0到4.7.9版本之间&#xff0c;连接 ElasticSearch 和 ClickHouse 数据库时存在一处服务端请求伪造漏洞&#xff08;SSRF&#xff09;。 VPS开启HTTP服务 VPS 开启HTTP 再同时跑POC 确保能访问poc里的链接文件 第一是目标地址 第二个是跳转地址 第三个是监听地址 如果…

为什么大学讲授 C 语言比讲授 C++ 的更多?

大学更倾向于讲授C语言而不是C的几个原因可能包括。我收集归类了一份嵌入式学习包&#xff0c;对于新手而言简直不要太棒&#xff0c;里面包括了新手各个时期的学习方向编程教学、问题视频讲解、毕设800套和语言类教学&#xff0c;敲个22就可以免费获得。 基础性质&#xff1a;…

【Linux】进程程序替换 + 模拟实现简易shell

前言 上一节我们介绍了 **进程终止**和 **进程等待**等一系列问题&#xff0c;并做了相应的验证&#xff0c;本章将继续对进程控制进行介绍&#xff0c;重点学习进程程序替换&#xff0c;并进行相应验证&#xff0c;在此基础上&#xff0c;自己模拟实现一个shell&#xff0c;该…

Redis分布式锁-Redisson可重入锁原理的个人见解。

记录Redisson可重入锁的个人见解。 文章目录 前言一、什么叫做锁的重入&#xff1f;二、Redisson可重入锁原理 前言 ⁣⁣⁣⁣ ⁣⁣⁣⁣ 之前在写项目的时候&#xff0c;注意到Redisson可重入锁的一个问题&#xff0c;随即在网上搜索其对应的资料&#xff0c;下面就记录一下个…

昇思25天学习打卡营第14天 | ShuffleNet图像分类

昇思25天学习打卡营第14天 | ShuffleNet图像分类 文章目录 昇思25天学习打卡营第14天 | ShuffleNet图像分类ShuffleNetPointwise Group ConvolutionChannel ShuffleShuffleNet模块网络构建 模型训练与评估数据集训练模型评估模型预测 总结打卡 ShuffleNet ShuffleNetV1是旷世科…

鸿蒙实训笔记

第一天 #初始化一个新的NPM项目(根据提示操作) npm init #安装TSC、TSLint和NodeJS的类型声明 npm install -s typescript tslint types/node 在根目录中新建一个名为tsconfig.json的文件&#xff0c;然后在代码编辑器中打开&#xff0c;写入下述内容&#xff1a; {"co…

MATLAB激光通信和-积消息传递算法(Python图形模型算法)模拟调制

&#x1f3af;要点 &#x1f3af;概率论和图论数学形式和图结构 | &#x1f3af;数学形式、图结构和代码验证贝叶斯分类器算法&#xff1a;&#x1f58a;多类型&#xff1a;朴素贝叶斯&#xff0c;求和朴素贝叶斯、高斯朴素贝叶斯、树增强贝叶斯、贝叶斯网络增强贝叶斯和半朴素…

网络层重点协议—IP协议

在复杂的网络环境中确定一个合适的路径 协议头格式如下&#xff1a; 4位版本号(version) 指定协议的版本&#xff08;IPV4-4,IPV6-6&#xff09; 4位首部长度(header length) IP头部的长度是多少个32bit&#xff0c;也就是length*4的字节数。4bit表示最大的数字是15&#x…

【密码学】密码学数学基础:群的定义

一、群的定义 在密码学中&#xff0c;群&#xff08;Group&#xff09;的概念是从抽象代数借用来的&#xff0c;它是一种数学结构&#xff0c;通常用于描述具有特定性质的运算集合。 群的定义 群定义中的几个关键要素&#xff1a; 集合&#xff1a;首先&#xff0c;群是由一系…

AutoMQ 中的元数据管理

本文所述 AutoMQ 的元数据管理机制均基于 AutoMQ Release 1.1.0 版本 [1]。 01 前言 AutoMQ 作为新一代基于云原生理念重新设计的 Apache Kafka 发行版&#xff0c;其底层存储从传统的本地磁盘替换成了以对象存储为主的共享存储服务。对象存储为 AutoMQ 带来可观成本优势的…

draggable 实现一个简单的拖拽

拖拽区域代码 <draggable v-if="activeFirstIndex !== 8" :list="showResourseList" :group="{ name: resources, pull: clone, put: false }" :sort="false" :multiple="false" :move="onMove1" @end="…

【JavaScript 算法】冒泡排序:简单有效的排序方法

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、算法原理二、算法实现三、应用场景四、优化与扩展五、总结 冒泡排序&#xff08;Bubble Sort&#xff09;是一种基础的排序算法&#xff0c;通过重复地遍历要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果它…

【香橙派 AIpro测评:探索高效图片分类项目实战】

前言 最近入手了一块香橙派 AIpro开发板&#xff0c;在使用中被它的强大深深震撼&#xff0c;有感而发写下这篇文章。 本文旨在深入探讨OrangePi AIpro的各项性能&#xff0c;从硬件配置、软件兼容性到实际应用案例&#xff0c;全方位解析这款设备如何在开源社区中脱颖而出&am…

案例 | 人大金仓助力山西政务服务核心业务系统实现全栈国产化升级改造

近日&#xff0c;人大金仓支撑山西涉企政策服务平台、政务服务热线联动平台、政务网、办件中心等近30个政务核心系统完成全栈国产化升级改造&#xff0c;推进全省通办、跨省通办、综合业务受理、智能审批、一件事一次办等业务的数字化办结进程&#xff0c;为我国数字政务服务提…