与其他高级编程语言相比,C 语言可以更高效地对计算机硬件进行操作,而计算机硬件的操作指令,在很大程度上依赖于地址。

指针提供了对地址操作的一种方法,因此,使用指针可使得 C 语言能够更高效地实现对计算机底层硬件的操作。另外,通过指针可以更便捷地操作数组。在一定意义上可以说,指针是 C 语言的精髓。

内存与地址

在计算机中,数据是存放在内存单元中的,一般把内存中的一个字节称为一个内存单元。为了更方便地访问这些内存单元,可预先给内存中的所有内存单元进行地址编号,根据地址编号,可准确找到其对应的内存单元。由于每一个地址编号均对应一个内存单元,因此可以形象地说一个地址编号就指向一个内存单元。C 语言中把地址形象地称作指针。

C语言中的每个变量均对应内存中的一块内存空间,而内存中每个内存单元均是有地址编号的。在 C 语言中,可以使用运算符 & 求某个变量的地址。

例如,在如下代码中,定义了字符型变量 c 和整型变量 a,并分别赋初值 'A' 和 100。

#include

int main(void)

{

char c='A';

int a=100;

printf("a=%d\n",a);//输出变量a的值

printf("&a=%x\n",&a);//输出变量a的地址

printf("c=%c\n",c);

printf("&c=%x\n",&c);

return 0;

}

程序某次的运行结果为:

a=100

&a=12ff40

c=A

&c=12ff44

分析:

在 C 语言中,字符型变量占一个字节的内存空间,而整型变量所占字节数与系统有关。例如,在 32 位系统中,VC++6.0 开发环境中,int 型占 4 个字节。假设程序在某次运行时,变量 a 和 c 在内存中的分配情况如图 1 所示:内存单元(每个字节)的地址编号分别为十六进制表示的 ...12ff40、12ff41、12ff42、12ff43、12ff44...,每个地址编号均为对应字节单元的起始地址。

图 1 变量的值及内存地址

由图 1 可知,变量 a 对应于从地址 12ff40 开始的 4 个字节(12ff40、12ff41、12ff42、12ff43)的内存空间,存储的是整数 100 的 32 位二进制形式(为直观表示,本例并没有转换成二进制形式)。字符型变量 c,对应地址为 12ff44,该地址内存储的是字母对应 ASCII 值的 8 位二进制形式。

语句 printf("a=%d\n",a); 输出:a=100。

语句 printf("&a=%x\n",&a); 是按十六进制形式输出变量 a 的地址(a 在内存中的起始地址值)为 &a=12ff40。

在上例中,变量 a 和 c 的起始地址 12ff40 和 12ff44 均为指针,分别指向变量 a 和变量 c。

区分变量的地址值和变量的值。如上例中,变量 a 的地址值(指针值)为12ff40,而变量 a 的值为 100。

指针变量的定义

可以保存地址值(指针)的变量称为指针变量,因为指针变量中保存的是地址值,故可以把指针变量形象地比喻成地址箱。

指针变量的定义形式如下。

类型 * 变量名;

例如:

int *pa;

定义了一个整型指针变量 pa,该指针变量只能指向基类型为 int 的整型变量,即只能保存整型变量的地址。

说明:

1) *号标识该变量为指针类型,当定义多个指针变量时,在每个指针变量名前面均需要加一个 *,不能省略,否则为非指针变量。例如:

int *pa,*pb;

表示定义了两个指针变量 pa、pb。而:

int *pa,pb;

则仅有 pa 是指针变量,而 pb 是整型变量。

int *pi,a,b; //等价于inta,b,*pi;

表示定义了一个整型指针变量 pi 和两个整型变量 a 和 b。

2) 在使用已定义好的指针变量时,在变量名前面不能加 *。例如:

int *p,a;

*p=&a; //错误,指针变量是p而不是*p

而如下语句是正确的。

int a,*p=&a; //正确

