C语言:指针(一)

目录

  • 1.内存和地址
  • 2. 指针变量和地址
    • 2.1 取地址操作符(&)
    • 2.2 指针变量和解引用操作符(*)
      • 2.2.1 指针变量
      • 2.2.2 解引用操作符(*)
    • 2.3 指针变量的大小
  • 3.指针变量的类型和意义
    • 3.1 指针的解引用
    • 3.2 指针+ -指针
    • 3.3 void*指针
  • 4.const修饰指针
    • 4.1 const修饰变量
    • 4.2 const修饰指针变量
  • 5.传值调用和传址调用

1.内存和地址

在生活中,我们住的房子一般都有门牌号,学生一般都有学号,注册一个软件账户一般都有账户编号,可见给一些事物编上号可以方便我们的生活。
计算机也是这样,计算机中处理数据的机器时CPU(中央处理器),它在处理数据的时候是在内存中读取数据,处理后将数据放回内存。在内存中将其划分为一个一个的内存单元,每个内存单元的大小取一个字节(8个bite),每个内存单元也有一个编号,就相当于门牌号一样,这样CPU就可以快速访问内存中需要的数据了。
内存单元就相当一间学生宿舍,一个字节能存放8个比特位,就相当于一间宿舍住了8个人。

1byte= 8bite
1kb = 1024byte
1mb = 1024kb
1Gb = 1024mb
1Tb = 1024Gb
1Pb = 1024Tb

生活中我们也把门牌号叫做地址,在计算机中,我们把内存单元的编号也叫做地址还可叫做指针
所以:内存单元编号 == 地址 == 指针

2. 指针变量和地址

2.1 取地址操作符(&)

取地址操作符&和按位与操作符&是同一种符号,但是功能完全不一样,而且取地址符是单目操作符,按位与操作符是双目操作符。
在C语言中创建变量其实就是向内存申请一块空间,比如

int a = 10;

这段代码就是向内存中申请4个字节(int类型占用4个字节)用于存放整数10,那如何得到这个地址呢,那么就要用到取地址操作符(&),比如:
在这里插入图片描述
这里的地址是用16进制表示
而int类型的数据会占用4个字节的大小,所以**&a取出的是所占4个字节中地址较小的字节的地址。**
在这里插入图片描述
十六进制的a表示的数就是10,当我们知道了第一个字节的地址,就可以往下顺藤摸瓜找到其他的地址

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

2.2.1 指针变量

当我们用取地址操作符拿到一个地址后就可以将这个地址存放到指针变量中,比如:

int main() {int a = 10;int* pa = &a;return 0;
}

指针变量是一种变量,这种变量是用来存放地址的,存放在指针变量的值都会被理解为地址
pa是指针变量,int*是指针变量的类型, *表示pa是指针变量,int表示pa指向的类型是int类型。这里的 int和星号中间加不加空格都表示指针变量,没有去区别。

2.2.2 解引用操作符(*)

指针变量用来保存地址,而解引用操作符(*)用来使用地址
在C语言中,我们拿到了指针就可以通过指针找到指针指向的对象,这里就需要*(解引用操作符)

