首页 > 编程笔记 > C语言笔记 阅读:4

C语言指针的定义和使用(附带实例)

指针是 C语言的一个重要组成部分,是 C语言的核心、精髓,用好指针可以让 C语言编程事半功倍。

C语言程序中使用指针,一方面可以提高程序的编译效率和执行速度以及实现动态的存储分配;另一方面,使用指针可使程序更灵活,便于表示各种数据结构,还可编写出高质量的程序。

C语言指针的概念

指针是 C语言显著的特点之一,其使用起来十分方便而且能提高某些程序的效率,不过如果使用不当则很容易造成系统错误。许多程序“挂死”(程序崩溃)往往都是由于错误地使用指针造成的。

1) 地址与指针

系统的内存就好比带有编号的小房间,如果想使用内存就需要得到房间编号。下图定义了一个整型变量 i,i 的内容是数据 0,一个整型变量需要 4 个字节,所以编译器为变量 i 分配的编号为 2000~2003。


图 1 变量在内存中的存储

地址就是内存区中每个字节的编号,图 1 所示的 2000、2001、2002 和 2003 就是地址,下面通过一张图来进一步说明。


图 2 变量存放

图 2 所示的 2000、2004 等就是内存单元的地址,而 0、1 就是内存单元的内容,换种说法就是基本整型变量 i 在内存中的地址从 2000 开始。因为基本整型变量占 4 个字节,所以变量 j 在内存中的起始地址为 2004。变量 i 的内容为 0,变量 j 的内容为 1。

如下图所示,这里仅将指针看作内存中的一个地址(变量 P),多数情况下,这个地址是内存中另一个变量(例如变量 i)的位置。

在程序中定义一个变量,在进行编译时就会给该变量在内存中分配一个地址,通过访问这个地址可以找到所需的变量,这个变量的地址称为该变量的“指针”。

下图所示的地址 2000 是变量 i 的指针:


图 3 指针

2) 变量与指针

变量的地址是变量和指针二者之间连接的纽带,如果一个变量包含另一个变量的地址,则可以理解成第一个变量指向第二个变量。“指向”就是通过地址来体现的。

例如,将变量 i 的地址存放到指针变量 p 中,p 就指向 i,其关系如下图所示。


图 4 地址与指针

可以把 i 看成一间房间,把 p 看成一把钥匙,这把钥匙 p 指向的就是 i 这个房间,而其中的 10 就是房间里的内容。

在程序代码中是通过变量名对内存单元进行存取操作的,代码经过编译后已经将变量名转换为该变量在内存中的存放地址,对变量值的存取都是通过地址进行的。

例如,对图 2 所示的变量 i 和变量 j 进行如下操作:
i+j;
其含义是:根据变量名与地址的对应关系,找到变量 i 的地址 2000,然后从 2000 开始读取 4 个字节的数据并将其放到 CPU 寄存器中,再找到变量 j 的地址 2004,从 2004 开始读取 4 个字节的数据并将其放到 CPU 的另一个寄存器中,通过 CPU 的加法中断计算出结果。

在汇编语言中是直接通过地址来访问内存单元的,在高级语言中一般使用变量名访问内存单元,但 C语言作为高级语言提供了通过地址来访问内存单元的方式。

C语言指针的定义

一个变量的地址称为该变量的指针。如果有一个变量专门用来存放另一个变量的地址,它就是指针变量。

指针变量与变量在内存中的关系如下图所示:


图 5 指针变量与变量在内存中的关系

通过 1000 这个地址能访问地址为 2000 的内存单元,再通过地址是 2000 找到对应的数据,以此类推。

还是以房间和钥匙来比喻,假设你要外出,为了方便就把钥匙放到朋友 A 家,突然你的朋友 B 想要在你家借宿一晚,这时候朋友 B 需要找到朋友 A 家,然后拿着钥匙再去你家。朋友 A 家地址就是 1000,你家地址就是 2000,而钥匙就是指针 p。而你家里的设施就是 1.13 这个数据。

在 C语言中有专门用来存放内存单元地址的变量,即指针变量。下面将针对如何定义一个指针变量、如何为一个指针变量赋值及如何引用指针变量等方面的内容进行介绍。

1) 定义指针变量的一般形式

如果有一个变量专门用来存放另一个变量的地址,则它称为指针变量。图 4 所示的 p 就是一个指针变量。如果一个变量包含指针(指针等同于一个变量的地址),则必须对它进行说明。