该语句貌似把 &a 赋给了 *p,而实际上 p 前的 * 仅是定义指针变量 p 的标识,仍然是把 &a 赋给了 p,故是正确的赋值语句。

3) 类型为该指针变量所指向的基类型,可以为 int、char、float 等基本数据类型,也可以为自定义数据类型。

该指针变量中只能保存该基类型变量的地址。

假设有如下变量定义语句:

int a,b,*pa,*pb;

char *pc,c;

则:

pa=&a;//正确。pa基类型为int,a为int型变量,类型一致

pb=&c;//错误。pb基类型为int,c为char型变量,类型不一致

pc=&c;//正确。pc基类型为char,c为char型变量,类型一致

*pa=&a;//错误。指针变量是pa而非*pa

4) 变量名是一合法标识符,为与普通变量相区分,一般指针变量名以字母 p(pointer)开头,如 pa、pb 等。

5) 由于是变量,故指针变量的值可以改变,也即可以改变指针变量的指向。

char c1,*pc,c2;//定义了字符变量c1、c2和字符指针变量pc

则如下对指针变量的赋值语句均是正确的。

pc=&c1; //pc指向c1

pc=&c2; //pc不再指向c1,而指向c2

6) 同类型的指针变量可以相互赋值。

int a,*p1,*p2,b;//定义了两个整型变量a,b;两个整型指针变量为p1,p2

float *pf;

以下赋值语句均是正确的。

p1=&a; //地址箱p1中保存a的地址,即p1指向a

p2=p1; //p2也指向a,即p1和p2均指向a

上述最后一条赋值语句相当于把地址箱 p1 中的值赋给地址箱 p2,即 p2 中也保存 a 的地址,即和 p1 —样,p2 也指向变量 a。

以下赋值语句均是错误的。

pf=p1; //错误。p1,pf虽然都是指针变量,但类型不同,不能赋值

pf=&b; //错误。指针变量pf的基类型为float,b类型为int,不相同

由于指针变量是专门保存地址值(指针)的变量,故本节把指针变量形象地看成“地址箱”。

设有如下定义语句:

int a=3,*pa=&a; //pa保存变量a的地址,即指向a

char c='d',*pc=&c; //pc保存变量c的地址,即指向c

把整型变量 a 的地址赋给地址箱 pa,即 pa 指向变量 a,同理 pc 指向变量 c,如图 2 所示。

图 2 指针指向变量

指针变量的引用

访问内存空间,一般分为直接访问和间接访问。

如果知道内存空间的名字,可通过名字访问该空间,称为直接访问。由于变量即代表有名字的内存单元,故通。过变量名操作变量,也就是通过名字直接访问该变量对应的内存单元。

如果知道内存空间的地址,也可以通过该地址间接访问该空间。对内存空间的访问操作一般指的是存、取操作,即向内存空间中存入数据和从内存空间中读取数据。

在 C 语言中,可以使用间接访问符(取内容访问符)*来访问指针所指向的空间。

例如:

int *p,a=3;//p中保存变量a对应内存单元的地址

p=&a;

在该地址 p 前面加上间接访问符 *,即代表该地址对应的内存单元。而变量 a 也对应该内存单元,故 *p 就相当于 a。

printf("a=%d\n",a); //通过名字,直接访问变量a空间(读取)

printf("a=%d\n",*p); //通过地址,间接访问变量a空间(读取)

*p=6;//等价于a=6;间接访问a对应空间(存)

“野”指针

本节中,把没有合法指向的指针称为“野”指针。因为“野”指针随机指向一块空间,该空间中存储的可能是其他程序的数据甚至是系统数据,故不能对“野”指针所指向的空间进行存取操作,否则轻者会引起程序崩溃,严重的可能导致整个系统崩溃。

例如:

int *pi,a; //pi未初始化,无合法指向,为“野”指针

*pi=3; //运行时错误!不能对”野”指针指向的空间做存入操作。该语句试图把 3 存入“野”指针pi所指的随机空间中,会产生运行时错误。

