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.rhkb.cn/news/263073.html

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

相关文章

二手货wordpress企业网站主题模板

二手车wordpress主题模板 简洁的二手车wordpress主题模板,适合做二手车业务的公司官方网站使用。 https://www.jianzhanpress.com/?p3473 wordpress二手物资回收主题 绿色wordpress二手物资回收主题,用于二手物资回收公司WP建站使用。 https://www.…

pikachu靶场-XSS

XSS: XSS(跨站脚本)概述 Cross-Site Scripting 简称为“CSS”,为避免与前端叠成样式表的缩写"CSS"冲突,故又称XSS。一般XSS可以分为如下几种常见类型: 1.反射性XSS; 2.存储型XSS; 3.DOM型XSS; …

[Angular 基础] - 自定义指令,深入学习 directive

[Angular 基础] - 自定义指令,深入学习 directive 这篇笔记的前置笔记为 [Angular 基础] - 指令(directives),对 Angular 的 directives 不是很了解的可以先过一下这篇笔记 后面也会拓展一下项目,所以感兴趣的也可以补一下文后对应的项目&a…

VSCODE include错误 找不到 stdio.h

解决办法: Ctrl Shift P 打开命令面板, 键入 “Select Intellisense Configuration”(下图是因为我在写文章之前已经用过这个命令,所以这个历史记录出现在了第一行) 再选择“Use gcc.exe ”(后面的Foun…

【Java程序设计】【C00277】基于Springboot的招生管理系统(有论文)

基于Springboot的招生管理系统(有论文) 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的招生管理系统 本系统分为系统功能模块、管理员功能模块以及学生功能模块。 系统功能模块:在系统首页可以查看首页、专业…

C语言——实用调试技巧——第2篇——(第23篇)

坚持就是胜利 文章目录 一、实例二、如何写出好(易于调试)的代码1、优秀的代码2、示范(1)模拟 strcpy 函数方法一:方法二:方法三:有弊端方法四:对方法三进行优化assert 的使用 方法五…

Hive【内部表、外部表、临时表、分区表、分桶表】【总结】

目录 Hive的物种表结构特性 一、内部表 建表 使用场景 二、外部表 建表:关键词【EXTERNAL】 场景: 外部表与内部表可互相转换 三、临时表 建表 临时表横向对比​编辑 四、分区表 建表:关键字【PARTITIONED BY】 场景: 五、分桶表 …

万界星空科技MES系统,实现数字化智能工厂

万界星空科技帮助制造型企业解决生产过程中遇到的生产过程不透明,防错成本高,追溯困难,品质不可控,人工效率低下,库存积压,交期延误等问题,从而达到“降本增效”的目标。打通各个信息孤岛&#…

【算法与数据结构】回溯算法、贪心算法、动态规划、图论(笔记三)

文章目录 七、回溯算法八、贪心算法九、动态规划9.1 背包问题9.2 01背包9.3 完全背包9.4 多重背包 十、图论10.1 深度优先搜索10.2 广度优先搜索10.3 并查集 最近博主学习了算法与数据结构的一些视频,在这个文章做一些笔记和心得,本篇文章就写了一些基础…

2023全新UI千月影视APP源码 | 前后端完美匹配、后端基于ThinkPHP框架

应用介绍 本文来自:2023全新UI千月影视APP源码 | 前后端完美匹配、后端基于ThinkPHP框架 - 源码1688 简介: 2023全新UI千月影视APP源码 | 前后端完美匹配、后端基于thinkphp框架 图片:

.NET Core MongoDB数据仓储和工作单元模式实操

前言 上一章节我们主要讲解了MongoDB数据仓储和工作单元模式的封装,这一章节主要讲的是MongoDB用户管理相关操作实操。如:获取所有用户信息、获取用户分页数据、通过用户ID获取对应用户信息、添加用户信息、事务添加用户信息、用户信息修改、用户信息删除…

kafka为什么性能这么高?

Kafka系统架构 Kafka是一个分布式流处理平台,具有高性能和可伸缩性的特点。它使用了一些关键的设计原则和技术,以实现其高性能。 上图是Kafka的架构图,Producer生产消息,以Partition的维度,按照一定的路由策略&#x…

Java知识点一

hello,大家好!我们今天开启Java语言的学习之路,与C语言的学习内容有些许异同,今天我们来简单了解一下Java的基础知识。 一、数据类型 分两种:基本数据类型 引用数据类型 (1)整型 八种基本数…

Unity 2021.3发布WebGL设置以及nginx的配置

使用unity2021.3发布webgl 使用Unity制作好项目之后建议进行代码清理,这样会即将不用的命名空间去除,不然一会在发布的时候有些命名空间webgl会报错。 平台转换 将平台设置为webgl 设置色彩空间压缩方式 Compression Format 设置为DisabledDecompre…

【kubernetes】二进制部署k8s集群之,多master节点负载均衡以及高可用(下)

↑↑↑↑接上一篇继续部署↑↑↑↑ 之前已经完成了单master节点的部署,现在需要完成多master节点以及实现k8s集群的高可用 一、完成master02节点的初始化操作 二、在master01节点基础上,完成master02节点部署 步骤一:准备好master节点所需…

opengl pyqt 显示文字

目录 效果图 效果图 import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QOpenGLWidgetfrom OpenGL.GL import * from OpenGL.GLUT import * from OpenGL.GLU import *class OpenGLWidget(QOpenGLWidget):def __init__(self, parentNone):super(OpenGLWidget…

【计算机毕业设计】541鲜花商城系统

🙊作者简介:拥有多年开发工作经验,分享技术代码帮助学生学习,独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。🌹赠送计算机毕业设计600个选题excel文件,帮助大学选题。赠送开题报告模板&#xff…

RabbitMq:什么是RabbitMq? ①

一、RabbitMq定位 RabbitMq是一个基于消息订阅发布的一款消息中间件。 二、技术原理 核心概念 server:又称broker,接受客户端连接,实现AMQP实体服务。缓存代理,Kafka集群中的一台或多台服务器统称broker.connection:…

长短期记忆神经网络

目录 LSTM 神经网络架构 分类 LSTM 网络 回归 LSTM 网络 视频分类网络 更深的 LSTM 网络 网络层 分类、预测和预报 序列填充、截断和拆分 按长度对序列排序 填充序列 截断序列 拆分序列 指定填充方向 归一化序列数据 无法放入内存的数据 可视化 LSTM 层架构 …

springboot+vue项目部署配置开机自启动

1.前端部属 下载nginx解压,在nginx\conf下找到nginx.conf 添加如下代码 server {listen 8081;server_name localhost;charset utf-8;location / {root F:/1ceshi/dist; #前端打包路径try_files $uri $uri/ /index.html;index index.html index.htm;}l…