张乃孝-C语言描述(第二版)C语言中的指针_第1页
张乃孝-C语言描述(第二版)C语言中的指针_第2页
张乃孝-C语言描述(第二版)C语言中的指针_第3页
张乃孝-C语言描述(第二版)C语言中的指针_第4页
张乃孝-C语言描述(第二版)C语言中的指针_第5页
已阅读5页,还剩39页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

算法与数据结构——C语言描述(第二版)高岩自我介绍

高岩,毕业于上海交通大学,计算机图形学方箱:ygao@理科大楼B219课程目标学习掌握基本数据结构与基本运算训练数据抽象能力训练算法设计与描述能力提高程序(软件)设计能力课程安排108个学时(5学分)–其中:上课73学时,试验36学时先期课程–C程序设计,面向对象程序设计,离散数学教材《算法与数据结构》,张乃孝编,高等教育出版社《数据结构》,严蔚敏编,清华大学出版社《数据结构题集》,严蔚敏等编,清华大学出版社C语言中的指针与函数A

指针

一个指针是一个特殊变量,它的值是另一个变量的地址。

除寄存器(register)变量外,所有的变量均有地址。地址是变量在内存中存放的位置。在声明一个指针变量时,我们在变量名字

前加一个星号*。A.1

指向变量的指针

声明字符型变量a和指向字符型的指针变量p:char

a="b";char

*p;

此处的p是指针变量,p前面的*用来声明p为一个指针,即p是存放一个变量地址的变量,p指向的变量是字符型的,即p存放字符型变量的地址。

指针变量p在初始化之前,它的当前值是不定的,语句p=

&a;

是将字符变量a的地址赋给指向字符型的指针变量p,

符号&在这里作为一元运算符,是地址运算符,&a是求变量a的地址。

上述语句执行后,在p内存放a的地址,重要的是p与a的类型要匹配。