a=*pi; //运行时错误!不能对”野”指针指向的空间取操作。该语句试图从“野”指针pi所指的空间中取出数据,然后赋给变量a同样会产生运行时错误。

正确的使用方法:

pi=&a;//让pi有合法的指向,pi指向a变量对应的空间

*pi=3;//把3间接存入pi所指向的变量a对应的空间

指针与数组

数组是一系列相同类型变量的集合,不管是一维数组还是多维数组其存储结构都是顺序存储形式,即数组中的元素是按一定顺序依次存放在内存中的一块连续的内存空间中(地址连续)。

指针变量类似于一个地址箱,让其初始化为某个数组元素的地址,以该地址值为基准,通过向前或向后改变地址箱中的地址值,即可让该指针变量指向不同的数组元素,从而达到通过指针变量便可以方便地访问数组中各元素的目的。

一维教组和指针

在 C 语言中,指针变量加 1 表示跳过该指针变量对应的基类型所占字节数大小的空间。指向数组元素的指针,其基类型为数组元素类型,指针加 1 表示跳过一个数组元素空间,指向下一个数组元素。

例如:

int *p,a[10];

p=a; //相当于 p=&a[0];

说明:数组名 a 相当于数组首元素 a[0] 的地址,即 a 等价于 &a[0]。

上述语句定义了整型指针变量 p 和整型数组 a,并使 p 初始指向数组首元素 a[0]。 当指针变量和数组元素建立联系后,可通过以下三种方式访问数组元素。

1)直接访问:数组名[下标]; 的形式。如 a[3]。

2) 间接访问:*(数组名+i); 的形式。其中,i 为整数,其范围为:0

如果指针变量 p 被初始化为 a 之后,不再改变,那么也可以使用 *(p + i) 的形式访问 a[i],不过这样就失去了使用指针变量访问数组元素的意义。

3)间接访问:*(指针变量);的形式。当执行语句 p=a; 后,可以通过改变 p 自身的值(可通过自增、自减运算),从而使得 p 中保存不同的数组元素的地址,进而通过 *p 访问该数组中不同的元素。这是使用指针访问数组元素较常用的形式。例如,如下代码通过使用指针变量的移动来遍历输出数组中的每个元素。

