·38· C程序设计要点分析与题解 第5章指针 5.1指针和地址 指针是C语言中一个极其重要的概念,也是C语言程序设计的难点。 L,指针的定义 债地指针变男是用于存放头他变接的地丝简玫为指针指针变所金的是内存约抗丽 个变量在内存中存储的位置。指针它本身也是一种变量,和其他变量一样。 要占有一定数量的存储空间,用来存放指针值(即地址)。 2.指针的作用 C语言中引入指针类型变量,不仅简单地实现了类似于机器间址操作的指令,更重要的 是使用指针可以实现程序设计中利用其他数据类型很难实现,甚至无法实现的工作。指针的 作用主要体现 (1)使代码更为紧凑和有效,提高了程序的效率。 (②)便于函数修改其调用参数,为函数间各类数据传递提供简捷而便利的方法。 (3)实现动态分配存储空间。 正确地使用指针会带来许多好处,但指针操作也有难以掌握的一面,若使用不当,可能 会产生程序失控甚至造成系统崩遗 5.2指针变量和指针运算符 1.指针变量及其说明 指针变量是存放地址的变量。和其他变量一样,必须在使用之前,加以定义说明。其定 义说明的一般形式 类型说明符 *指针变量名: 例如: int *P: 说明指针变量P是指向int类型变量的指针 char米s 说明指针变s是指向char类型变量的指针 float *f 说明指针变量f是指向f1oat类型变量的指针 Double *d: 说明指针变量d是指向double类型变量的指针。 static int pa:说明指针变量pa是指向int类型变量的指针,而pa本身的存储 类型是静态变量。 int *fpi: 说明fDi(0是一个函数,该函数返回指向int类型变量的指针。 Int (*pfi)() 说明p1是指向一个函数的指针 ,该函数返回int类型变量。 指针变量值表达的是某个数据对象的地址,只允许取正的整数值。然而,不能因此将它 与整数类型变量相混淆。所有合法指针变量应当是非0值。如果某指针变量取0值,即为L, 则表示该指针变量所指向的对象不存在。这是NULL在C语言中又一特殊用处。 2.指针运算符&和*
·38· C 程序设计要点分析与题解 第 5 章 指针 5.1 指针和地址 指针是 C 语言中一个极其重要的概念,也是 C 语言程序设计的难点。 1.指针的定义 指针变量是用于存放其他变量的地址,简称为指针。指针变量所包含的是内存地址,而 该地址便是另一个变量在内存中存储的位置。指针它本身也是一种变量,和其他变量一样, 要占有一定数量的存储空间,用来存放指针值(即地址)。 2.指针的作用 C 语言中引入指针类型变量,不仅简单地实现了类似于机器间址操作的指令,更重要的 是使用指针可以实现程序设计中利用其他数据类型很难实现,甚至无法实现的工作。指针的 作用主要体现如下: (1)使代码更为紧凑和有效,提高了程序的效率。 (2)便于函数修改其调用参数,为函数间各类数据传递提供简捷而便利的方法。 (3)实现动态分配存储空间。 正确地使用指针会带来许多好处,但指针操作也有难以掌握的一面,若使用不当,可能 会产生程序失控甚至造成系统崩溃。 5.2 指针变量和指针运算符 1.指针变量及其说明 指针变量是存放地址的变量。和其他变量一样,必须在使用之前,加以定义说明。其定 义说明的一般形式: 类型说明符 *指针变量名; 例如: int *P; 说明指针变量 P 是指向 int 类型变量的指针. char *s; 说明指针变量 s 是指向 char 类型变量的指针。 float *f; 说明指针变量 f 是指向 float 类型变量的指针。 Double *d; 说明指针变量 d 是指向 double 类型变量的指针。 static int pa; 说明指针变量 pa 是指向 int 类型变量的指针,而 pa 本身的存储 类型是静态变量。 int *fpi(); 说明 fpi()是一个函数,该函数返回指向 int 类型变量的指针。 Int (*pfi)(); 说明 pfi 是指向一个函数的指针,该函数返回 int 类型变量。 指针变量值表达的是某个数据对象的地址,只允许取正的整数值。然而,不能因此将它 与整数类型变量相混淆。所有合法指针变量应当是非 0 值。如果某指针变量取 0 值,即为 NULL, 则表示该指针变量所指向的对象不存在。这是 NULL 在 C 语言中又一特殊用处。 2.指针运算符&和*
第5章指针 ·39· 指针变量虽是正的整数值,但不是整数类型变量。指针变量最基本的运算符是&和*。 () 取地址 它的作用是返回后随变量(操作数)的内存地址。请注意,它只能用于一个具体的变量或 数组元素,不可用于表达式。 例: int *p: in m=200: p=&m: 这是将整数类型变量m的地址赋给整数类型的指针变量p。 (2)*一一取值 它的作用是返回其后随地址(指针变量所表达的地址值)中的变量值。 例: int *p: int m: int n: =200: p=&m 这是将指针变量p所指向的整数类型变量(即m)的值赋给整数类型变量。其结果与赋值 语句=n:一样,但操作过程用了指针变量p。 &与*运算符互为逆运算。对指针变量px指向的目标变量和x实行取址运算: &(px) 其结果就是px。对变量x的地址实行取值运算 *(&X) 其结果就是x。 注意,x与*px同级别可写成x=和x或和x=x。px与&x同级别可写成px=&x,但决不可写成 &x=DX,也不能写成D 3指针的初始化和赋值运算 指针的初始化往往与指针的定义说明同时完成,初始化一般格式 类型说明符 指针变量名=初始地址值: 例如: char c: char *charp=&c 请注意 ·任何一个指针在使用之前: ①必须加以定义说明。 ②必须经过初始化。 ③未经过初始化的指针变量禁止使用
第 5 章 指针 ·39· 指针变量虽是正的整数值,但不是整数类型变量。指针变量最基本的运算符是&和*。 (1)&——取地址 它的作用是返回后随变量(操作数)的内存地址。请注意,它只能用于一个具体的变量或 数组元素,不可用于表达式。 例: int *p; int m; m=200; p=&m; 这是将整数类型变量 m 的地址赋给整数类型的指针变量 p。 (2) *——取值 它的作用是返回其后随地址(指针变量所表达的地址值)中的变量值。 例: int *p; int m; int n; m=200; p=&m; n=*p; 这是将指针变量 p 所指向的整数类型变量(即 m)的值赋给整数类型变量 n。其结果与赋值 语句 m=n;一样,但操作过程用了指针变量 p。 &与*运算符互为逆运算。对指针变量 px 指向的目标变量*px 实行取址运算: &(*px) 其结果就是 px。对变量 x 的地址实行取值运算: *(&x) 其结果就是 x。 注意,x 与*px 同级别可写成 x=*px 或*px=x。px 与&x 同级别可写成 px=&x,但决不可写成 &x=px,也不能写成 px=x。 3.指针的初始化和赋值运算 指针的初始化往往与指针的定义说明同时完成,初始化一般格式: 类型说明符 指针变量名=初始地址值; 例如: char c; char *charp=&c; 请注意: ·任何一个指针在使用之前: ①必须加以定义说明。 ②必须经过初始化。 ③未经过初始化的指针变量禁止使用
·40 C程序设计要点分析与题解 ·在说明语句中初始化,也是把初始地址值赋给指针变量,只有在说明语句中,才允许这样 写。而在赋值语句中,变量的地址只能赋给指针变量本身。 ·指针变量初始化时,变量应当在前面说明过,才可使用&变量名作为指针变量的初始值 合则, 编译时将出错 ·必须以同类型数据的地址来进行指针初始化。 指针变量可以进行赋值运算,这种赋值运算操作也仅限制在同类之间才可实现。 例5.1:指针变量的引用。 int x=10 int*和l=&x,*p2: /体pl指向x/ p2=p1: /p2指向x*/ printf("%dn”,p2: 执行结果应显示:10 例5.2:指针变量的运算。 mainO char c='A' /变量c的初始值为'A'* char *charp=&c: /*变量c的地址作为指针变量charp的初始值* printf("%c%cn",c,*charp): c='B': /变量c赋值为'B'/ printf("%cc\n"c.*charp): *charp='a' /将指针变量charp所指向地址的内容改为'a'*/ printf(""c.charp): 执行结果应显示: AA BB 4.sizeof运算符 sizeof运算符可以准确地得到在当前所使用的系统中某一数据类型所占字节数。sizeof 运算的格式: i2e0f(举刑道明符) 其值为该类型变量所占字节数。用输出语句可方便地打印出有关信总,例如 printf("d\n",sizeof(int)): printf("d\n",sizeof(float)): printf("%d\n",sizeof(double)):
·40· C 程序设计要点分析与题解 ·在说明语句中初始化,也是把初始地址值赋给指针变量,只有在说明语句中,才允许这样 写。而在赋值语句中,变量的地址只能赋给指针变量本身。 ·指针变量初始化时,变量应当在前面说明过,才可使用&变量名作为指针变量的初始值。 否则,编译时将出错。 ·必须以同类型数据的地址来进行指针初始化。 指针变量可以进行赋值运算,这种赋值运算操作也仅限制在同类之间才可实现。 例 5.1:指针变量的引用。 main() { int x=10 int *p1=&x,*p2; /* p1 指向 x */ p2=p1; /* p2 指向 x */ printf(″%d\n″,*p2); } 执行结果应显示:10 例 5.2:指针变量的运算。 main() { char c=′A′; /*变量 c 的初始值为′A′*/ char *charp=&c; /*变量 c 的地址作为指针变量 charp 的初始值*/ printf(″%c%c\n″,c,*charp); c=′B′; /*变量 c 赋值为′B′*/ printf(″%c%c\n″,c,*charp); *charp=′a′; /*将指针变量 charp 所指向地址的内容改为′a′*/ printf(″%c%c\n″,c,*charp); } 执行结果应显示: AA BB aa 4.sizeof 运算符 sizeof 运算符可以准确地得到在当前所使用的系统中某一数据类型所占字节数。sizeof 运算的格式: sizeof(类型说明符) 其值为该类型变量所占字节数。用输出语句可方便地打印出有关信息,例如: printf(″%d\n″,sizeof(int)); printf(″%d\n″,sizeof(float)); printf(″%d\n″,sizeof(double));
第5章指针 41· 5.指针的算术运算 指针的算术运算是按地址计算规则进行。由于地址计算与相应数据类型所占字节数有关 所以,指针的算术运算应考虑到指针所指向的数据类型。 指针的算术运算只有如下四种: 十,一,十十。一 (1)指针自增1运算++和指针自减1运算一一 指针自增运算意味若指针向后移动一个数据的位置,指向的地址为原来地址十sizeof(类 型说明符)。例如 int i,*p: p=&i: n++: 结果是p指向了变量i的地址+sizeof(int)。 (2)指针变量的+和 指针变量px加(什)正整数,表示指针向后移过n个数据类型,使该指针所指向的地址 变为原指向的地址十sizeof(类型说明符)n。指针变量减(一)正整数n,表示指针往前移回n 个数据,使该指针所指向的地址变为原指向的地址一sizeof(类型说明符)知。 6.指针的关系运算 指向同一种数据类型的指针,才有可能进行各种关系运算。指针的关系运算符包括有: 它们实际所进行的是两个指针所指向的地址的比较。 >不同类型指针之间的比较是没有意义的。 指针与整数常量或变量的比较也没有意义。 独常量0是例外的, 一个指针变量为0(L)表示该指针指向空间不存在,称为 空指 如果有一个指针p,可以用p=0或p!=0来判断p是否为空指针。 7.使用指针编程中的常见错误 (①)使用未初始化的指针变量,例如: i0 intx,: x=0: 却=x: /*指针变量未初始化*/ 和未被初始化 (②)指针变量所指向的数据类型与其定义的类型不符,例如: main( float x,y:
第 5 章 指针 ·41· 5.指针的算术运算 指针的算术运算是按地址计算规则进行。由于地址计算与相应数据类型所占字节数有关, 所以,指针的算术运算应考虑到指针所指向的数据类型。 指针的算术运算只有如下四种: +,-,++,-- (1)指针自增 1 运算++和指针自减 1 运算-- 指针自增运算意味着指针向后移动一个数据的位置,指向的地址为原来地址+sizeof(类 型说明符)。例如: int i,*p; p=&i; p++; 结果是 p 指向了变量 i 的地址+sizeof(int)。 (2)指针变量的+和-运算 指针变量 px 加(+)正整数 n,表示指针向后移过 n 个数据类型,使该指针所指向的地址 变为原指向的地址+sizeof(类型说明符)*n。指针变量减(-)正整数 n,表示指针往前移回 n 个数据,使该指针所指向的地址变为原指向的地址-sizeof(类型说明符)*n。 6.指针的关系运算 指向同一种数据类型的指针,才有可能进行各种关系运算。指针的关系运算符包括有: ==,!=,<,<=,>,>=。 它们实际所进行的是两个指针所指向的地址的比较。 ➢ 不同类型指针之间的比较是没有意义的。 ➢ 指针与整数常量或变量的比较也没有意义。 ➢ 唯独常量 0 是例外的,一个指针变量为 0(NULL)表示该指针指向空间不存在,称为 空指针。 如果有一个指针 p,可以用 p==0 或 p!=0 来判断 p 是否为空指针。 7.使用指针编程中的常见错误 (1)使用未初始化的指针变量,例如: main() { int x,*p; x=0; *p=x; /*指针变量未初始化*/ . } *p 未被初始化。 (2)指针变量所指向的数据类型与其定义的类型不符,例如: main() { float x,y;
·42 C程序设计要点分析与题解 short int柳: D=&x: /数据类型不符* *p: X,y与和数据类型不符。 (③)指针的错误赋值,例如: 照in0 intx,和: x=10 D=x 错在以普通变量x赋给指针变量p。 (④)用局部变量的地址去初始化静态的指针变量,例如: int glo: int loc1,loc2; static int *gp=&glo: static int *lp=&loc1: int杠p=&1oc2: 用局部变量1oc1去初始化静态的指针变量1p是错误的。 5.3指针与函数参数 在函数调用中,使用指针作为参数,可以改变调用环境中的变量之值。这是使用一般变 量作为参数所难以实现的。让我们来观察一个函数的调用: 例5.3:x和y的值互换。 swapl(x,y) int x,y: /*局部变量不能带出函数*/ int temp: temp=x: x=y: v=temp:
·42· C 程序设计要点分析与题解 short int *p; p=&x; /*数据类型不符*/ y=*p; . } x,y 与*p 数据类型不符。 (3)指针的错误赋值,例如: main() { int x,*p; x=10 p=x . } 错在以普通变量 x 赋给指针变量 p。 (4)用局部变量的地址去初始化静态的指针变量,例如: int glo; func() { int 1oc1,1oc2; static int *gp=&glo; static int *1p=&1oc1; int *rp=&1oc2; . } 用局部变量 1oc1 去初始化静态的指针变量 1p 是错误的。 5.3 指针与函数参数 在函数调用中,使用指针作为参数,可以改变调用环境中的变量之值。这是使用一般变 量作为参数所难以实现的。让我们来观察一个函数的调用: 例 5.3:x 和 y 的值互换。 swap1(x,y) int x,y; /*局部变量不能带出函数*/ { int temp; temp=x; x=y; y=temp;