【C语言】解开指针|编址内存&解引用&指针产量|

  write in front :

个人主页 : @啊森要自信的主页

✨ 作者寄语 : 小菜鸟的力量不在于它的体型,而在于它内心的勇气和无限的潜能,只要你有决心,就没有什么事情是不可能的。

欢迎大家关注点赞收藏⭐️留言>希望看完我的文章对你有小小的帮助,如有错误,可以指出,让我们一起探讨学习交流,一起加油鸭。 请添加图片描述

文章目录

  • 开端
  • 一、内存和地址
    • 1.1 内存
    • 1.2 怎么理解编址呢?
  • 二、 指针变量和地址
    • 2.1 取地址操作符(&)
    • 2.2指针变量和解引⽤操作符(*)
      • 2.2.1 如何拆解指针类型
      • 2.2.2 解引⽤操作符
    • 2.3 指针变量的⼤⼩
  • 三、 指针变量类型的意义
    • 3.1 指针的解引⽤
    • 3.2 指针+ - 整数
    • 3.3 void* 指针


开端

C语言中的指针是一种特殊的变量,它存储了一个内存地址,该地址指向另一个变量的位置。指针允许程序直接访问和操作内存中的数据,而不需要将数据复制到另一个位置

指针在C语言中具有重要的作用,它可以用于动态内存分配、数组和字符串操作、函数传递参数等方面。通过指针,程序可以更灵活地处理内存中的数据,提高了程序的效率和性能。

看到这里,你可能会想到指针竟然有这么多的用处,但是我都不会呀?接下来博主带你一起解开指针的面纱,体会不一样的指针!


一、内存和地址

1.1 内存

在学习内存和地址之前,我们想想这个:
【C语言】解开指针|编址内存&解引用&指针产量|_第1张图片

当我们早八要去教室上课时,我们冲到教学楼,我们怎么找到我们上课的教室呢?像教室有这么多个,我们不可能一个一个的找,不然这样很容易迟到,同样效率也就低了,但是如果我们给每个教室门口上个牌子,然后编上号:一栋教学楼—>

  1. 一楼:101,102,103…
  2. 二楼:201,202,203…

  3. 【C语言】解开指针|编址内存&解引用&指针产量|_第2张图片

有了这个教室门牌号,你就可以立马跑上去,快速找到,并签到,不会迟到。

接下来,我们把上面的案例对比我们的计算中,又会怎么样呢?

CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数据也会放回内存中,买电脑的,电脑上的内存8G/16G/32G等,这些内存空间是怎么高效的管理我们的数据的呢?
【C语言】解开指针|编址内存&解引用&指针产量|_第3张图片

在内存中,内存划分为一个一个内存单元,每个内存单元的大小取1个字节一个字节有多大呢?
计算机中常⻅的单位(补充):
⼀个⽐特位(bit)可以存储⼀个2进制的位1或者0

bit - ⽐特位
byte - 字节
KB - 千字节
MB -兆字节
GB - 千兆字节
TB - 千千兆字节
PB - 拍字节
  1. 1byte = 8bit
  2. 1KB = 1024byte
  3. 1MB = 1024KB
  4. 1GB = 1024MB
  5. 1TB = 1024GB
  6. 1PB = 1024TB

每个内存单元也都有⼀个编号(这个编号就相当于教室的⻔牌号),有了这个内存单元的编号,CPU就可以快速找到这个内存空间。

生活中我们把门牌号也叫地址,在计算机中我们把内存单元的编号也称为地址。C语⾔中给地址起了新的名字叫:指针。

所以我们可以理解为:
内存单元的编号 == 地址 == 指针
【C语言】解开指针|编址内存&解引用&指针产量|_第4张图片

1.2 怎么理解编址呢?

CPU访问内存中的某个字节空间,必须知道这个
字节空间在内存的什么位置,而因为内存中字节
很多,所以需要给内存进行编址(就如同教室很
多,需要给教室编号一样)。
【C语言】解开指针|编址内存&解引用&指针产量|_第5张图片
小知识来了:计算机中的编址,并不是把每个字节的地址记录下来,⽽是通过硬件设计完成的。也就是说计算中的编址,不是把整个地址编号记录下来,而是制造商已经在硬件层⾯上设计好了。

计算机内部有许多硬件单元,这些单元需要相互协作。协作的意思是它们至少要能够进行数据传输。但是,硬件单元之间是相互独立的,那么它们如何进行通信呢?

答案很简单,通过连接线进行通信。

CPU想读取内存中某一个数据中时,控制总线发出一个信号,CPU通过地址总线把内存中的这个位置找到,然后再通过数据总线传给CPU.

