C语言指针入门 《C语言非常道》

2024-09-09 05:32
文章标签 语言 指针 入门 非常

本文主要是介绍C语言指针入门 《C语言非常道》,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C语言指针入门 《C语言非常道》

作为一个程序员,我接触 C 语言有十年了。有的朋友让我推荐 C 语言的参考书,我不敢乱推荐,尤其是国内作者写的书,往往七拼八凑,漏洞百出。

但是,李忠老师的《C语言非常道》值得一读。对了,李老师有个官网,网址是:

李忠老师官网

最棒的是,有配套的教学视频,可以试看。

试看点这里

在这里插入图片描述

在这里插入图片描述

接下来言归正传,讲解指针。以下内容很多都参考了李忠老师的《C语言非常道》,如果读起来吃力的话,建议看视频。

文章目录

  • C语言指针入门 《C语言非常道》
    • 初识指针
    • 取地址运算符和指针变量的声明
    • 指针指向什么类型很重要
    • 解引用运算符
    • 总结与补充

指针是 C 语言的难点,也是亮点。有人说如果不懂指针,那就不算是掌握了 C 语言。

作为一个嵌入式软件工程师,我认为指针是 C 语言的杀手锏,离开了它,C 语言不可能在嵌入式领域“一览众山小”。

好了,进入正题。

初识指针

int a = 5;

这句话定义了 int 类型的变量 a,并给它赋值 5;

在计算机执行这条语句的时候,会为变量 a 分配内存。

从此,这块内存就和 a 联系起来了,可以说变量名 a 就是这块内存的化身。目前,这块内存的存储值是 5。

在这里插入图片描述

如果你要把存储值修改为 8,你可以写

a = 8;

程序执行的时候,它自然会根据变量名 a 找到这块内存,把里面存储的值改为 8.

在这里插入图片描述

如果不知道这块内存的名字是 a,你还能修改它的存储值吗?

方法还是有的,那就是通过“指针”。

其实在计算机眼中,内存是有地址的。要访问某个内存单元,需要知道它的地址。如果把内存比喻成一排房子,那内存地址就是房子的门牌号码。

在这里插入图片描述

如上图所示,右边标注的就是内存的地址(假设一个格子占 4 字节),变量 a 的内存地址就是 12.

如下图所示,假设有个变量 b,它里面的内容刚好是变量 a 的内存地址(12),那么顺着这个地址就可以找到变量 a.

红色箭头表示顺着变量 b 的值(其实是 a 的地址——12)找到了变量 a.

在这里插入图片描述

你瞧,b 代表的值,像指针一样,指向那个地址上的变量,鉴于这种类比特别形象,C 语言引入了指针类型,简称指针。图中的变量 b 就是指针类型。

取地址运算符和指针变量的声明

有人问,你怎么知道变量 a 的地址是 12 呢?

C 语言里面有个运算符——“&”,叫“取地址运算符”,用于取得某个变量的地址。要得到变量 a 的地址,可以这样写:&a

要想把 a 的地址保存在 b 中,可以这样写:

int *b;
int a = 8;
b = &a;

第 1 行,定义了一个变量,变量名字是 b.
第 3 行,获得变量 a 的地址,把这个地址存储在变量 b 中。

int *b; 应该这样理解:

首先,从标识符开始读,因为标识符 b 的右边是分号,所以要向左读,左边是 *,意思是指针,所以读做 b 的类型是指针

其次,对于指针这种类型来说,它指向的类型也很关键,我们继续向左读,遇到了“int”,所以读“指向 int

把粗体字连起来:b 的类型是指针,指向 int

再比如:

int * p;  // 注意,* 和 p 之间也可以有空格

这句话定义了一个指针类型的变量 p,准确地说,p 的类型是指针,指向 int 类型,即 p 是一个指向 int 类型的指针变量。

在这里插入图片描述
上图来自李忠老师的书——《C语言非常道》,告诉我们如何读指针类型的声明或定义。

注意:指针类型是个统称,根据它所指向的类型,可细分为指向 char 的指针、指向 short 的指针、指向 int 的指针,等等。

要把变量 x 的地址保存在一个变量里,这个变量的类型必须是指针类型,而且,指针指向的类型必须和 x 的类型一致。例如,如果 x 是 char 类型,那么指向 x 的指针要声明为 char * p;如果 x 是 double 类型,那么指向 x 的指针要声明为 double * p;

指针指向什么类型很重要

有人会说:指针变量就是存储地址的变量,顺着这个地址,可以找到另一个变量,这个可以理解,但是为什么要强调指针指向的类型呢?

在 C 语言里,取地址运算符 & 的结果(值)并不单纯是一个地址,而是一个包含了类型信息的地址

例如前面提到的 &a,它确实可以计算变量 a 的地址,但是这个地址还包含了一个信息,即这个地址是用于访问 int 类型变量的(因为 a 是 int 类型)。

为什么要附加一个类型信息呢?

前面我画的内存图示比较粗,现在细化一下。假设我的实验环境下,int 类型的变量占 4 个字节,short 类型占 2 个字节,char 类型占 1 个字节。现在定义 3 个变量,运行时的内存如下图所示:

在这里插入图片描述

右边标注的是内存地址,每个格子代表一个字节,你会发现内存地址是按照字节来编号的。

对于变量 a ,它占据了 4 个字节,即内存 12、13、14、15.

有人会问,那 a 的地址是多少?是 12 还是 13,还是 14,或者 15?

按照规定,a 的地址是它所占内存中编号最小的那个,即 12.

在这里插入图片描述

如果指针不含有类型信息,仅仅是一个地址(比如 12),那么顺着这个地址去访问内存,到底访问多少字节呢?