int main() {int a = 10;int* pa = &a;*pa = 0;return 0;

*pa的意思就是通过指针变量pa找到pa指向的对象a,然后改变它的值,上述代码就是将a的值由10改为0.

*pa = 0;的效果和a = 0;的效果一样,都是将a的值置为0,但是使用指针提供了一种新的修改途径。

2.3 指针变量的大小

在32位计算机中有32根地址总线(相关知识可以自行学习),每根地址总线都可以使用电信号来表示0和1,这样就由32根地址总线产生的二进制序列就可以当作地址,那么一个地址就是32个bite位,需要4个字节来存储。
所以:任何指针变量的大小都是4个字节(64位机是8个字节)

int main() {printf("%zd\n", sizeof(char*));printf("%zd\n", sizeof(int*));printf("%zd\n", sizeof(double*));printf("%zd\n", sizeof(short*));printf("%zd\n", sizeof(long int*));return 0;
}

在这里插入图片描述

3.指针变量的类型和意义

既然在相同平台下所有的指针类型的大小都是一样的,那么为什么还要设置这么多的指针变量呢。

3.1 指针的解引用

对比以下代码:

int main() {int a = 0x11223344;int* pa = &a;*pa = 0;return 0;
}
int main() {int a = 0x11223344;char* pa = &a;*pa = 0;return 0;
}

通过调试中的内存监控可知,代码1会将0x11223344中的4个字节全部置为0,而代码2只会将第一个字节44置为0,其他不变。
在这里插入图片描述
结论:指针的类型决定了对指针解引用的时候有多大的权限(一次能操作几个字节)
比如,int类型的指针变量可以解引用4个字节,而char类型的指针变量只能访问1个字节

3.2 指针+ -指针

int main() {int n = 10;int* pi = &n;char* pc = &n;printf("%p\n", &n);printf("%p\n", pi);printf("%p\n", pc);printf("%p\n", pi + 1);printf("%p\n", pc + 1);return 0;
}

运行结果如下:
在这里插入图片描述
这里的pi和pc都指向变量n,而pi+1加了4个字节,因为pi是int*类型的指针变量,而pc+1只加

了1个字节,因为pc是char* 的指针变量。
结论:指针的类型决定了指针想前或者其向后走一步有多少距离。

3.3 void*指针

在指针类型中有一种特殊的指针类型是void*类型,它是无具体类型的指针(泛型指针),它可以用来接收任何类型的地址,但也有局限性:不能进行+和-和解引用的操作

int main() {int a = 0x11223344;void* pa = &a;*pa = 0;//错误操作return 0;
}

void*指针可以接受不同类型的地址,但是无法直接进行指针运算

4.const修饰指针

变量是可以修改的,而在变量前面加上const修饰那么该变量就不能被修改了

4.1 const修饰变量

int main() {const int a = 10;a = 29;return 0;
}

在这里插入图片描述
可以看到,变量a被const修饰过后,那么改值就不能修改了,而这个限制只是在语法层面加上限制,我们可以用指针来越过这个限制,比如:
在这里插入图片描述
上面用指针变量pa来读取a的地址,而用解引用操作符操作指针变量a,使其修改值为20,那么有什么办法能让指针也不能改变其值呢?

4.2 const修饰指针变量

int main() {const int a = 10;const int* pa = &a;*pa = 20;//错误printf("%d\n", a);return 0;
}

在这里插入图片描述
可以看出,在指针变量pa前面加上const,那么该指针变量就无法进行去引用操作并赋值的操作
注意:const int* pa = &a;的效果和 int const * pa = &a;的效果一致

那const放在a的右边呢

int main() {const int a = 10;int* const pa = &a;*pa = 20;printf("%d\n", a);return 0;
}

这样就对pa的值没有限制作用了,加在右边的作用是限制指针变量的内容不能修改。
这里必须要弄懂三个概念的含义:

1.pa存放的是a的地址 2.pa是指针变量,也是一种变量,他有自己的地址 3.*pa是pa指向的空间即a的值

上述代码就是限制了变量pa里面存放的值不能改变

int main() {const int a = 10;int* const pa = &a;*pa = 20;printf("%d\n", a);int b = 0;pa = &b;//错误return 0;
}

在这里插入图片描述
结论:

  • const放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针改变但是指针变量本身的内容可以改变
  • const放在*的右边,修饰的是指针本身的内容,保证指针变量本身的内容不可以改变但是但是指针指向的内容可以改变

5.传值调用和传址调用

传值调用就是调用函数,参数是值。而传址调用就是传的地址
比如:

用函数实现交换两个数

void Swap(int x, int y) {int type = x;x = y;y = type;
}
int main() {int a = 10;int b = 20;printf("交换前:%d %d\n", a, b);Swap(a, b);printf("交换后:%d %d\n", a, b);return 0;
}


这里可以看到交换值不成功,这是因为实参传递给形参时,形参会单独创建一分临时空间来接受实参,对形参的修改不影响实参
可以使用指针来实现两个数的交换

void Swap(int *x, int *y) {int type = 0;type = *x;*x = *y;*y = type;
}
int main() {int a = 10;int b = 20;printf("交换前:%d %d\n", a, b);Swap(&a, &b);printf("交换后:%d %d\n", a, b);return 0;
}

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

/考研势在必行/

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

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

相关文章

【PyTorch][chapter 17][李宏毅深度学习]【无监督学习][ Auto-encoder]

前言: 本篇重点介绍AE(Auto-Encoder) 自编码器。这是深度学习的一个核心模型. 自编码网络是一种基于无监督学习方法的生成类模型,自编码最大特征输出等于输入 Yann LeCun&Bengio, Hinton 对无监督学习的看法. 目录: AE 模型原…

FPGA OSERDESE2

Output Parallel-to-Serial Logic Resources (OSERDESE2) OSERDESE2 在Xilinx 7 系列器件是一款专用的并行至串行转换器,具有特定的时钟和逻辑资源,旨在促进高速源同步接口的实现。每个OSERDESE2模块都包括一个专用的数据串行器和 3 状态控制。数据和 3 态串行器都可以在 SD…

Edwards爱德华STP系列-A1603分子泵使用维修保养说明

Edwards爱德华STP系列-A1603分子泵使用维修保养说明

前端基础自学整理|DOM树

DOM,文档对象模型(Document Object Model),简单的说,DOM是一种理念,一种思想,一个与系统平台和编程语言无关的接口,一种方法, 使 Web开发人员可以访问HTML元素!不是具体方…

Flask数据库操作-Flask-SQLAlchemy

Flask中一般使用flask-sqlalchemy来操作数据库。flask-sqlalchemy的使用介绍如下: 一、SQLAlchemy SQLALchemy 实际上是对数据库的抽象,让开发者不用直接和 SQL 语句打交道,而是通过 Python 对象来操作数据库,在舍弃一些性能开销…

