9. 指针访问内存的高级用法

本节课我们讲解指针访问内存的高级用法,本节的内容在 C 语言中非常常用,但难于理解。为了能让我的朋友们快速理解本节内容,我们先来复习一下我们前面说过的几个概念。

  1. 指针的是一个变量,它的内部保存的是指向变量的内存地址。
  2. 指针解引用 返回的数据是指针指向的变量的引用。
  3. 指针解引用 后能够引用的内存数据范围和指针本身的类型相关。
  4. 指针解引用 后能够引用的数据类型是指针类型去掉一个星号(*)后的类型,如:指针 p 的类型为 char*,则解引用后 *p 的类型为 char

既然 指针解引用 后能够引用的内存数据范围和指针本身的类型相关,那么我们就可以使用这个规则对内存进行重新定义类型,这样可以方便对内存的操作。

下面举例说明

在 IP 协议中,网络层传输的 IPv4 的地址通常用一个无符号型的 32 位整数表示,如要表示 192.168.1.100 的 IP 地址可以用无符号型 int 类型存储。如:

unsigned int ipv4 = (192 << 24) | (168 << 16) | (1 << 8) | (100 << 0);

那么我们如何得到每个字节的呢?我们知道 unsigned char * 类型的指针解引用后每次只能访问一个字节。基于这个思想。我们定义指针如下:

unsigned char * pc = (unsigned char *) &ipv4;

这样我们就使用指针 pc 指向了 变量 ipv4 的起始地址。再通过指针的运算,我们就可以得到每个字节数据了。比如:ipv4 最高字节的数据可以使用 *(pc+3) 获取;ipv4 最高字节的数据可以使用 *pc 获取。

完整示例如下:

// filename: pointer_adv.c
#include <stdio.h>

int main(int argc, char *argv[]) {
    unsigned int ipv4 = (192 << 24) | (168 << 16) | (1 << 8) | (100 << 0);
    unsigned char * pc = (unsigned char *) &ipv4;

    // 以点分隔的方式打印 IPv4 的地址。
    printf("ipv4 address: %d.%d.%d.%d\n", *(pc+3), *(pc+2), *(pc+1), *(pc+0));

    return 0;
}

运行结果如下:

weimingze@mzstudio:~$ gcc -o pointer_adv pointer_adv.c
weimingze@mzstudio:~$ ./pointer_adv
ipv4 address: 192.168.1.100

练习:

已知一个 unsigned short int 类型的变量 s 的值为 0x0102,即十进制的 258。使用指针将 s 的高位字节修改为 0x02,低位字节修改为 0x04,最后打印修改后的值。

#include <stdio.h>

int main(int argc, char *argv[]) {
    unsigned short int s = 0x0102;
    // ... 完成此处的代码。
    printf("s: %#06x\n", s);  // 打印 s: 0x0204
    return 0;
}