for (p=a;p

printf ("%d\t",*p);

确定 p 指针移动的起止地址,即循环控制表达式的确定是使用指针访问数组元素的关键。

p 初始指向 a[0],即 p=&a[0]; 或 p=a;。

p 终止指向 a[N-1],即 p=&a[N-l]; 或 p=a+N-1;。

故可得 p 的移动范围为:p>=a && p<=a+N-1;,而 p<=a+N-1 通常写成 p

c语言引入指针的目的,指针,C语言指针完全攻略相关推荐

  1. Python语言学习:python语言的特点、入门、基础用法之详细攻略

    Python语言学习:python语言的特点.入门.基础用法之详细攻略 相关内容 Python 基础教程 目录 python语言的特点 python语言的入门 python语言的基础用法 python ...

  2. 信息学奥林匹克c语言提高组,CSP信息学奥赛提高组一级全攻略,你值得拥有!...

    12月15日,中国计算机学会CCF的软件能力职业考试--CSP的本年度第三次认证顺利结束.这是一个面向全国计算机相关专业大学毕业生的软件能力的考试,该项认证每年大约3.9.12月各举办一次,自2014 ...

  3. 赛尔号对战c语言程序,秘密军事会议 赛尔号9月10日攻略

    赛尔号9月10日攻略:赛尔号战术预演!赛尔号战术预演怎么做?赛尔号秘密军事会议 "各位,相信大家已经看到了敌军的大致路线图!现在他们主要分为3个势力,艾里逊小队主要掌控左边的巡洋舰,佐格小队 ...

  4. 红心大战c语言程序设计,Win 7系统安全优化、瘦身攻略(2)

    以下 这些删不删看你了 C:/Program Files/Microsoft Games/Chess 象棋高手(30.3M) C:/Program Files/Microsoft Games/Free ...

  5. 为什么指针是个糟糕的语言特性

    1 什么是指针 本文所谓的指针(pointer) ,是指C和C++等语言中的内建的语言特性. 在不同范畴中指针这个概念有所不同.在体系结构规范中,指针指称特定的整数字节地址或者两个地址的差(地址偏移量 ...

  6. c语言如何将值赋给结构体指针,C语言给结构体指针赋值

    <C语言给结构体指针赋值>由会员分享,可在线阅读,更多相关<C语言给结构体指针赋值(6页珍藏版)>请在人人文库网上搜索. 1.指向结构体的指针 在C语言中几乎可以创建指向任何类 ...

  7. char类型怎么输入 c语言_还没搞懂C语言指针?这里有最详细的纯干货讲解(附代码)...

    21ic综合自网络信息 指针对于C来说太重要.然而,想要全面理解指针,除了要对C语言有熟练的掌握外,还要有计算机硬件以及操作系统等方方面面的基本知识.所以本文尽可能的通过一篇文章完全讲解指针. 为什么 ...

  8. 【C 语言】指针 与 数组 ( 指针 | 数组 | 指针运算 | 数组访问方式 | 字符串 | 指针数组 | 数组指针 | 多维数组 | 多维指针 | 数组参数 | 函数指针 | 复杂指针解读)

    相关文章链接 : 1.[嵌入式开发]C语言 指针数组 多维数组 2.[嵌入式开发]C语言 命令行参数 函数指针 gdb调试 3.[嵌入式开发]C语言 结构体相关 的 函数 指针 数组 4.[嵌入式开发 ...

  9. c语言指针实验报告总结,c语言指针实验报告

    c语言指针实验报告 C语言实习报告 题目:指针及其应用 系别: 专业: 姓名: 学号: 日期: 一 实验名称:指针及其应用 二 实验目的: (1) 掌握变量的指针及其基本用法. (2) 掌握一维数组的 ...

最新文章

  1. 黑客是如何发现女朋友出轨的,痛心的经历!
  2. Spring的@ImportResource注解
  3. 【MariaDB】MariaDB编译参数
  4. Flex4_操作XML
  5. Atitit.c# .net 3.5 4.0 4.5 5.0 6.0各个版本新特性战略规划总结
  6. 【深入浅出通信原理-学习笔记】信道
  7. nachos操作系统初步认识
  8. Java注解@PostConstruct使用及相关原理分析
  9. Mac打包生成加密dmg
  10. tftpd获取文件失败
  11. 单片机管脚工作状态的解释
  12. pwnable-mistake
  13. flutter doctor --android-licenses命令之后出现JAVA_HOME错误
  14. usermod -a -G group user修改user用户信息,把user添加到组group中
  15. 豆瓣 API ( 解决104问题 )
  16. BHQ-1 amine,1308657-79-5,BHQ染料通过FRET和静态猝灭的组合工作
  17. mysql冷热分离的技术_冷热数据分离思路
  18. 长期换衣行人重识别(Long-Term Clothes-Changing Person Reid)数据集汇总
  19. 老虎证券开放api期货合约建立
  20. formdata格式传参

热门文章

  1. Word中 mytype公式编辑器编辑的公式与文字不对齐,偏上的问题
  2. LayUI使用Echarts实现统计图
  3. Object Removal by Exemplar-Based Inpainting 概括(附源码)
  4. iOS VIPER 架构解读
  5. 关于win10应用商店打不开,win10应用商店明明连接网络确提示无网络连接,代码: 0x80131500
  6. 智慧街道智慧社区一体化综合管理平台Java商业源码
  7. 慎独的修炼之道--群处守嘴 独处守心 修以清心为主 涉世及慎言为先
  8. RabbitMQ安装流程
  9. iTab新标签页,一款个性化的浏览器起始页插件
  10. 鸿蒙os后台运行,Day10 鸿蒙,Ability全家桶(二)如何后台运行任务