指针?地址?内存?

简介: 指针?地址?内存?

1.地址和地址上存储的值

  1. 地址:在计算机内存中,每个字节都有一个唯一的地址,用来标识它在内存中的位置。这个地址通常以十六进制表示,并且在程序运行时是固定的。指针就是用来存储和操作这些地址的变量,它们存储的是内存中某个对象或变量的地址。
  2. :内存地址中存储的实际数据,即在特定地址处存储的内容。这个值可以是任何数据类型,比如整数、字符、浮点数等。

所以当我们说“解引用一个指针”时,我们实际上是在获取该指针所指向地址处存储的值

通俗的讲,内存中的每个字节是实际存在的,我们用地址标识这些字节。而地址本身没有意义,只有解引用地址才能得到该地址对应的字节数据

并不是说一个地址只标识一个字节,
int *P,char *Q,对P保存的地址解引用*P可以得到一个8字节整型,对Q保存的地址解引用*Q可以得到一个4字节字符
。因此,我们可以通过强制转换指针的类型,修改它所标识字节的范围!

刚才我们使用了变量P和Q的值也就是他们保存的地址,当然也可以变量P进行修改:P = Q,这时我们修改了内存里一个8字节的数据,但是我们没有使用地址,这是怎么做到的呢?

当我们执行 int *P; 这样的语句时,系统会为变量 P 分配一块内存,然后将其地址与标识符 P 关联起来。所以在实际使用时,我们不需要显式地使用地址编译器会自动帮你完成地址的管理。

P = Q; 这样的语句中,编译器会知道 P 的地址,并将 Q 的值存储到该地址中。这个过程是由编译器隐式地完成的。你不需要手动获取 PQ 的地址,因为编译器已经知道P和Q的地址,可以直接将值存储到那个地址中。

也就是说我们虽然没有显式地解引用地址,然后对实际的字节进行修改,实际上标识符P已经和若干字节的地址关联起来了,所以我们在使用变量P和Q时,实际上就是通过解引用地址来操作实际的内存字节

只不过指针为我们提供了更灵活更强大的操作内存的方式,感谢指针!

2.二级指针进阶用法:深入理解地址和内存的关系

二级指针也是指针,保存的也是地址,不论几级指针,只要是指针,就保存地址

二级指针的类型是确定的,是一个指针,一级指针的类型不确定

我们之前谈到了,改变指针类型,可以修改它标识内存中字节的范围,因此也就修改了这个指针解引用的结果

二级指针解引用的结果是内存中的8个字节,一级指针解引用的结果由它的类型确定,比如int是4字节,char是1字节,等等

说了这么多,将一级指针转换成二级指针有什么用呢?

举一个例子

typedef struct task_s { 
    void *next;  // 指向下一个task
    int a;
}task_t;

这是一个结构体,大小是8+4=12字节

下面我们将一级指针转换成二级指针:

01:  task_t *task = (task_t *)malloc(sizeof(task_t)); // 创建一个task_t对象
02:  task_t *p = (task_t *)malloc(sizeof(task_t)); // 创建另一个task_t对象
03:
04:  task->next = p; // 等价于(*task).next = p;
05:  *(task **)task = p; //将一级指针转换成二级指针,并解引用, 结果是next指针

注意,04行和05行是完全等价的,你看出来二级指针的用法了吗?

一级指针task和二级指针task指向的地址是同一个task_t对象的首地址

而它们的区别在于解引用的结果:

1.一级指针解引用的结果是12个字节也就是整个task_t对象,操作其中的next成员:task->next或(*task).next

2.二级指针解引用的结果不再是整个对象,而是task_t对象的前8个字节,刚好是next在内存中的位置,所以*(task **)task等价于next

为什么会有这样的区别?

答案在前文中提到过两次:改变指针类型,可以修改它标识内存中字节的范围,因此也就修改了这个指针解引用的结果

将一级指针转换成二级指针,指针所标识的内存中的字节的范围从12字节变为8字节,解引用的结果也因此改变

推荐学习https://xxetb.xetslk.com/s/p5Ibb

目录
相关文章
|
4月前
|
存储 C语言
指针和动态内存分配
指针和动态内存分配
101 0
|
1月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
117 13
|
27天前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
1月前
|
存储 C语言 开发者
C 语言指针与内存管理
C语言中的指针与内存管理是编程的核心概念。指针用于存储变量的内存地址,实现数据的间接访问和操作;内存管理涉及动态分配(如malloc、free函数)和释放内存,确保程序高效运行并避免内存泄漏。掌握这两者对于编写高质量的C语言程序至关重要。
54 11
|
1月前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
1月前
|
容器
在使用指针数组进行动态内存分配时,如何避免内存泄漏
在使用指针数组进行动态内存分配时,避免内存泄漏的关键在于确保每个分配的内存块都能被正确释放。具体做法包括:1. 分配后立即检查是否成功;2. 使用完成后及时释放内存;3. 避免重复释放同一内存地址;4. 尽量使用智能指针或容器类管理内存。
|
1月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
100 4
|
2月前
链表指针的传参,传值和传地址
本文讨论了链表操作中指针传参的问题,特别是指针的传值与传地址的区别,并提供了修正代码,以确保链表插入操作能正确地修改指针指向的地址。
19 1
链表指针的传参,传值和传地址
|
2月前
|
存储 Rust C#
内存指针解引用
【10月更文挑战第14天】
44 1
|
2月前
|
C++
析构造函数就是为了释放内存,就是在局部指针消失前释放内存,拷贝构造函数就是以构造函数为模块,在堆里面新开一块,同一个变量在堆里面的地址
本文讨论了C++中构造函数和析构函数的作用,特别是它们在管理动态内存分配和释放中的重要性,以及如何正确地实现拷贝构造函数以避免内存泄漏。
42 2