举个例子,假设要修改 a 的值为 100,如果不是按照 4 个字节来写,而是按照 8 个字节来写,那肯定会把变量 m 和 n 的值给覆盖,这肯定不行。

所以,指针必须含有类型信息,这样才能知道此地址指示的变量占用多大的内存,访问的时候才不会出错。

在这里插入图片描述

如图所示,一旦知道了指针 b 所指向的类型是 int ,在访问 a 的时候,就可以锁定 12~15 这四个字节。

所以,一个指针是包含 2 个信息的:

  1. 指针代表的地址。如图中的红色箭头,这个地址可以让我们定位到内存 12,但是我们只知道从 12 开始,不知道在哪里结束。
  2. 指针指向的类型。类型确定了,占多少个字节就确定了。如图中的红色虚线框,这个类型可以让我们锁定从 12 开始的 4 个字节( int 占 4 个字节)。这 4 个字节,就是变量 a 所占的内存。

基于以上 2 点,通过指针 b 间接访问变量 a 成为可能,堪称完美。

解引用运算符

如何通过 b 修改 a 的值呢?假设要通过 b 把 a 的值改为 100,可以这样写:

int *b;
int a = 8;
b = &a;
*b = 100;

第 4 行,b 左边的这个 *,不代表指针,而是解引用运算符,也叫间接运算符

前文已经说过,& 运算符用于取得变量的地址,而 * 运算符则根据一个地址来得到那个变量本身。也就是说, b 指向了哪个变量,*b 就代表那个变量。

所以,第 4 行的 *b = 100; 就相当于 a = 100;

*& 在一起可以互相抵消, 例如 *&a 就等价于 a,你想,&a 表示一个指向 a 的指针,指针左边加一个 *,就得到此指针指向的变量,于是又成了 a;

另外,&*b 等价于 b,因为 *b 就是 a,而 &a 就是 b.

总结与补充

相信有了前面的铺垫,你再读教科书上的文字会很有感觉。

以下几点是总结和补充。

  1. 一元 & 运算符称为取地址运算符,它需要一个右操作数,这个右操作数必须是变量或者函数。这是很自然的,只有内存中的变量或者函数才有地址,你不能取一个常量的地址,比如 & 250,这很荒唐。 一元 * 运算符则根据一个地址来得到那个变量(或者函数)本身 。(注意:指向函数的指针是进阶内容,初学者可以忽略。)

  2. “指针”这个词其实有多种含义,需要根据上下文来区分。

    1). 是一种类型,比如整形、浮点型等。指针这种类型特殊在它的值是一个内存地址,顺着这个地址可以找到另一个变量。

    2). 为方便起见,人们有时候也把指针类型的值叫作“指针”。 比如说, C 语言规定, 如果操作数的类型为 T,则一元 & 运算符的结果是指向 T 的指针。在这里,“指针”应该理解为“指针类型的值”。

    3). 人们更经常地把指针类型的变量叫作指针,相对于“p 是一个指针类型的变量”,人们更喜欢说“p 是一个指针”。

  3. 为了还原指针所指向的变量或函数,需要使用一元 *运算符。 C 语言规定,一元 * 运算符的操作数必须是一个指针(即指针类型的变量或值), 如果此指针指向某变量,则一元 * 运算符的结果是个左值(你可以认为左值就是代表变量的表达式 ),代表指向的变量。

  4. 如果两个指针指向的类型不同,则它们是不同的指针类型。

【end】

这篇关于C语言指针入门 《C语言非常道》的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1150296

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

数论入门整理(updating)

一、gcd lcm 基础中的基础,一般用来处理计算第一步什么的,分数化简之类。 LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; } <pre name="code" class="cpp">LL lcm(LL a, LL b){LL c = gcd(a, b);return a / c * b;} 例题:

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

【IPV6从入门到起飞】5-1 IPV6+Home Assistant(搭建基本环境)

【IPV6从入门到起飞】5-1 IPV6+Home Assistant #搭建基本环境 1 背景2 docker下载 hass3 创建容器4 浏览器访问 hass5 手机APP远程访问hass6 更多玩法 1 背景 既然电脑可以IPV6入站,手机流量可以访问IPV6网络的服务,为什么不在电脑搭建Home Assistant(hass),来控制你的设备呢?@智能家居 @万物互联

poj 2104 and hdu 2665 划分树模板入门题

题意: 给一个数组n(1e5)个数,给一个范围(fr, to, k),求这个范围中第k大的数。 解析: 划分树入门。 bing神的模板。 坑爹的地方是把-l 看成了-1........ 一直re。 代码: poj 2104: #include <iostream>#include <cstdio>#include <cstdlib>#include <al

MySQL-CRUD入门1

文章目录 认识配置文件client节点mysql节点mysqld节点 数据的添加(Create)添加一行数据添加多行数据两种添加数据的效率对比 数据的查询(Retrieve)全列查询指定列查询查询中带有表达式关于字面量关于as重命名 临时表引入distinct去重order by 排序关于NULL 认识配置文件 在我们的MySQL服务安装好了之后, 会有一个配置文件, 也就

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

MiniGPT-3D, 首个高效的3D点云大语言模型,仅需一张RTX3090显卡,训练一天时间,已开源

项目主页:https://tangyuan96.github.io/minigpt_3d_project_page/ 代码:https://github.com/TangYuan96/MiniGPT-3D 论文:https://arxiv.org/pdf/2405.01413 MiniGPT-3D在多个任务上取得了SoTA,被ACM MM2024接收,只拥有47.8M的可训练参数,在一张RTX