C语言的灵魂——指针(1)
指针是C语言的灵魂,有了指针C语言才能完成一些复杂的程序;没了指针就相当于C语言最精髓的部分被去掉了,可见指针是多么重要。废话不多讲我们直接开始。
指针
- 一,内存和地址
- 二,编址
- 三,指针变量和地址
- 1,&(取地址)操作符
- 2,指针变量
- 3,解引用操作符
- 4,指针变量的大小
- 四,指针类型的意义
- 五,偏移量
- 六,指针的运算
一,内存和地址
谈到指针我们首先就会想到地址,因为指针就是地址。为什么这么会认为指针它就是地址呢?指针与地址有什么关联呢?想要回答上面两个问题那我们就先来探究一下内存和地址的关系。
我们举一个生活中的例子你就知道了,我们生活中所看见的学校的宿舍楼其实就是内存,比如一栋一栋的宿舍喽在建造之初就规定好了有多少个房间,房间里能住几个人。这可以说是宿舍楼的内存;而计算机也一样,计算机就是将一个大内存分成若干个小的内存单元,每个内存单元占一个字节,这里就相当于一栋宿舍楼有若干间数;而每一字节占8个比特位,就相当于一间能住8个人。 这里给出一些常见的内存单位

了解完内存我们来说说地址,地址就相当于门牌号,平时在购物时买东西填的地址填的可不就是家里的门牌号嘛,所以通过门牌号(地址)快递员才能找对地方给我们派件;对应计算机也是一样的,地址为每一个内存进行编号。比如上面所说的宿舍楼每一间都有不同的门牌号,只不过C语言给地址取了一个新的名字叫指针我们给出一张图来让你更直观和清晰的了解内存和地址的关系。

了解完了内存和地址接下来我们来了解一下编址。
二,编址
谈到编址就不得不谈到一些硬件上的知识了,要了解编址首先必须理解,计算机内是有很多的硬件单元,而硬件单元是要互相协同工作的。所谓的协同,至少相互之间要能够进行数据传递。但是硬件与硬件之间是互相独立的,那么如何通信呢?
答案很简单,用"线"连起来。 而CPU和内存之间也是有大量的数据交互的,所以,两者必须也用线连起来。 不过,我们今天关心一组线,叫做地址总线。
我们画图来让大家更好的理解:

搞清楚上图的原理我们来说说为什么要编址?
CPU访问内存中的某个字节空间,必须知道这个 字节空间在内存的什么位置,而因为内存中字节很多,所以需要给内存进⾏编址(就如同宿舍很多,需要给宿舍编号⼀样)。但是计算机中的编址,并不是把每个字节的地址记录下来,而是通过硬件设计完成的。
上面说到什么地址总线,数据总线,控制总线那大家是不是很好奇,为什么电路板上会有这么多的线呢?
在硬件电路中只有高电平和低电平这两种状态,这两种状态分别代表0和1,但是你想想既然一根能表示两种状态,那么2根能表示3种,以此类推以2的n次方呈现指数式增长,而线越多能表示的东西也越多,比如我们现在用的64位机器就可以表示2^64这么多种含义而每一种含义都代表一个地址;地址信息被下达给内存,在内存上,就可以找到 该地址对应的数据,将数据在通过数据总线传入CPU内寄存器。
三,指针变量和地址
1,&(取地址)操作符
既然指针与地址关系那么密切那我们就有必要来学习一下&(取地址)操作符,我们给出一段代码:
#include<stdio.h>
int main()
{int a = 10;printf("%p",&a);//%p是专门用来打印地址的占位符 注意是&a
}

我们也可以调试起来让大家来看:

但有一点需要特别注意取地址取出来的是较小的地址,因为我们知道数据类型占几个字节又知道较小的地址剩下的顺藤摸瓜直接往后推算即可。
我们来看看在内存中是怎么样存储的:

2,指针变量
我们已经了解了&操作符,并且已经拿到了变量的地址,那么这时就会有人问了:我们已经拿到了变量的地址,怎么去存放它呢?答案是使用指针变量。
#include<stdio.h>
int main()
{int a = 10;char b = 'b';char * ch = &b;int * p = &a;
}
上面我们定义了两个指针变量分别为ch和p来储存a和b的地址,这样我们就可以通过访问指针变量来间接访问a和b。我们如何来看待指针变量呢?
这里p左边写的是 int , * 是在说明p是指针变量,而前面的 int 是在说明pa指向的是整型(int) 类型的对象。
ch左边写的是 char , * 是在说明ch是指针变量,而前面的 char 是在说明pa指向的是整型(int) 类型的对象。
画一个图你就明白了:

当我们了解了如何存储地址后肯定会想这如何去使用它,这就引出了我们的解引用操作符。
3,解引用操作符
在现实生活中,我们使用地址要找到⼀个房间,在房间里可以拿去或者存放物品。 C语言中其实也是⼀样的,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针) 指向的对象,这里必须学习⼀个操作符叫解引用操作符(*)。
举个例子:
#include<stdio.h>
itn main()
{int a = 100;printf("a=%d\n",a);int * p = &a;*p=0;//*p拿到了p所指向的对象 a 对*p操作即是对a操作 这里就是间接访问printf("a=%d",*p);//这里注意打印的一定是*p而不是preturn 0;
}

从运行结果来看我们看到,通过 * 这个解引用操作可以间接来改变a的值。 * p实际上就是通过通过pa中存放的地址,找到指向的空间所以 * p本质上就是a变量了。

另外值得注意的是一定要分清 * p和p 前者是对p这个指针变量进行解引用操作;后者则是指针变量其存储的是p所指向对象(a)的地址。
说完了解引用我们来看看指针变量的大小。
4,指针变量的大小
32位机器假设有32根地址总线,每根地址线出来的电信号转换成数字信号后是1或者0,那我们把32根地址线产⽣的2进制序列当做⼀个地址,那么⼀个地址就是32个bit位,需要4 个字节才能存储。
如果指针变量是⽤来存放地址的,那么指针变量的大小就得是4个字节的空间才可以。
同理64位机器,假设有64根地址线,⼀个地址就是64个⼆进制位组成的⼆进制序列,存储起来就需要 8个字节的空间,指针变量的大小就是8个字节。
#include <stdio.h>
//指针变量的⼤⼩取决于地址的⼤⼩
//32位平台下地址是32个bit位(即4个字节)
//64位平台下地址是64个bit位(即8个字节)
int main()
{ //zd是专门用来打印sizeof的返回值的printf("%zd\n", sizeof(char *)); printf("%zd\n", sizeof(short *)); printf("%zd\n", sizeof(int *)); printf("%zd\n", sizeof(double *)); return 0;
}
我们分别让它在32位和64位平台下运行看看会有什么结果:


我么可以看到在不同平台下的结果是不同的所以我们可以知道:
• 32位平台下地址是32个bit位,指针变量大小是4个字节
• 64位平台下地址是64个bit位,指针变量大小是8个字节
• 注意指针变量的大小和类型是无关的,只要指针类型的变量,在相同的平台下,大小都是相同的。

既然指针变量的大小和类型无关,只要是指针变量,在同⼀个平台下,大小都是⼀样的,为什么还要有各种各样的指针类型呢?接下来我们就来探究一下指针类型的意义。
四,指针类型的意义
我们先来看两段代码:
#include <stdio.h>
int main()
{ int n = 0x11223344; int *pi = &n; *pi = 0; return 0;
}
我们来看调试结果:

#include <stdio.h>
int main()
{int n = 0x11223344; char *pc = (char *)&n; //强制转换为char*的地址 赋给字符指针变量pc*pc = 0; return 0;
}
我们直接看调试结果:

