指针详解

目录

[1. 内存](#1. 内存)

[2. 编址​编辑](#2. 编址编辑)

[3. 指针变量和地址](#3. 指针变量和地址)

1)取地址操作符(&)

2)指针变量

3)指针类型

4)解引用操作符

[4. 指针变量的大小](#4. 指针变量的大小)

[5. 指针变量类型的意义](#5. 指针变量类型的意义)

1)指针的解引用

[6. 指针 +- 运算 (整数)](#6. 指针 +- 运算 (整数))

[7. void* 指针](#7. void* 指针)


1. 内存

内存划分为一个个的内存单元,每个内存单元的大小取1个字节

计算时 CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数据也会放回内存中

一个比特位可以存储一个2进制的位1或者0

bit - 比特位
byte - 字节      1byte = 8bit
KB               1KB = 1024byte
MB               1MB = 1024KB
GB               1GB = 1024MB
TB               1TB = 1024GB
PB               1PB = 1024TB

每个内存单元也都有一个编号,有了这个内存单元的编号,CPU就可以快速找到一个内存空间,同时C语言中给地址起了新的名字叫:指针 所以我们可以理解为:内存单元的编号 == 地址 == 指针

2. 编址

CPU访问内存中的某个字节空间,必须知道这个字节空间在内存的什么位置,而因为内存中字节很多,所以需要给内存进行编址

计算机中的编址,并不是把每个字节的地址记录下来,而是通过硬件设计完成

通过地址总线,就可以找到该地址对应的数据,将数据在通过数据总线传入CPU内寄存器

3. 指针变量和地址
1)取地址操作符(&)

在C语言中创建变量其实就是向内存申请空间

#include <stdio.h>
int main()
{
    int a = 10;//创建了整型变量a,内存中申请4个字节,用于存放整数10
    return 0;
}

我们可以通过取地址操作符(&)来得到a的地址

{
    int a = 10;
    &a;//取出a的地址
    printf("%p\n", &a);
    return 0;
}

推理图:

&a取出的是a所占4个字节中地址较小的字节的地址,虽然整型变量占用4个字节,我们只要知道了第一个字节地址,访问到4个字节的数据也是可行的

2)指针变量

我们通过取地址操作符(&) 拿到的地址是一个数值,比如:0x006FFD70,这个数值有时候也是需要存储起来,方便后期再使用的,那我们把这样的地址值存放**指针变量(其中的值为地址)**中

#include <stdio.h>
int main()
{
    int a = 10;
    int* pa = &a;//取出a的地址并存储到指针变量pa中
    return 0;
}
3)指针类型
int a = 10;
int * pa = &a;//pa左边写的是int* , * 是在说明pa是指针变量,而前面的int 是在说明pa指向的是整型(int)类型的对象
char ch = 'w';
pc = &ch;//同理
4)解引用操作符

通过地址(指针)找到地址(指针)指向的对象,这里必须学习一个操作符叫解引用操作符 ( * )

#include <stdio.h>

int main()
{
    int a = 100;
    int* pa = &a;
    *pa = 0;//*pa 的意思就是通过pa中存放的地址,找到指向的空间,*pa其实就是a变量了;所以*pa = 0, 
            //这个操作符是把a改成了0.
    return 0;
}
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()
{
    printf("%zd\n", sizeof(char *));  //4/8
    printf("%zd\n", sizeof(short *)); //4/8
    printf("%zd\n", sizeof(int *));   //4/8
    printf("%zd\n", sizeof(double *));//4/8
    return 0;
}

注意:指针变量的大小和类型是无关的,只要指针类型的变量,在相同的平台下,大小都是相同的

5. 指针变量类型的意义
1)指针的解引用
//代码1
#include <stdio.h>

int main()
{
    int n = 0x11223344;
    int *pi = &n;
    *pi = 0;
    return 0;
}

//代码2
#include <stdio.h>

int main()
{
    int n = 0x11223344;
    char *pc = (char *)&n;
    *pc = 0;
    return 0;
}

调试我们可以看到,代码1会将n的4个字节全部改为0,但是代码2只是将n的第一个字节改为 0

结论 :指针的类型决定了,对指针解引用的时候有多大的权限(一次能操作几个字节)

比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节

6. 指针 +- 运算 (整数)
#include <stdio.h>
int main()
{
    int n = 10;
    char *pc = (char*)&n;//强制类型装换 ( )
    int *pi = &n;
    printf("%p\n", &n);
    printf("%p\n", pc);
    printf("%p\n", pc+1);
    printf("%p\n", pi);
    printf("%p\n", pi+1);
    return 0;
}

我们可以看出, char* 类型的指针变量+1跳过1个字节,int* 类型的指针变量+1跳过了4个字节。这就是指针变量的类型差异带来的变化
结论:指针的类型决定了指针向前或者向后走一步有多大距离

7. void* 指针

在指针类型中有一种特殊的类型是void* 类型的,可以理解为无具体类型的指针(或者叫泛型指

针),这种类型的指针可以用来接受任意类型地址。

注意:void* 类型的指针不能直接进行指针的+-整数和解引用的运算

#include <stdio.h>
int main()
{
    int a = 10;
    int* pa = &a;
    char* pc = &a;//nt类型的变量的地址赋值给一个char*类型的指针变量 编译器给出了一个警告
    return 0;
}

由于类型不兼容。而使用void*类型就不会有这样的问题

#include <stdio.h>
int main()
{
    int a = 10;
    void* pa = &a;
    void* pc = &a;
    *pa = 10;
    *pc = 0;
    return 0;
}

一般void* 类型的指针是使用在函数参数的部分,用来接收不同类型数据的地址,这样的设计可以

实现泛型编程的效果。使得一个函数来处理多种类型的数据

谢谢观看

相关推荐
Navigator_Z1 小时前
数据结构C //线性表(链表)ADT结构及相关函数
c语言·数据结构·算法·链表
菜菜想进步2 小时前
内存管理(C++版)
c语言·开发语言·c++
知星小度S2 小时前
C语言——自定义类型
c语言·开发语言
cleveryuoyuo2 小时前
二叉树的链式结构和递归程序的递归流程图
c语言·数据结构·流程图
科研小白_d.s2 小时前
vscode配置c/c++环境
c语言·c++·vscode
暮色_年华3 小时前
嵌入式C语言自我修养:C语言的模块化的编程思想
c语言
大母猴啃编程4 小时前
数据结构---非线性--树
c语言·数据结构·学习·算法·青少年编程
码农探知5 小时前
鹏哥C语言自定义笔记重点(67-)
c语言·数据结构
追逐远方的梦5 小时前
二级C语言2023-3易错题
c语言·开发语言
kid_sup5 小时前
C语言错题本
c语言·开发语言