指针篇(1)- 什么是指针?


前言

请原谅我又开始挖坑了, 挖坑的原因在于最近把 C 语言基础抛得一干二净, 自以为能做高大上的开发了, 到头来却发现基本的指针用法都忘掉了, 不该不该。 所以就打算整理一下手上的笔记, 重拾一下丢下的指针 。

一个初学 C 语言的人不懂指针; 一个学 C 语言 1 年的人自以为懂指针; 一个学 C 语言 3 年的人会说自己不懂指针; 一个学 C 语言 10 年的人会说指针是 C 语言的灵魂。 指针对于 C 语言的重要作用不言而喻, 但是也有许多人困惑指针到底有什么用。 这不是个一言两语就能解决的问题, 却是个值得去仔细思考和探究的问题。 也只有足够了解 C 语言机制的人才懂得指针的魅力。

指针是什么?

1. 指针的全称是指针变量, 指针的本质就是变量! 但是一般变量(直接使用数据类型+变量名的就是一般变量)存放的是该变量的值, 可以直接访问得到; 而指针存放的是指向变量(常量)的地址, 通过指针对该变量(常量)进行间接访问。

2. 指针具有类型, 其类型和其指向的变量(常量)需要保持一致。指针在使用时需指明类型(void * 型指针在使用时需要强制转换)。

注:关于指针的声明有两种风格: int *p 和 int* p。这两种风格在语法上都正确, 都能通过编译。 但也是一个经常被讨论的问题, 关于为什么会有这两种风格, 会在《C 语言返璞归真: 指针篇番外》中讲述。

通过一个简单的示例程序来说明(建议自己敲代码来了解 C 语言的这些特性):

/*
	GCC 5.4 环境编译
	
*/

#include <stdio.h>

int main(void)
{
	int count = 5;  		  //局部变量的声明和初始化,在使用该局部变量前必须赋初值
	int *p = &count;		 //指针的声明和初始化,建议指针在声明时就给一个明确的指向,或者等于NULL

//	printf("count = %d\n",*count);	 // 编译时会出现error: invalid type argument of `unary *' 
	printf("count = %d\n",count);	 //一般变量的直接访问 
	printf("&count = %p\n",&count);  //一般变量的取地址 
	
	
	printf("&p = %p\n",&p);		   	//指针变量的取地址 
	printf("p = %p\n",p);		   	//指针变量的直接访问 
	printf("*p = %d\n",*p);		   	//指针变量的间接访问 
	
	return 0;
}

输出结果:

count = 5
&count = 0x7ffffd6e84ac
&p = 0x7ffffd6e84b0
p = 0x7ffffd6e84ac
*p = 5

为什么会有这样的输出结果呢?

在讨论输出结果之前, 我们首先来看下面的图:

这是在不同平台下(操作系统和编译器)的数据类型长度, 用红框标记的是比较常见的模型。 ILP32LL 对应的是32位操作系统(指针采用 32 位); LP64 对应的是大部分 64 位的 Linux 操作系统(指针和 long 型均采用 64 位); LLP64 对应的是 64 位 Windows 操作系统(指针采用 64 位, long 型采用 32 位), 但由于 64 位 Windows 中有很多 32 位的编译器(比如 Visual Studio 的 Win32 编译器), 所以很多时候使用的依然是 ILP32LL 模型。 之后我的测试程序都会在 64位 Ubuntu 下编译运行, 所以使用的模型是 LP64。

取值运算符「&」

回到上面的程序和结果, 可以看到一般变量和指针变量都可以直接访问和取地址(使用取址运算符「&」), 这两种变量在声明时系统就会为它们分配一块内存用于存放数据。 从上面的结果就可以看到系统为 count 分配了一块内存,其地址为 0x7fff3e31e3ac , 紧接着为指针 p 分配一块内存, 其地址为 0x7fff3e31e3b0。
注: 系统管理内存的最小单元是 1 byte, 也就是 8 bit。 当我们看到一个地址时, 务必清楚地知道它背后的内存单元大小就是 1 byte。实际上上面 int 类型的 count 的地址范围是 0x7fff3e31e3ac ~ 0x7fff3e31e3af,正好是 4 byte(32 bit)大小, 下一个内存单元开始就是指针的地址了,如果再紧接着定义一个变量, 那么变量的地址就是 0x7ffff3e313b8(指针占了 8 byte 内存空间)。 记住这一点: 系统在描述地址时永远用的都是首地址!!!

指针中存放的东西?

上面我们说明了通过取址运算符(功能就是取地址)「&」可以得到一般变量和指针变量的地址。 不加任何运算符时就可以直接访问得到一般变量和指针变量的内容, 从上面的结果可以看到 count = 5, p = 0x7fff3e31e3ac。 明显发现指针变量 p 中存放的正好是一般变量 count 的内存地址。 代码在声明指针的时候我们作了如下的初始化:
int *p =  &count; 
这句实际上可以也分为两句: int *p = NULL; p = &count; 我们首先声明了一个指针变量 p,「*」是解引用运算符, 不过这里的作用不是解引用, 而是表明后面的变量是指针变量。 使用取址运算符「&」得到一般变量 count 的内存地址, 将其赋值给指针变量 p, 因此 p 中存放的数据就是 count 的内存地址。所以经常会出现一种错误说法说指针就是内存地址。 请注意地址本身是个常量, 是为了方便系统方便管理内存的一个标记。 就好比房间上的门牌号一样, 一个地址对应一块内存空间。 而指针是系统给我们提供的间接访问内存空间的一把钥匙, 这把钥匙能开哪个房间由我们来决定, 因为指针是个变量可以改变其指向。 所以正如不能说钥匙就是门牌一样, 指针也不是地址。

解引用运算符「*」

从上面的描述中我们已经得知指针变量 p 存储的内容是一般变量 count 的内存地址, 但是 count 的值才是我们真正想要的。 所以 C 语言提供了一个特殊的运算符——「*」解引用运算符(也叫取值运算符或者间接运算符)。这是 指针和数组名所独有的,从上面的代码可以看到对一个一般变量进行解引用是没有意义的,在编译时会报错。 解引用运算符用于获取指针所指向的变量值。得到指针所指向的变量值之后, 就可以进行运算, 这些运算将直接作用于变量的值。 这是因为从内存的角度来看, 指针所指向的变量的值在内存中只有一份, 指针并没有对其指向的变量进行拷贝。
指针最基本的使用先说到这, 下一篇依旧写指针, 就说说数组和指针的暧昧。
2017 年 6 月 17 日
Kilento
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值