31 变量的访问方式(直接和间接),内存地址(32 位和 64 位),指针的概念与定义,取址与取值运算符(& 与 *)

目录

1 变量的访问方式

1.1 直接访问

1.2 间接访问

2 内存地址

2.1 唯一性

2.2 32 位系统的内存地址

2.3 64 位系统的内存地址

3 什么是指针

4 指针的定义

4.1 定义格式

4.2 三种定义指针的写法

5 取址运算符和取值运算符

5.1 取址运算符(&)

5.2 取值运算符(*)

6 指针应用案例

6.1 指针的赋值和间接访问

6.2 修改指针所指向的值


1 变量的访问方式

        内存作为计算机系统中至关重要的组件,承担着程序运行时数据存储的任务。为了高效地利用内存资源,它被细分为多个较小的存储单元,每个单元一般占据 1 个字节的空间当程序需要使用数据时,这些数据会首先被加载到内存中,形成变量的形式存在。不同的变量类型根据其特性,会在内存中占据不同大小的空间。那么,如何有效地访问这些存储在内存中的变量数据呢?主要存在两种访问方式:

1.1 直接访问

        这是最常见的访问方式,通过直接使用变量名即可实现对内存中数据的读取或修改。在大多数编程语言中,当我们声明一个变量并赋予其值后,就可以直接通过该变量名来操作其内存中的数据。例如,在 C 语言中,声明一个整型变量 int number  = 10; 之后,可以通过 number  直接访问这个变量的数据。

int number = 10;  
printf("%d\n", number); // 直接访问 number 变量的值

1.2 间接访问

        这种访问方式则是通过指针来实现的。指针是一个特殊的变量,用于存储其他变量的内存地址。通过指针,我们可以间接地访问或修改指针所指向的内存位置中的数据。这种方式提供了更大的灵活性,尤其是在处理大型数据结构或动态内存管理时。例如,在 C 语言中,如果有一个指针 int *ptr; 并且让它指向变量 number  的地址 ptr = &number; ,那么我们可以通过 *ptr 来访问 number  的值。

int number = 10;  
int *ptr = &number; // ptr 是一个指针,存储了 number 的地址  
printf("%d\n", *ptr); // 通过指针 ptr 间接访问 number 的值

2 内存地址

2.1 唯一性

        为了确保每个内存单元都能被准确无误地访问,每个单元都被赋予了一个唯一的编号,这个编号就是内存地址。由于每个内存单元都拥有自己的地址,因此存储在这些单元中的变量也自然拥有了对应的地址。内存地址的存在使得程序能够精确地定位和操作数据,是计算机内存管理系统的基础。

        假设有 int 型变量 num,其在内存中会占用 4 个字节,也就是占用 4 个内存单元,第一个内存单元的地址即是变量 num 的地址。如下图所示: 

2.2 32 位系统的内存地址

        在 32 位架构的系统中,内存地址通常由 32 位(4 个字节)的二进制数字构成。这意味着理论上可以寻址 2 的 32 次方个不同的内存位置,大约等同于 4GB 的内存空间。这对于早期的个人计算机和某些嵌入式系统来说已经足够,但在现代计算环境中可能显得有些局限。

        在 32 位系统中,打印出来的内存地址通常有 8 位十六进制数字。这是因为 32 位系统中的内存地址是 32 位(4 个字节)的二进制数,每 4 位二进制数可以用 1 位十六进制数表示。因此,32 位地址转换为十六进制表示时,会有 8 位(32 / 4 = 8)的十六进制数字。

2.3 64 位系统的内存地址

        随着技术的发展,64 位架构的系统成为了主流。这类系统中的内存地址则由 64 位(8 个字节)的二进制数字组成,能够寻址的内存位置数量达到了 2 的 64 次方,这是一个极其庞大的数字,远超目前任何实际应用中所需的内存容量。64 位系统的出现极大地扩展了可寻址内存空间,为高性能计算和大数据处理提供了坚实的硬件基础。

        在 64 位系统中,打印出来的内存地址通常有 16 位十六进制数字。这是因为 64 位系统中的内存地址是 64 位(8 个字节)的二进制数,每 4 位二进制数可以用 1 位十六进制数表示。因此,64 位地址转换为十六进制表示时,会有 16 位(64 / 4 = 16)的十六进制数字。

提示:

        无论指针指向 int、char、float 还是 double,指针本身的长度是固定的,由系统的位数决定。在 32 位系统中,所有指针的长度都是 4 个字节;在 64 位系统中,所有指针的长度都是 8 个字节


3 什么是指针

        在编程中,如果一个变量专门用于存储另一个变量的内存地址,那么这个变量就被称为指针变量,简称指针。指针提供了一种间接访问内存中数据的方法。通过指针,我们不仅可以访问数据本身,还可以修改数据,甚至可以改变指针所指向的内存地址

        如下图所示,有一个整型变量 num,它的值存储在某个内存地址中。如果创建一个指针变量 ptr 并将 num 的地址赋值给 ptr,那么我们就可以说 ptr 指向了变量 num通过 ptr,我们可以间接访问和操作 num 的值