定义指针变量的一般形式如下:
类型说明 * 变量名;
其中,“*”表示该变量是一个指针变量,“*”是一个单目运算符;变量名即定义的指针变量名,类型说明表示该指针变量所指向的变量的数据类型。

例如:
int *p;
这句代码定义了一个指针变量 p,其中 int 是类型说明,p 是变量名。

2) 指针变量的赋值

指针变量和普通变量一样,使用之前不仅需要定义,还必须赋予具体的值。未经赋值的指针变量不能使用。

给指针变量所赋的值与给其他变量所赋的值不同,给指针变量赋值只能赋予地址,而不能赋予任何其他数据,否则将引起错误。

C语言中提供了地址运算符“&”来表示变量的地址。其一般形式为:
& 变量名;
运算符“&”是一个返回操作数地址的单目运算符,叫作取地址运算符,例如:
p=&i;
上述代码就是将变量i的内存地址赋给 p,这个地址是该变量在计算机内部的存储位置。

如 &a 表示变量 a 的地址,&b 表示变量 b 的地址。给一个指针变量赋值可以有以下两种方法:
第一种,定义指针变量的同时进行赋值,例如:
int a;
int *p=&a;

第二种,先定义指针变量再赋值,例如:
int a;
int *p;
p=&a;

注意,在定义完指针变量再赋值时注意不要加“*”。


初学者使用指针常见的一个错误,就把一个数值赋给指针变量,错误示例如下:
int *p;
p=1002;

C语言指针变量的引用

引用指针变量是对变量进行间接访问的一种形式。对指针变量进行引用的形式如下:
*指针变量
其含义是引用指针变量所指向的值。例如:
#define _CRT_SECURE_NO_WARNINGS /* 解除 vs 安全性检测问题 */
#include<stdio.h> /* 包含头文件 */
void main()
{
    int n = 100; /* 定义整型变量 */
    int *p = &n; /* 定义指针变量 */

    printf("the result1 is: %d\n", *p); /* 引用指针变量,输出 p 所指内容的值*/
}

C语言指针自增自减运算

指针的自增自减运算不同于普通变量的自增自减运算,也就是说其并非简单地加 1 或减 1,这里通过下面的实例进行具体分析。

定义一个指针变量,使这个变量进行自增运算,利用printf()函数将地址输出。

具体代码如下:
#define _CRT_SECURE_NO_WARNINGS /* 解除 vs 安全性检测问题 */
#include<stdio.h> /* 包含头文件 */
int main()
{
    int i; /* 定义整型变量 */
    int *p; /* 定义指针变量 */
    printf("please input the number:\n"); /* 提示信息 */
    scanf("%d", &i); /* 输入数据 */
    p = &i; /* 将变量 i 的地址赋给指针变量 */
    printf("the result1 is: %d\n", p); /* 输出 p 的地址 */
    p = p + 1; /* 地址加 1,这里的 1 并不代表一个字节 */
    printf("the result2 is: %d\n", p); /* 输出 p++ 后的地址 */
}
程序运行结果为:

please input the number:
36
the result1 is: 6487572
the result2 is: 6487576


修改上面的实例,具体代码如下:
#define _CRT_SECURE_NO_WARNINGS /* 解除 vs 安全性检测问题 */
#include<stdio.h> /* 包含头文件 */
int main()
{
    short i; /* 定义整型变量 */
    short *p; /* 定义指针变量 */
    printf("please input the number:\n"); /* 提示信息 */
    scanf("%hu", &i); /* 输入数据 */
    p = &i; /* 将变量 i 的地址赋给指针变量 */
    printf("the result1 is: %hu\n", p); /* 输出 p 的地址 */
    p = p + 1; /* 地址加 1,这里的 1 并不代表一个字节 */
    printf("the result2 is: %hu\n", p); /* 输出 p++ 后的地址 */
}
程序运行结果为:

please input the number:
36
the result1 is: 65046
the result2 is: 65048

短整型变量 i 在内存中占 4 个字节,指针 *p 是指向变量 i 的地址的,这里的 p++ 不是简单地在地址上加 1,而是指向下一个存放短整型数的地址。

指针都按照它所指向的数据类型的直接长度进行增或减的操作。可以用下图来形象地表示:


图 6 指向整型变量的指针

相关文章