CPU和内存之间也需要进行大量的数据交互,因此它们必须通过连接线进行连接。然而,今天我们要关注的是一组连接线,称为地址总线。

学到这里,同学们可能有个疑问,地址总线有多少根,怎么构建联系的呢?32位机器有32根地址总线,64位机器有64根地址总线,每根线只有两态,表⽰0,1【电脉冲有⽆】,那么⼀根线,就能表⽰2种含义,2根线就能表⽰4种含义,依次类推。32根地址线,就能表⽰2^32种含义,每⼀种含义都代表⼀个地址。地址信息被下达给内存,在内存上,就可以找到该地址对应的数据,将数据在通过数据总线传⼊CPU内寄存器。
【C语言】解开指针|编址内存&解引用&指针产量|_第6张图片

二、 指针变量和地址

2.1 取地址操作符(&)

当我们理解了内存和地址的关系,我们再回到C语⾔,在C语⾔中创建变量其实有两种含义:

#include 
int main()
{
 	int a = 66;内层含义
 	return 0;
}

&a取出的是类型为a所占4个字节中地址较小的地址。我们知道a的地址,就能推出他剩下的三个地址了,就可以访问到他4个字节的数据。
【C语言】解开指针|编址内存&解引用&指针产量|_第7张图片
16进制转换为2进制:
【C语言】解开指针|编址内存&解引用&指针产量|_第8张图片
怎么观测到a的地址呢?
按F10调试起来,打开窗口找到内存窗口,4个点击哪一个都可以。
【C语言】解开指针|编址内存&解引用&指针产量|_第9张图片

输入&取地址操作符(&a)就可以找到对应的地址,当然也可以在监视看,以下在内存中观察:
【C语言】解开指针|编址内存&解引用&指针产量|_第10张图片

2.2指针变量和解引⽤操作符(*)

那我们通过取地址操作符(&)拿到的地址是⼀个数值,⽐如:0x006ffae0,这个数值有时候也是需要存储起来,⽅便后期再使⽤的,那我们把这样的地址值存放在哪⾥呢?答案是:指针变量中。
⽐如:

#include 
int main()
{
 	int a = 10;
 	int* pa = &a;//取出a的地址并存储到指针变量pa中
 	return 0
}

【C语言】解开指针|编址内存&解引用&指针产量|_第11张图片

指针变量也是⼀种变量,这种变量就是⽤来存放地址的,存放在指针变量中的值都会理解为地址。

2.2.1 如何拆解指针类型

我们看到pa的类型是 int* ,我们该如何理解指针的类型呢?

nt a = 10;
int * pa = &a;

这⾥pa左边写的是 int** 是在说明pa是指针变量,⽽前⾯的 int 是在说明pa指向的是整型(int)类型的对象。

【C语言】解开指针|编址内存&解引用&指针产量|_第12张图片

【C语言】解开指针|编址内存&解引用&指针产量|_第13张图片

那如果有⼀个char类型的变量chch的地址,要放在什么类型的指针变量中呢?

char ch = 'R';
pc = &ch;//pc 的类型怎么写呢?

答案是:
char *pc = &ch;

2.2.2 解引⽤操作符

解引用运算符( * ) 将指针变量所指向的对象的值赋给左值变量。当使用指针变量时,使用解引用运算符来访问指针变量所指向的对象。

#include 
int main()
{
	int a = 100;
	int* pa = &a;
	*pa = 0;
	printf("%d", a);
	return 0;
}

*pa 的意思就是通过pa中存放的地址,找到指向的空间,
*pa其实就是a变量了;所以*pa = 0,这个操作符是把a改成了0
【C语言】解开指针|编址内存&解引用&指针产量|_第14张图片

#include 

int main()
{
    int num1 = 10;
    int *ptr1 = &num1;

    printf("The value of num1 is %d\n", num1);
    printf("The address of num1 is %d\n", &num1);
    printf("The value of ptr1 is %d\n", ptr1);
    printf("The value of *ptr1 is %d\n", *ptr1);

    return 0;
}

变量 num1 的值为 10,因为它被赋值为 10。
变量 num1 的地址为 13629256,因为它在内存中的位置是 13629256。
变量 ptr1 的值为 13629256,因为它被赋值为 num1 的地址。
变量 *ptr1 的值为 10,因为它是 ptr1 所指向的对象的值。
【C语言】解开指针|编址内存&解引用&指针产量|_第15张图片

2.3 指针变量的⼤⼩

指针变量的⼤⼩取决于地址的⼤⼩

• 32位平台下地址是32个bit位,指针变量⼤⼩是4个字节
• 64位平台下地址是64个bit位,指针变量⼤⼩是8个字节
• 注意指针变量的⼤⼩和类型是⽆关的,只要指针类型的变量,在相同的平台下,⼤⼩都是相同的。

