概述

  • 内存地址
    • 在计算机内存中,每个存储单元都有一个唯一的地址(内存编号)。
      • 通俗理解,内存就是房间,地址就是门牌号

image.png

  • 指针和指针变量
    • 指针(Pointer)是一种特殊的变量类型,它用于存储内存地址。
      • 指针的实质就是内存“地址”
    • 指针变量就是存储这个地址的变量。

image.pngimage.png

  • 指针作用
    • 可间接修改变量的值

指针变量的定义和使用

  • 指针也是一种数据类型,指针变量也是一种变量
  • 指针变量指向谁,就把谁的地址赋值给指针变量
  • 语法格式:

    1. 类型 变量;
    2. 类型 * 指针变量 = &变量;
    • & 叫取地址,返回操作数的内存地址
      • 叫解引用,指操作指针所指向的变量的值
    • 在定义变量时,* 号表示所声明的变量为指针类型
      • 指针变量要保存某个变量的地址,指针变量的类型比这个变量的类型多一个*
    • 在指针使用时,* 号表示操作指针所指向的内存空间

示例代码:

  1. #include <stdio.h>
  2. int main() {
  3. // 定义一个int类型的变量,同时赋值为10
  4. int a = 10;
  5. // 打印变量的地址
  6. printf("&a = %p\n", &a);
  7. // 定义一个指针变量,int *保存int的地址
  8. // int *代表是一种数据类型,int *指针类型,p才是变量名
  9. int* p;
  10. // 指针指向谁,就把谁的地址赋值给这个指针变量
  11. p = &a;
  12. // 打印p, *p, p指向了a的地址,*p就是a的值
  13. printf("p = %p, *p = %d\n", p, *p);
  14. return 0;
  15. }

image.png

通过指针间接修改变量的值

  • 指针变量指向谁,就把谁的地址赋值给指针变量
  • 通过 *指针变量 间接修改变量的值 ```c

    include

int main() { // 定义一个int类型变量a,同时赋值为0 int a = 0; // 定义int 指针变量,同时赋值a的地址 int p = &a; // 通过指针间接修改a的值 p = 123; printf(“a = %d\n”, a); // 定义一个int类型变量b,同时赋值为5 int b = 5; // p 保存 b的地址 p = &b; // 通过指针间接修改b的值 p = 250; printf(“b = %d\n”, b);

  1. return 0;

}

  1. <a name="e7ZEy"></a>
  2. # const修饰的指针变量
  3. - 语法格式
  4. ```c
  5. int a = 1;
  6. const int *p1 = &a; // 等价于 int const *p1 = &a;
  7. int * const p2 = &a;
  8. const int * const p3 = &a;
  • 从左往右看,跳过类型,看修饰哪个字符
    • 如果是*, 说明指针指向的内存不能改变
    • 如果是指针变量,说明指针的指向不能改变,指针的值不能修改 ```c

      include

int main() { int a = 1; int b = 2; // p1 可以改,p1不能改 const int p1 = &a; // 等价于 int const p1 = &a; // p1 = &b; // ok // p1 = 555; // err

  1. // p2 不能修改,*p2可以修改
  2. int *const p2 = &a;
  3. // p2 = &b; //err
  4. // *p2 = 555; // ok
  5. // p3 和 *p 都不能改
  6. const int *const p3 = &a;
  7. // p3 = &b; // err
  8. // *p3 = 555; // err
  9. return 0;

}

  1. <a name="PVz7T"></a>
  2. # 指针大小
  3. - 使用sizeof()测量指针的大小,得到的总是:4或8
  4. - sizeof()测的是指针变量指向存储地址的大小
  5. - 在32位平台,所有的指针(地址)都是32位(4字节)
  6. - 在64位平台,所有的指针(地址)都是64位(8字节)
  7. ```c
  8. #include <stdio.h>
  9. int main() {
  10. int *p1;
  11. int **p2;
  12. char *p3;
  13. char **p4;
  14. printf("sizeof(p1) = %llu\n", sizeof(p1));
  15. printf("sizeof(p2) = %llu\n", sizeof(p2));
  16. printf("sizeof(p3) = %llu\n", sizeof(p3));
  17. printf("sizeof(p4) = %llu\n", sizeof(p4));
  18. printf("sizeof(double *) = %llu\n", sizeof(double *));
  19. return 0;
  20. }

指针步长

  • 指针步长指的是通过指针进行递增或递减操作时,指针所指向的内存地址相对于当前地址的偏移量。
  • 指针的步长取决于所指向的数据类型。
    • 指针加n等于指针地址加上 n 个 sizeof(type) 的长度
    • 指针减n等于指针地址减去 n 个 sizeof(type) 的长度
  1. #include <stdio.h>
  2. int main() {
  3. char ch;
  4. char *p1 = &ch;
  5. printf("p1:%p, p1+1: %p\n", p1, p1 + 1); // 步长为1字节
  6. int a;
  7. int *p2 = &a;
  8. printf("p2:%p, p2+1: %p\n", p2, p2 + 1); // 步长为4字节
  9. double d;
  10. double *p3 = &d;
  11. printf("p3:%p, p3+1: %p\n", p3, p3 + 1); // 步长为8字节
  12. return 0;
  13. }

野指针和空指针

  • 指针变量也是变量,是变量就可以任意赋值
  • 任意数值赋值给指针变量没有意义,因为这样的指针就成了野指针
    • 此指针指向的区域是未知(操作系统不允许操作此指针指向的内存区域)
  • 野指针不会直接引发错误,操作野指针指向的内存区域才会出问题
  • 为了标志某个指针变量没有任何指向,可赋值为NULL
    • NULL是一个值为0的宏常量 ```c

      include

int main() { int p; p = 0x12345678; // 给指针变量p赋值,p为野指针, ok,不会有问题,但没有意义 // p = 1000; // 操作野指针指向未知区域,内存出问题,err printf(“111111111111111111\n”);

  1. int *q = NULL; // 空指针
  2. return 0;

}

  1. <a name="OzYl8"></a>
  2. # 多级指针
  3. - C语言允许有多级指针存在,在实际的程序中一级指针最常用,其次是二级指针。
  4. - 二级指针就是指向一个一级指针变量地址的指针。
  5. ```c
  6. #include <stdio.h>
  7. int main() {
  8. int a = 100;
  9. // 一级指针
  10. int* p1 = &a;
  11. printf("&a=%p\n", &a);
  12. printf("p1=%p\n", p1);
  13. printf("&p1=%p\n", &p1);
  14. // 二级指针,可以存储一级指针变量的地址
  15. int** p2 = &p1;
  16. printf("p2=%p\n", p2);
  17. printf("&p2=%p\n", &p2);
  18. // 三级指针,可以存储二级指针变量的地址
  19. int*** p3 = &p2;
  20. printf("p3=%p\n", p3);
  21. printf("&p3=%p\n", &p3);
  22. printf("---------------------\n");
  23. // 通过一级指针访问100,打印出来
  24. printf("*p1=%d\n", *p1);
  25. // 通过二级指针访问100,打印出来
  26. printf("**p2=%d\n", **p2);
  27. // 通过三级指针访问100,打印出来
  28. printf("***p3=%d\n", ***p3);
  29. return 0;
  30. }