C语言入门,深入理解指针(1)

目录

  • [1. 内存和地址](#1. 内存和地址)
  • [2. 指针变量和地址](#2. 指针变量和地址)
  • [3. 指针变量类型的意义](#3. 指针变量类型的意义)
  • [4. 指针运算](#4. 指针运算)

前言

指针是 C 语言中最重要也最让初学者头疼的概念之一。本文将从「内存与地址」讲起,逐步带你理解指针变量、指针类型、指针运算等核心知识,帮助你建立对指针的直观认识,为后续深入学习打下坚实基础。

本文适合C 语言初学者阅读,建议你已掌握基本的变量、数据类型和数组知识。阅读本文前,请确保你了解:变量的创建与赋值、基本数据类型(如 int、char)、数组的基本使用。

1.内存和地址

1.内存

内存作为电脑中很重要的一部分,当程序运行起来时,程序要加载到内存中,数据的存储也是在内存中。

我们先了解一下计算机中常见的单位:

Byte表示字节,bit表示比特位

我们知道当电脑中的CPU处理数据时,会从内存中读取数据,处理完后的数据放回内存中,那么内存是如何做到有效管理的呢?

我们将学生宿舍与内存结合进行说明,一栋学生宿舍里包含很多个房间,而内存也被划分为一个个内存单元;一个房间有8个床位,而一个内存单元就是一个字节,一个字节包含8个bit位;每个房间都有对应的宿舍号,通过宿舍号可以找到正确的宿舍,而一个内存单元也有对应的编号,通过编号可以找到对应的内存单元。宿舍号是宿舍的地址,那么编号就是一个内存单元的地址。

通过以上类比,我们得出1个结论:内存单元的编号=地址=指针(C语言规定)

2.如何理解编址

对于计算机中CPU和内存的联系,我们给上一张关系图:

读取数据:控制总线发出read的信号-->CPU-->想要访问内存空间的地址-->地址总线-->找到对应内存空间-->读取数据-->数据总线-->CPU

CPU和内存通过3种功能的线联系起来,进行数据的传输。

在今天我们主要关心一组线:地址总线,CPU想要访问内存中的某块空间,首先要知道内存存放的地址,才能去访问;而每个内存单元的地址不需要存起来,因为在计算机中内存的地址是通过硬件设计编写的,类似钢琴,每个琴键都有对应的固定发音。地址总线在32位环境下,有32根地址总线,1根线有2种状态,0或1,1根线可以表示2种含义,那么32根线可以表示2^32种含义,每一种含义对应一个地址。

2.指针变量和地址

1.取地址操作符:&

我们既然讲到编址的内容,顺便提问一下变量创建的本质是什么?

答案是在内存中申请一块空间,用来存放数据

举例:

变量a的创建,数据类型是int,向内存申请一块4个字节的空间用来存放10,在编译器和计算机看来,a其实是对应那块空间的地址;而空间的名字叫做a,实际上是方便程序员自己看的。

为了得到a的地址,我们需要运用到取地址操作符&,得到的是a所占4个字节中第1个字节的地址,通过这个地址,顺藤摸瓜就可以知道其他字节的地址。

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

1.指针变量

专门用来存放地址(指针)的变量,就叫做"指针变量 "。

2.如何拆解指针类型

根据上面的代码,为什么指针变量pa的类型是int *?

解释:星号表示pa是一个指针变量 ,int表示p所指向的对象的类型是整型 ,

其他类型指针变量依次类推。

3.解引用操作符(*)

当我们想要使用地址时,此时我们要用到解引用操作符*,这里的星号跟上面的星号表示指针变量的不一样,这里表示通过pa里面的地址找到它所指向的对象 。

比如下面的例子:

*pa通过解引用,根据pa里面的地址找到所指向的对象是变量a,将0赋给变量a,此时a的值变为0。

到此,我们又学习了一种修改数值的方法了。

3.指针变量的大小

在上述代码中,我们创建了指针变量pa,为此我们得向内存申请空间。但是pa这个指针变量的大小是多少?又要向内存申请多少空间呢?

指针变量的大小与地址的存储需要多大空间有关 。

在上面编址部分,我们讲到地址总线,而地址总线的数量跟环境有关,在32位机器下,把32根地址线产生的2进制序列当做一个地址,一个地址就是32个bit位,需要4个字节存储,指针变量的大小也就是4个字节;以此类推,64位机器下,64根地址线做一个地址,一个地址就是64个bit位,需要8个字节存储,指针变量的大小也就是8个字节。

指针变量的大小和类型是无关的,不同指针类型的变量在相同的平台下,大小都是一样的 。

在VS2022编译器进行演示:

在x64环境下运行的结果:

在x86环境下运行的结果:

3.指针变量类型的意义

从上述代码运行结果来看,在相同环境下,指针变量的大小相同,那为什么还要有不同的指针类型呢?下面对指针变量类型的意义进行讲解。

1.指针的解引用

对于上面2段代码,我们通过调试,观察内存的变化,代码1会将a的4个字节都变成0,而代码2会将a的1个字节变成0。

结论:指针的类型可以决定在解引用过程中的权限,也就是一次可以访问并操作多少个字节数。

2.指针±整数

当指针加上或减去一个整数,不同的指针变量类型会对结果产生什么影响呢?

举下面一段代码为例:

首先取出a的地址赋给不同类型的指针变量,紧接着打印pa、pb,还未发生改变前,这2个地址打印出来肯定是一样的,但是当pa+1、pb+1后,地址会怎么变化呢?

我们从运行结果可知:pa到pa+1地址增加了1,这说明了char类型的指针变量加1后会跳过1个字节;pb到pb+1地址增加了4,这说明了int 类型的指针变量加1后会跳过4个字节。

结论:指针的类型决定了指针(地址)向前或向后一步可以走多少字节

3.void*指针

在指针类型中存在着1种类型:void*类型,它可以接受任意类型地址,但不能直接进行指针的±整数和解引用运算。

举例:

将一个int类型变量的地址赋给int类型的指针变量,这不会出现什么问题;但将一个int类型变量的地址赋给char 类型的指针变量,编译器就会警告了,如下图:

然而void的出现,则不会出现不兼容问题,不同类型变量的地址赋给void*类型,它都能够去接收。

但是void*类型的指针无法参与指针相关的运算 ,如下面代码:

那么void类型的指针有什么用呢?一般void 类型的指针用在函数参数的部分,用于接受任何类型数据的地址。

4.指针运算

1.指针±整数

例1.

数组在内存中连续存放,我们只要知道第一个元素的地址,就可以顺藤摸瓜地找到其他元素。

在之前我们对数组的打印,也许是单纯的通过数组下标进行打印的:

但在今天,我们学习了指针的一些基本知识之后,我们也许可以试着用解引用来做:

或

例子2.

我们之前学过如何统计字符串的长度?用strlen函数去统计。

我们通过一个函数结合指针去写一下strlen函数的实现过程:

2.指针-指针

3.指针的关系运算

用指针去打印数组,代码如下:

总结

本文围绕 C 语言中的指针展开,核心要点如下:

  • 地址与指针 :内存单元都有编号,这个编号就是地址,C 语言规定地址即指针。通过取地址操作符 & 可以获取变量的地址。
  • 指针变量 :专门用来存放地址的变量称为指针变量,其类型由「指向对象的类型 + *」构成,如 int *pa 表示 pa 是指向整型的指针变量。
  • 解引用操作符 *:通过指针变量中存放的地址,找到并访问它所指向的对象,从而实现对数据的间接修改。
  • 指针变量的大小:指针变量的大小与类型无关,只与平台相关------32 位环境下为 4 字节,64 位环境下为 8 字节。
  • 指针类型的意义 :指针类型决定了解引用时一次能访问的字节数,也决定了指针 +/- 整数时一次跳过的字节数。
  • void* 指针:可以接收任意类型的地址,但不能直接参与指针的加减和解引用运算,常用于函数参数以接收任意类型数据的地址。
  • 指针运算 :指针可以 +/- 整数实现数组元素的遍历,两个指针相减可以得到元素个数,指针之间还可以进行关系运算(比较大小)。

掌握这些基础,你就已经迈出了理解 C 语言指针的第一步,后续可以进一步学习指针与数组、指针与函数、动态内存分配等进阶内容。

相关推荐
H.莓飛2 分钟前
【数据结构】快速排序专题
linux·服务器·c语言·数据结构·visual studio
努力实干7 分钟前
Qt/C++ 模块化设计与工程组织
开发语言·c++·qt
阿里嘎多学长14 分钟前
2026-10-23 GitHub 热点项目精选
开发语言·程序员·github·代码托管
Lhan.zzZ31 分钟前
Qt:动态库模块框架设计
开发语言·c++·qt
quantdash_cc36 分钟前
如何从多只股票的历史行情构建收益率矩阵?Python 与 QuantDash 实战教程
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
wuminyu38 分钟前
JVM规范学习总结-JVM规范基本概念
java·linux·c语言·jvm·c++
不是万能的豆学长4 小时前
filetidy 文件整理助手:一键归类 + 规范重命名(Python 零依赖单文件工具)
大数据·开发语言·python·技术美术
懂点Tech9 小时前
ctfshow MISC入门图片篇(信息附加):misc41解题思路
开发语言·python
catchadmin10 小时前
PHP 8.7 协程新提案 让跨协程代码共享请求身份
开发语言·php
念何架构之路10 小时前
go-grpc设计思想
开发语言·后端·golang