对比这两次调试结果不知各位读者有没有发现第一次*pi变成0结果整个n的值(4个字节)都变为了0。
而第二次*pc变成零只有前面一个字节变成了0。
由此我们得出结论:指针的类型决定了,对指针解引⽤的时候有多⼤的权限(⼀次能操作指针所指对象的几个字节)。 比如: char* 的指针解引⽤就只能访问⼀个字节,而int* 的指针的解引⽤就能访问四个字节。 操作的一定是指针所指对象的空间!
五,偏移量
偏移量相信大家在物理中都能经常听到,而偏移量在指针中代码什么意思呢?偏移量指的就是指针变量加减整数时的那个数字叫做偏移量。偏移量是为了形象说明不是专有名词哈。
举个例子:
#include<stdio.h>
int main()
{int a=0;char*pc=(char*)&a;int *pi=&a;printf("&a = %p\n",&a);printf("pc = %p\n",pc);printf("pc+1 = %p\n",pc+1);printf("pi = %p\n",pi);printf("pi+1 = %p\n",pi+1);return 0;
}

从上图我们可以看到:
我们可以看出, char 类型的指针变量+1跳过1个字节, int 类型的指针变量+1跳过了4个字节。 这就是指针变量的类型差异带来的变化。指针+1,其实跳过1个指针指向的元素。指针可以+1,那也可 以-1。偏移的其实就是一个类型的大小比如int类型 +1就偏移4个字节。
结论:指针的类型决定了指针向前或者向后偏移的距离。
了解完了这些基本的知识后我们就来看一些有关指针的的运算
六,指针的运算
指针的基本运算有三种,分别是:
1,指针± 整数
2,指针-指针
3,指针的关系运算
我们依次给出代码大家可以体会一下:
1,指针加整数型
#include<stdio.h>
int main()
{//指针加整数型int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);int* p = arr;for (int i = 0;i < sz;i++){//printf("%d \n", p);//注意这样打印出来的是以%d形式打印的地址//printf("%p \n", p);//这样是打印所有元素的地址printf("%d ", *p);//加上*号是解引用 这样打印的才是所有元素p++;}return 0;
}
#include<stdio.h>
int main()
{ int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);int* p = arr;for (int i = 0;i < sz;i++){printf("%d ", *(p + i));//(p+i)括号指针变量加整数是偏移量的意思即 往后取i个地址并把该地址的内容以%d形式打印出来}return 0;
}
2,指针减指针,及指针的关系运算
#include <stdio.h>
int my_strlen(char *s)
{ char *p = s; while(*p != '\0' ) p++; return p-s;
}
int main()
{ printf("%d\n", my_strlen("abc")); return 0;
}
以上就是本章的全部内容啦!
感谢能够看到这里的读者,如果我的文章能够帮到你那我甚是荣幸,文章有任何问题都欢迎指出!制作不易还望给一个免费的三连,你们的支持就是我最大的动力!