4 指针的定义

        指针是一种特殊类型的变量,用于存储内存地址。

4.1 定义格式

        定义指针时,需要指定指针所指向的数据类型。指针的定义格式如下:

数据类型 *指针变量名 [=初始地址值];
  • 数据类型:指针所指向的地址处的数据类型,例如 int、char、float 等。
  • 符号 *:用于通知编译器,这里定义的是一个指针变量。* 符号通常放在变量名前面,表示指针指向的是什么类型的值。例如,char * 表示一个指向字符的指针,float * 表示一个指向浮点数的指针。
  • 指针变量名:指针变量的名称,用于在程序中引用该指针。
  • 初始地址值(可选):可以为指针变量提供一个初始地址值,通常是另一个变量的地址。

4.2 三种定义指针的写法

        在 C 语言中,以下三种定义指针的写法都是合法的,它们在功能上是等价的:

int *ptr;
int* ptr;
int * ptr;

        尽管这三种写法都可以正确编译和运行,但为了代码的可读性和一致性,建议选择一种风格并保持统一。常见的做法是将 * 放在变量名前面,如下所示:

int *ptr; // 推荐写法

        这样写法的好处是,当定义多个指针变量时,可以更清晰地表达每个变量的类型:

int *ptr1, *ptr2; // 推荐写法

        如果将 * 符号紧随数据类型,当定义多个指针变量时,可能会引起误解,误以为都是 int* 类型的指针:

int* ptr1, ptr2;

        其实,在这个例子中,ptr1 是一个指向 int 类型的指针,而 ptr2 是一个普通的 int 变量,而不是指针。


5 取址运算符和取值运算符

5.1 取址运算符(&)

  • 符号:&
  • 作用:取址运算符用于获取变量的内存地址
  • 用法:将 & 符号放在变量名前,可以得到该变量的内存地址。例如,&num 返回变量 num 的地址。
  • 格式化输出地址:如果要在 printf 函数中格式化输出地址,需要使用 %p 格式占位符。例如:
printf("num 的地址: %p\n", (void*)&num);

5.2 取值运算符(*)

  • 符号:*
  • 作用:取值运算符用于获取指针所指向的内存地址处的数据值,也称为解引用运算符间接引用运算符
  • 用法:将 * 符号放在指针变量名前,可以访问指针所指向的变量的值。例如,如果 ptr 是一个指向 int 类型的指针,*ptr 就表示 ptr 所指向的 int 变量的值。


6 指针应用案例

6.1 指针的赋值和间接访问

        创建一个 int 类型的变量,使用取址运算符取出其地址,并将其地址赋值给一个指针,然后分别打印变量的值、变量的地址、指针的值、指针的地址、指针指向的值。

#include <stdio.h>

int main()
{
    // 定义一个整型变量 num 并初始化为 100
    int num = 100;

    // 定义一个整型指针 ptr,它将被用来存储变量 num 的地址
    // 使用 & 符号取得 num 的地址,并将这个地址赋值给 ptr
    int *ptr = &num;

    // 打印变量 num 的值和地址
    printf("num 的值是 %d\n", num);
    printf("num 的地址是 %p\n\n", &num); // %p 是用来打印指针(地址)的格式说明符

    // 打印 ptr 的相关信息
    // ptr 的值:即 ptr 指针本身存储的地址值,这里是 num 的地址
    printf("ptr 的值是 %p\n", (void *)ptr); // 强制转换为 void* 以避免平台依赖的警告
    // ptr 的地址:即 ptr 指针变量本身的内存地址
    printf("ptr 的地址是 %p\n", &ptr);
    // ptr 指向的值:即 ptr 指针所指向的内存地址中的值,这里是 num 的值
    printf("ptr 指向的值是 %d\n", *ptr);

    return 0;
}

        输出结果如下所示:

          内存示意图:

6.2 修改指针所指向的值

#include <stdio.h>

int main()
{
    // 创建 double 类型的变量 num 并初始化为 2.88
    double num = 2.88;

    // 创建指针 p1,指向变量 num
    double *p1 = &num; // p1 存储的是 num 的地址

    // 创建指针 p2,将 p1 的值(即 num 的地址)赋值给 p2
    // 此时 p1 和 p2 都指向同一个变量 num
    // 注意:指针指向的数据类型和指针类型最好要匹配,这里都是 double 类型
    double *p2 = p1;

    // 打印 num 的初始值
    printf("num的初始值:%.2f \n", num); // 输出: 2.88

    // 通过指针 p1 修改 num 的值,并打印
    *p1 = 3.88; // 解引用 p1 并将其指向的值修改为 3.88,即修改了 num 的值
    printf("p1指针变量修改num后,num的值:%.2f \n", num); // 输出: 3.88

    // 通过指针 p2 修改 num 的值,并打印
    // 注意:这里使用 += 运算符,先解引用 p2 得到 num 的值,然后加 10
    *p2 += 10;   // 等价于 num += 10
    printf("p2指针变量修改num后,num的值:%.2f \n", num); // 输出: 13.88

    return 0;
}

        输出结果如下所示:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thanks_ks

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值