C指针

指针

指针是一种派生数据类型,它与基本数据类型不一样。它用于存放变量的地址。因此,使用指针数据类型声明的变量,称为指针变量。

语法:
datatype* pointer_variable_name;
指针变量声明

例如:

/* 声明一个指针变量存放整型变量的地址 */
int *i_ptr;
 
/* 声明一个指针变量存放字符变量的地址 */
char *c_ptr;
 
/* 声明一个指针变量存放浮点型变量的地址 */
float *f_ptr;

指针是C语言的一个核心概念,也是比较难理解的概念。下面通过一个例子来分析一下C语言指针是如何工作的。

例如:假设有一个整型变量,变量值为5。同时,将存放5的变量的地址赋值给一个指针变量。代码如下:

int i_var = 5;
int *i_ptr;
i_ptr = &i_var;

在讲解之前,我们首先要知道变量是存放在计算机的内存里的。假设变量i_var的地址是0x10008000;指针变量的地址是0x20001000。那么,在内存中,它们的地址映射关系如下:

指针映射

从上图我们可以看到,以上三个语句分为3步:

  1. i_var声明并初始化值为5,此时内存地址0x10008000处存放的数据就是5。
  2. 声明一个整型指针变量,内存开辟了一个地址空间,地址为0x20001000。
  3. 将变量i_var的地址赋给i_ptr指针变量,因此0x20001000处存放的是变量i_var的地址0x10008000。

指针运算符(*)

指针运算符(*)用于从指针保存的地址中获取值。下面通过一个图来了解如何通过使用指针运算符来获取指针指向地址处的值。

指针运算符

上图使用了指针运算符(*)将地址在0x10008000内的数据5取出。
注意:& 表示取出变量的地址。

指针使用要点

1. 指针的数据类型必须与指向地址存储的变量数据类型一致。

unsigned char ch_var=65;

unsigned int *i_ptr;

unsigned char *ch_ptr;

i_ptr=&ch_var;   /*错误!因为数据类型不一致*/

ch_ptr=&ch_var;  /*正确!因为数据类型一致 */

例如:

#include <stdio.h>

int main()
{
    unsigned int i_var=65;

    unsigned int *i_ptr;

    i_ptr=&i_var;

    printf("i_var地址是:%p\n",i_ptr);

    printf("地址%p处存放的值是:%u\n",i_ptr,i_var);

    return 0;
}

输出结果:
指针的使用1

2. 如果指针的数据类型与变量的数据类型不同,则必须在地址赋值给指针变量之前将变量类型转换为指针变量的数据类型。
例如:

#include <stdio.h>

int main()
{
    unsigned char ch_var=65;

    unsigned int *i_ptr;

    i_ptr=(unsigned int *)&ch_var; /*正确,因为字符变量类型被转换为了unsigned int类型 */

    printf("ch_var的地址是:%p\n",i_ptr);

    printf("地址%p处存放的值是:%u\n",i_ptr,*((unsigned char*)i_ptr));

    return 0;
}

输出结果:
指针的使用2
从上面的示例中科员看到,ch_var是unsigned char类型,而i_ptr属于unsigned int类型。在地址赋值前ch_var数据类型已通过类型转换临时更改成了unsigned int。

(*)符号根据其用途具有不同的含义。上面的例子中:

  1. unsigned int i_ptr,这里* 表示i_ptr是指针变量。
  2. *i_ptr,这里的*表示取出i_ptr指向地址的变量的值。

请记住:

  1. 无论处理器大小如何,char指针都只能以一个字节单位步进。
  2. 如果处理器为32位,则int 指针以4个字节为单位步进。
  3. 如果处理器为32位,则float指针以4个字节为单位步进。
  4. 如果处理器为32位,则double指针以8个字节为单位步进。

void指针

void指针,因为它的数据类型是void. 同时它也被称为通用指针,因为它可以指向任何类型的变量的地址。

语法:

void *vptr; /*vptr是一个void指针*/

例如:

#include <stdio.h>

int main()
{
    unsigned char ch_var=65;

    void *i_ptr;

    i_ptr=(unsigned int *)&ch_var; /*正确,因为字符变量类型被转换为了unsigned int类型 */

    printf("ch_var的地址是:%p\n",i_ptr);

    printf("地址%p处存放的值是:%u\n",i_ptr,*((unsigned char*)i_ptr));

    return 0;
}

输出与结果:
指针的使用2

Null指针

NULL是不指向任何地址的指针,也就是说,它被赋予一个空值。如果未初始化的指针最好附值为NULL,这是一个良好的编程习惯。
例如:

#include <stdio.h>

int main()
{
    unsigned int i_var=65;

    unsigned int *i_ptr=NULL;

    i_ptr=&i_var;

    printf("i_var的地址是:%p\n",i_ptr);

    printf("地址%p处存放的值是:%u\n",i_ptr,*i_ptr);

    return 0;
}

下一节