相关文章:
C语言的灵魂——指针(1)
指针是C语言的灵魂,有了指针C语言才能完成一些复杂的程序;没了指针就相当于C语言最精髓的部分被去掉了,可见指针是多么重要。废话不多讲我们直接开始。 指针 一,内存和地址二,编址三,指针变量和地址1&#…...
14-6-2C++STL的list
(一)list对象的带参数构造 1.list(elem);//构造函数将n个elem拷贝给本身 #include <iostream> #include <list> using namespace std; int main() { list<int> lst(3,7); list<int>::iterator it; for(itlst.begi…...
Linux 基础1
gcc的编译过程 预处理——编译——汇编——链接 Linux文件类型 普通文件,目录文件,管道文件,链接文件,块设备文件,字符设备文件,套接字文件 Linux系统下的软链接和硬链接有什么异同 linux中软链接和硬…...
Ubuntu Server 安装 XFCE4桌面
Ubuntu Server没有桌面环境,一些软件有桌面环境使用起来才更加方便,所以我尝试安装桌面环境。常用的桌面环境有:GNOME、KDE Plasma、XFCE4等。这里我选择安装XFCE4桌面环境,主要因为它是一个极轻量级的桌面环境,适合内…...
xarray转换nc文件经度范围:0-360更改为-180-180
原文见https://blog.csdn.net/weixin_44237337/article/details/119707332,因为觉得很实用就转载一下。 lon_name longitude #你的nc文件中经度的命名 ds[longitude_adjusted] xr.where(ds[lon_name] > 180,ds[lon_name] - 360,ds[lon_name]) ds (ds.swap_d…...
MySQL 基础学习(1):数据类型与操作数据库和数据表
MySQL 基础学习:数据类型与操作数据库和数据表 在这篇博客中,我们将深入学习 MySQL 的基础操作,重点关注数据库和数据表的操作,以及 MySQL 中常见的数据类型。希望本文能帮助你更好地理解和掌握 MySQL 的基本用法。 一、操作数据…...
一个简单的自适应html5导航模板
一个简单的 HTML 导航模板示例,它包含基本的导航栏结构,同时使用了 CSS 进行样式美化,让导航栏看起来更美观。另外,还添加了一些 JavaScript 代码,用于在移动端实现导航菜单的展开和收起功能。 PHP <!DOCTYPE htm…...
深入解析“Wholesome”的含义及用法
深入解析“Wholesome”的含义及用法 一、引言 在阅读英文材料时,我们经常会遇到一些词汇,它们的含义既有直接的字面意思,又带有丰富的情感色彩。“Wholesome”就是这样一个词。它表面上看似简单,但在不同语境中却有多重内涵。在…...
供水企业满意度调查报告
民安智库作为一家独立的第三方评估机构,致力于为供水企业提供全面的客户满意度调查服务。本报告将详细介绍民安智库的调查方法、结果和建议,以帮助供水企业更好地理解其服务质量和客户需求。 一、调查方法 民安智库首先对客户进行了分类,包括…...
实现B-树
一、概述 1.历史 B树(B-Tree)结构是一种高效存储和查询数据的方法,它的历史可以追溯到1970年代早期。B树的发明人Rudolf Bayer和Edward M. McCreight分别发表了一篇论文介绍了B树。这篇论文是1972年发表于《ACM Transactions on Database S…...
无人机微波图像传输数据链技术详解
无人机微波图像传输数据链技术是无人机通信系统中的关键组成部分,它确保了无人机与地面站之间高效、可靠的图像数据传输。以下是对该技术的详细解析: 一、技术原理 无人机微波图像传输数据链主要基于微波通信技术实现。在数据链路中,图像数…...
【Leetcode 热题 100】300. 最长递增子序列
问题背景 给你一个整数数组 n u m s nums nums,找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如, [ 3 , 6 , 2 , 7 ] [3,6,2,7] [3,6,2…...
macos的图标过大,这是因为有自己的设计规范
苹果官方链接:App 图标 | Apple Developer Documentation 这个在官方文档里有说明,并且提供了sketch 和 ps 的模板。 figma还提供了模板: Figma...
信号处理以及队列
下面是一个使用C和POSIX信号处理以及队列的简单示例。这个示例展示了如何使用信号处理程序将信号放入队列中,并在主循环中处理这些信号。 #include <iostream> #include <csignal> #include <queue> #include <mutex> #include <thread…...
微信阅读网站小程序的设计与实现(LW+源码+讲解)
专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…...
美国公司有意收购TikTok(抖音)
众所周知,2016年TikTok由字节跳动集团推出,最初以“抖音”为名在中国市场推广,随后于2017年下半年出海,面向国际市场更名为“TikTok”。 新华社1月19日快讯:“TikTok公司当地时间18日晚通知美国用户,由于美…...
《Java程序设计》课程考核试卷
一、单项选择题(本大题共10个小题,每小题2分,共20分) 1.下列用来编译Java源文件为字节码文件的工具是( )。 A.java B.javadoc C.jar D.javac 2…...
ThinkPHP 8 操作JSON数据
【图书介绍】《ThinkPHP 8高效构建Web应用》-CSDN博客 《2025新书 ThinkPHP 8高效构建Web应用 编程与应用开发丛书 夏磊 清华大学出版社教材书籍 9787302678236 ThinkPHP 8高效构建Web应用》【摘要 书评 试读】- 京东图书 使用VS Code开发ThinkPHP项目-CSDN博客 编程与应用开…...
《AI赋能光追:开启图形渲染新时代》
光线追踪技术是图形渲染领域的重大突破,能够通过模拟光的传播路径,精准渲染反射、折射、阴影和间接光照等效果,实现高度逼真的场景呈现。而人工智能的加入,更是为光线追踪技术带来了前所未有的变革,主要体现在以下几个…...
LeetCode | 最小路径和的两种解决办法
第一种:动态规划 思路 在过去,有这样一个词,那就是遇难则反,从起点推导出最小路径和是困难的,那我们就从终点去推导。 解题过程 我们都知道一个方块,只能向右或向下。在初始化dp之后,我们会…...
Windows 环境下 Docker Desktop + Kubernetes 部署项目指南
Windows 环境下 Docker Desktop Kubernetes 部署项目指南 一、环境准备二、安装与配置 Kubernetes安装 windows 版的 docker启动 kubernetes安装 windows 版的 kubectl 工具下载 k8s-for-docker-desktop启动 Kubernetes Dashboard 二、在 Kubernetes 上部署项目创建一个 demo …...
WebSocket 详解:全双工通信的实现与应用
目录 一、什么是 WebSocket?(简介) 二、为什么需要 WebSocket? 三、HTTP 与 WebSocket 的区别 WebSocket 的劣势 WebSocket 的常见应用场景 WebSocket 握手过程 WebSocket 事件处理和生命周期 一、什么是 WebSocket…...
神经网络|(二)sigmoid神经元函数
【1】引言 在前序学习进程中,我们已经了解了基本的二元分类器和神经元的构成,文章学习链接为: 神经网络|(一)加权平均法,感知机和神经元-CSDN博客 在此基础上,我们认识到神经元本身在做二元分类,是一种非…...
云原生:构建现代化应用的基石
一、什么是云原生? 云原生是一种构建和运行应用程序的方法,旨在充分利用云计算的分布式系统优势,例如弹性伸缩、微服务架构、容器化技术等。云原生应用程序从设计之初就考虑到了云环境的特点,能够更好地适应云平台的动态变化&…...
【浏览器 - Chrome调试模式,如何输出浏览器中的更多信息】
在开发过程中,如果不主动console.log,浏览器中的信息有些不会主动输出到 控制台console里面。这个如果是一些浏览器内部的接口调试,则会很麻烦。比如RTCPeerConnection过程 ,RTCPeerConnection属于浏览器内部的方法,其…...
不同操作系统(Windows、Linux)上安装和配置Tomcat的详细教程
以下是在不同操作系统(Windows、Linux)上安装和配置Tomcat的详细教程: Windows系统下Tomcat的安装与配置 下载Tomcat 访问Apache Tomcat官方网站(https://tomcat.apache.org)。在“Download”页面,根据需求选择合适的Tomcat版本。例如,选择“Core”下的zip压缩包下载。…...
MapReduce,Yarn,Spark理解与执行流程
MapReduce的API理解 Mapper 如果是单词计数:hello:1, hello:1, world:1 public void map(Object key, // 首字符偏移量Text value, // 文件的一行内容Context context) // Mapper端的上下文,…...
unity导入图片素材注意点和AI寻路模块导入
当我们导入了图片资源,我们需要设置为Sprite类型 UI资源的位置通常是Rect Transform 要进行转化: (imgHP.transform as RectTransform).sizeDelta new Vector2((float)hp / maxHP * hpW,74); RectTransform 是Unity中用于UI元素的特殊变换组件&#…...
单片机-STM32 IIC通信(OLED屏幕)(十一)
一、屏幕的分类 1、LED屏幕: 由无数个发光的LED灯珠按照一定的顺序排列而成,当需要显示内容的时候,点亮相关的LED灯即可,市场占有率很高,主要是用于户外,广告屏幕,成本低。 LED屏是一种用发光…...
Windows Docker Desktop安装及使用 Docker 运行 MySQL
Docker Desktop是Docker的官方桌面版,专为Mac和Windows用户设计,提供了一个简单易用的界面来管理和运行Docker容器。它集成了Docker引擎,为开发人员提供了一个快速、可靠、可扩展的方式来构建、运行和管理应用。DockerDesktop的优势在于&…...