用*p表示指针p所指的对象,即先取出p中的值,得一个地址,再通过此地址得到需要的对象,因此下面的两个语句输出同样的结果’b’:printf("a

is

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

is

%c\n",*p);

我们可用变量的名字a,也可用指向变量a的指针变量p。这样,要将a内的原有值"b"改成"d",可直接将"d"赋给变量a,也可间接地使用指针变量p,其程序片段为:/*

初始化

p

*//* 将

"d"

直接赋给

a

*/p=&a;a="d";*p="d";/*通过指针变量p将"d"赋给a

*A.2

指向数组的指针先讨论指向数组元素的指针。

用下面语句声明一个字符型数组和一个指向字符型变量的指针:char

line[100],*p;可用下面的语句给line的前两个元素赋值:line[0]="a";

line[1]="b";

也可用指针,先对p初始化使其指向数组line的首址:p=&line[0];

/*第0个元素的地址*/或直接写成:p=line;

/*数组名字是数组的首址*/

然后可用下面两个语句给数组的前两个元素赋值:*p="a";

*(p+1)="b";

对于每个赋值,编译程序将首先计算元素

的地址:数组名字line即是数组的首地址,

line加上增量0,line加上增量1,分别是前两个元素的地址。连续执行下面两个语句*p++="a";

*p++="b";

/*

运算符*与++的优先级相同,结合方向是

“从右到左”*p++

*(p++)

*/

指针p将两次增1,最终指向line[2]的地址。假设有整型数组和指向整型量的指针:int

num[10],*q=num;

q指向num[0]的地址,当q增1时,q指向

num[1]的地址,要移动2个或4个字节(依赖于不同的计算机);而指向字符型的指针增1时,只移动一个字节,这就是指针变量与其指向的变量的类型必须要匹配的道理。

若两个指针指向同一数组,这两个指针也可以做比较运算。

以上讨论的是指向数组元素的指针,下面再简单介绍指向一维数组的指针:int

a[3][4],(*pa)[4];pa=a;第一行声明的pa是一个指针,指向有4个元素的一维整型数组;第二行通过对pa赋值,使得

pa

等于a[0][0]的地址,pa+1要后移4个整数,即pa+1指向a[1][0]的地址,*(pa+1)+3指向a[1][3]的地址,*(*(pa+2)+1)

是a[2][1]的值。

也可建立一个指针数组,它的每个元素均是一个指针,存放地址,下面的语句char

*ap[3];

声明ap是一个指向字符型的指针数组,ap的每个元素存放一个字符串的首址。A.3

指针数组

若我们用内存动态存储区分配函数分配每个字符串的空间:ap[i]=(char

*)malloc(sizeof(字符串));则ap[i]指向分配的相应字符串区域的首址。例如ap[0]存放"science"的首址ap[1]存放"technology"的首址ap[2]存放"art"的首址可以如下表示:ap[0]=(char

*)malloc(sizeof("

science"));ap[1]=(char

*)malloc(sizeof("techonology"))ap[2]=(char

*)malloc(sizeof("art"));A.4指向结构的指针

可定义一个结构数组,然后用指针指向此数组的第一个元素,这等同于我们以前讨论的指向数组元素的指针。例如:struct

exp

/*定义结构exp

*/{char

c;int

i;};struct

exp

ae[10],*p;/*

定义结构数组

ae

和指向结构的指针

p

*/p=ae;/* 使

p

指向数组的首址,即

ae[0]

的地址

*/p->c="a";*//*

元素ae[0]

的成员c

"a"

*/p->i=0;/*

元素

ae[0]

的成员

i

0

*/p++;

/*

使p指向ae[1]p->c="b";

/*

元素

ae[1]

的成员

c

"b"

*/当p是指向结构的指针时,运算符->是成员运算符,p->c

等价于

(*p).c

一个结构中的成员也可以是一个指针,此指针可指向同种类型的另一个结构,称自引用结构,例如struct

self{char

c;struct

self

*next;};struct

self

*p;

声明了p是一个指向结构struct

self的指针变量,链表常用类似的结构表示,p指向链表中的一个元素(结构类型),要存取表中的下一个元素,可以用

p=p->next;因为在p->next中存放下一个元素的地址。A.5补充(指针与数组)一维数组二维数组二维数组与指针指针数组指针数组与指针的指针指向数组的指针多维数组pa[0]a[1]a[2]…...aint

a[10],

*p;

p=a;*p

*a*(p+i)a[0]*(a+i)a[i]一维数组a[0]a[0][0]a[0][1]a[0][2]…...a[1][0]a[1][1]a[1][2]…….a[1]a[2]…...a二维数组:a[i][j]int

a[10][10];*(*(a+i)+j)*(a[i]+j)#include<stdio.h>main()

/*

数组的初始化*/{ int

a[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};int

i,j:for

(i=0;

i<4;

i++){

for(

j=0;

j<4;

j++)printf(“%10d”,

*(a[i]+j)

);printf(“\n”);}}pa[0]a[0][0]a[0][1]a[0][2]…...a[1][0]a[1][1]a[1][2]…….a[1]a[2]…...a二维数组与指针:int

a[10][10];

int

*p;p=(int

*)

a;a[i][j]

*(

(p+i*10)+j

)*(a[i]+j)#include<stdio.h>main(){ int

a[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};int

*p,

i,

j;

p=(int*)a;

for

(i=0;

i<4;

i++){

for(

j=0;

j<4;

j++)printf(“%10d”,

*(

(p+i*4)

+j)

);printf(“\n”);

}}pa[0][0]a[0][1]a[0][2]…...a[1][0]a[1][1]a[1][2]…….…...aint

a[10][10];

int

*p[10];

/*指针数组*/for(i=0;

i<10;

i++)a[i][j]

*(*(p+i)+j)p[i]=a[i];*(p[i]+j)*(a[i]+j)a[0]{ int

a[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};int

*p[4],

i,

j;for

(i=0;

i<4;

i++)

p[i]=a[i];

for

(i=0;

i<4;

i++){

for(

j=0;

j<4;

j++)printf(“%10d”,

*(*

(p+i)

+j)

);printf(“\n”);

}}pa[0][0]a[0][1]a[0][2]…...a[1][0]a[1][1]a[1][2]…….…...a/*指针数组与指针的指针*/int

a[10][10];

int

*p[10],**q

;for(i=0;

i<4;

i++)

p[i]=a[i];a[i][j] *(*(q+i)+j)

*(p[i]+j)q=p;*(a[i]+j)a[0]q{ int

a[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};int*p[4],

**q,i,j;for(i=0;

i<4;

i++)

p[i]=a[i];q=p;for{(i=0;

i<4;

i++)for(

j=0;

j<4;

j++)printf(“%10d”,

*(*

(q+i)

+j)

);printf(“\n”);

}}pa[0]a[0][0]a[0][1]a[0][2]…...a[1][0]a[1][1]a[1][2]…….a[1]a[2]…...int

a[10][10];

int

(*p)[10];/*指向数组的指针*p=(int(*)[10])a[0];a[i][j]

*(

*(p+i)+j

)

*(a[i]+j)a{ int

a[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};int

(

*p)[4],

i,

j;p=(int(*)[4])a[0];

for

(i=0;

i<4;

i++){

for(

j=0;

j<4;

j++)printf(“%10d”,

*(*

(p+i)

+j)

);printf(“\n”);

}}pa[0][0][0]a[0][0][1]a[0][0][2]….a[0][1][0]a[0][1][1]a[0][1][2]…….a[1][0][0]a[1][0][1]a[1][0][2]……..a[0][0]a[0][1]a[0][2]…...a[1][0]a[1][1]a[1][2]…….a[0]a[1]a[2]…...a多维数组注:图中画出的左边两个数组并不是数组。B.函数

一个C程序由几个函数组成。在调用函数时,实际传到函数的信息称为实在参数(argument),而函数中保存要得到信息的参数称为形式参数

(parameter)。void

f(int

x);

说明函数f需要一个整型参数,无返回值到调用它的函数中。

函数原型写出了此函数所需要的参数个数及其类型,如果函数不需要参数,则圆括号内为空或写

void,函数名字前面的类型指出函数要返回的表达式的值的类型,若此函数无返回值,则此类型写成void。B.1函数的实在参数

值传送

在调用函数时,先将实在参数(通常是一个表达式)值计算出来,然后传给函数的形式参数,因此,形式参数得到的是实在参数值的拷贝。如果在被调用函数内改动形式参数,则只改变了这个拷贝的值,而调用函数中的实在参数并没有改变。这就是“值传送”。考虑以下函数:void

f(int

j){j--;printf("j

is

%d\n",j);/*输出的结果是

2

*/}……i=3;f(i);printf("

i

is

%d

\n"

,i);/*

输出的i仍是3

*/……B.2函数的实在参数地址传送

有时我们在函数调用时,需要直接将被调函数中对形式参数的修改体现在调用函数的某个实在变量上,此时要用这个变量的地址作为实在参数传送,相应的形式参数应该是与这个实在变量类型一致的指针类型。例如,函数:void

g(int

*k){

*k=2;

}

形式参数是一个指向整型变量的指针,在此函数内将2赋给用指针k指向的整型变量,调

用此函数的一个例子是•void

main(void){

int

i;g(&i);printf("i=%d\n",i);}/*输出的结果是

由于数组名提供的就是数组的开始地址,所以可作为实在参数和要求与数组元素类

型一致的指针类型的形式参数对应。例如:int

getline(char

*p,int

i);…int

n;char

line[100];...n=getline(line,100);

上面的程序片段调用函数getline,需要一个指向字符的指针和一个整型量作实参,

因数组名字表示地址,我们传送数组名字line,并传送一个规定数组大小的整数100,

如果在函数getline内改动了第一个形式参数指向的变量的值,也就相应地改动了主

调函数中的数组的值。B.3指向指针的指针作参数

有时需修改用地址传送去的实在参数,如调用一个函此函数修改一个指针指向的变量void

f(char

*);void

main

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论