Linux C : 指针

发布于:2025-07-28 ⋅ 阅读:(11) ⋅ 点赞:(0)

本篇文章向大家介绍了C语言中最为重要也较难理解的一部分——指针,主要记录了关于指针的一些基本概念和注意事项,只有前面简单的知识理解透彻了才更方便于后续难知识点的学习,指针后续部分我也会在后面的时间里补充记录上。

一、指针的特点

  1. 代码优化:让代码更加简洁高效,减少冗余操作,提升程序运行效率
  2. 内存访问:提供直接访问内存的操作能力,可直接对内存中的数据进行读写等操作
  3. 硬件交互:利用指针可以直接操作硬件设备,实现对底层硬件的控制,这在嵌入式开发等场景中非常重要

二、指针的基础概念

  1. 地址:内存中不同字节的唯一编号,就像每个房间的门牌号一样,用于区分不同的内存空间。在 64 位系统中,其寻址范围为0 - 2^64 
  2. 指针与地址的关系:指针本质上就是地址,地址即指针;但指针比地址多了 “指向” 的逻辑概念,它明确了所指向数据的类型,这使得指针在操作时能正确地解析内存中的数据
  3. 指针变量:专门用于存放指针(地址)的变量。在 64 位操作系统中,所有指针变量的大小均为 8 个字节无论它指向的数据类型是整数、字符还是浮点数等

三、指针相关运算符

1. 取地址运算符(&)

  • 功能:获取变量在内存中的首地址,通过这个地址就能找到变量在内存中的位置。
  • 使用限制:仅能对变量(左值)进行操作,常量和表达式不能使用 & 运算符,因为常量和表达式没有固定的内存地址7。
  • 表达式值:变量在内存中所占空间的首地址。  eg:  对于int Num = 0 ; 中,  &Num得到的就是 Num 在内存中 4 字节空间的首地址8。
  • 表达式类型:是变量类型升级后的指针类型。    eg:  int num; ,  &num的类型就从 int 升级为 int *型

2. 解引用运算符(*)(*运算符)

  • 功能:获取指针指向的内存空间,或者该空间中存储的值,通过它可以间接操作指针所指向的变量
  • 使用限制:* 运算符连接的内容必须为指针类型,不能是普通变量类型,否则会导致编译错误
  • 表达式值:若直接使用 * 对应的表达式,其值为该指针指向空间中的值。eg:  *&Num就可以获得 & Num 指向的空间中 int 类型的值
  • 表达式类型:是指针类型降级后的类型。eg:   int *p ;   ,  *p的类型就从 int * 型降级为 int型
  • 左值特性:当 * 对应的表达式作为左值时,表示将等号右边的值放入指针指向的空间。        eg:   int *p = 5 ;  就是把 5 存入 p 所指向的内存空间中

四、指针变量的定义与注意事项

1. 定义方法

  • 基本格式存储类型 数据类型 *变量名;
  • eg:
    int *p;         // 定义int型指针变量p
    char *str;      // 定义char型指针变量str
    float *f_ptr;   // 定义float型指针变量f_ptr
    int *p1, *p2;   // 同时定义多个int型指针变量(每个变量前都需加*)
    ```
    

2. 注意要点

  • 禁止使用未初始化指针:未经初始化的指针可能指向内存中的任意位置,对其进行操作可能会修改重要数据,导致程序崩溃等不可预知的错误,所以指针变量定义后必须初始化
  • 野指针:指未经初始化的指针,或者曾经指向有效空间但该空间已被释放(回收)后仍指向该地址的指针。野指针会导致程序运行时出现不可预期的错误,是程序安全的重大隐患,在编程中需严格避免
  • 空指针:指向内存地址0x0的指针,用NULL表示
    • 内存地址0x0为只读空间,不能对空指针执行赋值操作,比如*p = 10;如果 p 是 NULL 指针,该操作会导致程序错误
    • 用途:常用于指针的初始化,如int *p = NULL;,表示指针当前暂未指向任何有效空间,这样可以避免野指针的出现

指针初始化的必要性:定义指针变量后必须及时初始化,要么让它指向一个有效的变量地址,要么将其初始化为 NULL。如果不初始化,指针就会成为野指针,可能会破坏内存中的数据或者导致程序崩溃。

指针类型的重要性:指针的类型不仅决定了指针变量本身的类型,更重要的是决定了解引用时访问的字节数算数运算的偏移量。比如int *指针解引用时会访问 4 字节内存,double *指针解引用时会访问 8 字节内存,这使得指针能正确解析对应类型的数据。

空指针的判断:在使用指针进行操作之前,通常需要先判断指针是否为 NULL,避免对空指针进行解引用等操作。

eg:

int *p = NULL;  
if (p != NULL) {  // 先判断指针是否有效再操作  
    *p = 10;  
}  

五、指针的访问形式

变量有两种访问内存空间的方式:

直接访问:通过变量名直接访问其内存空间。例如在int num = 10;中,我们通过num就可以直接访问到它所存储的 10 这个值

间接访问:通过指针变量存储的地址访问变量空间。

eg:

int num = 10;  
int *p = #  // p存储num的地址  
*p;  // 通过*p间接访问num的空间,获取值10  
```

六、指针的算数运算

1. 运算特性

指针的算数运算(如++--+n-n)的偏移量由指针指向的数据类型决定,偏移大小等于指针所指向数据类型的字节数乘以运算数。例如:

  • char *类型的指针,每个元素占 1 字节,所以p++会使指针向后偏移 1 字节
  • int *类型的指针,每个元素占 4 字节,所以p++会使指针向后偏移 4 字节
  • double *类型的指针,每个元素占 8 字节,所以p+2会使指针向后偏移 16 字节(8×2)

2. 指针相减

两个同类型指针相减的结果为这两个指针之间相差的数据类型元素个数(而非字节数)

eg:

int arr[5] = {1,2,3,4,5};  
int *p1 = &arr[0], *p2 = &arr[3];  
int diff = p2 - p1;  // diff结果为3,表示两个指针之间相差3个int元素  

这是因为指针相减的结果是通过两个地址之间的字节数除以指针所指向类型的字节数得到的,在此例中,p2 和 p1 地址相差 12 字节(3×4),除以 int 类型的 4 字节,得到 3

指针运算的限制:指针不能进行乘法、除法运算,也不能与非 0 整数进行加法以外的运算,这些运算没有实际的意义,还会导致编译错误或者逻辑错误,在编写程序的过程中要避免此类操作


网站公告

今日签到

点亮在社区的每一天
去签到