Nginx----高性能的WEB服务端

一、Nginx介绍 1、什么是Nginx Nginx Nginx是一个高性能的HTTP和反向代理服务器。是一款轻量级的高性能的web服务器/反向代理服务器/电子邮件(IMAP/POP3)代理服务器,单台物理服务器可支持30 000~50 000个并发请求。 一款高性能…

(done) Positive Semidefinite Matrices 什么是半正定矩阵?如何证明一个矩阵是半正定矩阵? 可以使用特征值

参考视频:https://www.bilibili.com/video/BV1Vg41197ew/?vd_source7a1a0bc74158c6993c7355c5490fc600 参考资料(半正定矩阵的定义):https://baike.baidu.com/item/%E5%8D%8A%E6%AD%A3%E5%AE%9A%E7%9F%A9%E9%98%B5/2152711?frge_ala 看看半正定矩阵的…

Milvus数据库介绍

参考:https://www.xjx100.cn/news/1726910.html?actiononClick Milvus 基于FAISS、Annoy、HNSW 等向量搜索库构建,核心是解决稠密向量相似度检索的问题。在向量检索库的基础上,Milvus 支持数据分区分片、数据持久化、增量数据摄取、标量向量…

基于Java在线宠物店商城系统设计与实现(源码+部署文档)

博主介绍: ✌至今服务客户已经1000、专注于Java技术领域、项目定制、技术答疑、开发工具、毕业项目实战 ✌ 🍅 文末获取源码联系 🍅 👇🏻 精彩专栏 推荐订阅 👇🏻 不然下次找不到 Java项目精品实…

Redis的常见面试题

目录 前言 Redis支持哪些数据类型 五种核心类型 Zset为什么用跳表不用红黑树 ? Redis常见的应用场景? 如何检测Redis的连通性? 如何设置key的过期时间? Redis为什么是单线程模型? Redis里的IO多路复用是什…

惠尔顿安全审计系统任意文件读取漏洞

免责声明:文章来源互联网收集整理,请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该…

启动node服务报错Error: listen EACCES: permission denied 0.0.0.0:5000

启动node服务报错: 解决方案: 将监听端口改成3000或者其他 修改后结果: 参考原文: Error: listen EACCES: permission denied_error when starting dev server: error: listen eacc-CSDN博客

Conda管理Python不同版本教程

Conda管理Python不同版本教程 目录 0.前提 1.conda常用命令 2.conda设置国内源(以添加清华源为例,阿里云源同样) 3.conda管理python库 4.其它 不太推荐 pyenv管理Python不同版本教程(本人另一篇博客,姊妹篇&…

C语言菜鸟入门·数组简介

目录 1. 简介 2. 声明数组 3. 初始化数组 3. 访问数组元素 4. 获取数组长度 5. 数组名 1. 简介 在 C 语言中,数组是一种用来存储相同类型数据元素的集合。数组提供了一种便捷的方式来管理一系列相同类型的数据,可以按照索引来访问和操作数组…

探究网络工具nc(netcat)的使用方法及安装步骤

目录 🐶1. 什么是nc(netcat)? 🐶2. nc(netcat)的基本使用方法 2.1 🥙使用 nc 进行端口监听 2.2 🥙使用 nc 进行端口扫描 2.3 🥙使用 Netcat 进行文件传输…

代码随想录算法训练营day20

题目:530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先 参考链接:代码随想录 530.二叉搜索树的最小绝对差 思路:我一开始想到的方法是先生成中序序列,然后对相邻两项的差进行计算,取…

【PCIE709-F】基于复旦微JFM7VX690T80 FPGA的全国产化8通道光纤双FMC接口数据处理平台

板卡概述 PCIE709-F是一款基于上海复旦微电子的28nm 7系列FPGA JFM7VX690T80的全国产化8通道光纤双FMC接口数据预处理平台,该板卡采用复旦微的高性能7系列FPGA作为实时处理器,实现4路10G SFP光纤以及1路QSFP通信接口、实现1路X8 PCIE数据传输的功能。板载…

【鸿蒙系统学习笔记】网络请求

一、介绍 资料来自官网:文档中心 网络管理模块主要提供以下功能: HTTP数据请求:通过HTTP发起一个数据请求。WebSocket连接:使用WebSocket建立服务器与客户端的双向连接。Socket连接:通过Socket进行数据传输。 日常…

SpringMVC回顾总结笔记

MVC是一种思想而SpringMVC是具体的实现(Ioc和DI的关系) 在创建项目的时候勾选的SpringWeb框架就是SpringMVC框架 与浏览器建立连接 默认返回的是一个 view 视图。需要添加ResponseBody说明返回的是json数据。RestController是ControllerResponseBody…

【数据结构】_队列

目录 1.概念 2.队列的使用 3.队列模拟实现 4.循环队列 5.双端队列 6.栈与队列的互相实现 6.1 用队列实现栈 6.2 用栈实现队列 1.概念 (1)队列是只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表; &am…