32位机器假设有32根地址总线,每根地址线出来的电信号转换成数字信号后是1或者0,那我们把32根地址线产⽣的2进制序列当做⼀个地址,那么⼀个地址就是32个bit位,需要4个字节才能存储。

#include 
int main()
{
	int* a = 10;
	short* b = 10;
	char* c = 10;
	double* d = 10;
	
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(b));
	printf("%d\n", sizeof(c));
	printf("%d\n", sizeof(d));
	return 0;
}

debug X86也就是调试状态下的32位环境下:
【C语言】解开指针|编址内存&解引用&指针产量|_第16张图片

debug X64也就是调试状态下的64位环境下:
【C语言】解开指针|编址内存&解引用&指针产量|_第17张图片

三、 指针变量类型的意义

当你看到这里,你发现指针变量的⼤⼩和类型⽆关,只要是指针变量,在同⼀个平台下,⼤⼩都是⼀样的, 那还要那么多的指针类型干嘛呢?统一归为一种指针类型不就好了,就没那么麻烦了,bug或许可能就没有那么多了!同学带着你的疑问,让我们一起走下去。看看为什么这么设计的?

3.1 指针的解引⽤

首先,我们观察两组代码的变化环境为debug x86

  1. 代码1:
#include 
int main()
{
	int n = 0x66778899;
	int* pk = &n;
	*pk = 0;
	return 0;
}

【C语言】解开指针|编址内存&解引用&指针产量|_第18张图片

  1. 代码2:
#include 
int main()
{
	int n = 0x66778899;
	char* pk = (char*)&n;
	*pk = 0;
	return 0;
}

【C语言】解开指针|编址内存&解引用&指针产量|_第19张图片
调试我们可以看到,代码1会将n的4个字节全部改为0,但是代码2只是将n的第⼀个字节改为0。

结论:指针的类型决定了,对指针解引⽤的时候有多⼤的权限(⼀次能操作⼏个字节)。

⽐如: char* 的指针解引⽤就只能访问⼀个字节,⽽ int* 的指针的解引⽤就能访问四个字节

3.2 指针+ - 整数

指针加减整数的语法如下:

ptr + n
ptr - n

其中,ptr 是指针变量,n 是整数。

当我们向一个指针加减整数时,我们实际上是在向指针所指向的内存地址加减整数。这意味着,如果我们向一个指针加 1,则指针会指向内存中下一个字节的位置。如果我们向一个指针减 1,则指针会指向内存中上一个字节的位置。

以下是不同类型的指针加减整数的示例:

整数指针:

int *p = 0;
p++; // 指向内存中下一个字节的位置
p--; // 指向内存中上一个字节的位置

指针数组:

int arr[] = {1, 2, 3, 4, 5};
int *p = arr;//int*类型加4
p++; // 指向内存中下一个元素的位置
p--; // 指向内存中上一个元素的位置

以下是指针加减 1 的示例:

#include 
int main()
{
	int n = 10;
	char* pc = (char*)&n;
	int* pi = &n;
	int* arr[] = { 1,2,3,4,5 };
	int* pk = arr;
	printf("%p\n", &n);
	printf("%p\n", pc);
	printf("%p\n", pc + 1);
	printf("%p\n", pi);
	printf("%p\n", pi + 1);
	printf("%p\n", pk);
	printf("%p\n", pk + 1);
	return 0;
}

运行结果:

【C语言】解开指针|编址内存&解引用&指针产量|_第20张图片

可以看到,
char类型的指针变量+1跳过1个字节,int类型的指针变量+1跳过了4个字节。这表明指针变量的类型差异会导致步长的变化。
结论:指针的类型决定了指针向前或向后移动一步的距离。

3.3 void* 指针

void 指针是 C 语言中一种特殊的指针,它可以指向任何类型的数据。void 指针的类型是 void,它不指向任何特定的数据类型。

void* 类型的指针不能直接进⾏指针的±整数和解引⽤的运算。

void 指针也可以用来解引用,但必须在解引用之前使用类型转换。void` 指针可以用来存储指向任何类型数据的指针。

#include 
int main()
{
	int a = 88;
	void* p=&a;
	int* q = (int*)p;//类型转换
	printf("n = %d\n", *q);
	return 0;
}

【C语言】解开指针|编址内存&解引用&指针产量|_第21张图片

void* 类型的指针不能直接进⾏指针的±整数和解引⽤的运算。
【C语言】解开指针|编址内存&解引用&指针产量|_第22张图片


你可能感兴趣的:(我爱C语言,c语言,开发语言,算法)