白 雪 飞
baixf@ustc.edu.cn
中国科学技术大学电子科学与技术系
Dept,of Elec,Sci,& Tech.,USTC
Fall,2003
第 7章 指 针
C语言程序设计 - 第 7章 指针 2
目 录
? 指针概念
? 指针变量和指针运算
? 指向数组的指针
? 指向字符串的指针
? 指向函数的指针
? 返回指针值的函数
? 指针数组和指向指针的指针
C语言程序设计 - 第 7章 指针 3
指针 (Pointer)
? 指针表示变量等的存储地址
? 使用指针可以获得紧凑、高效的代码
? 使用指针也可能使程序晦涩难懂
? 指针的使用灵活方便
? 指针操作容易出错且难以调试
? 指针与数组关系密切
C语言程序设计 - 第 7章 指针 4
指针与地址
? 地址
?通过首地址和数
据类型可以访问
内存中某一数据
?数据类型决定所
占用存储单元数
? 指针
?就是地址
?和类型有关
3 7 H
4 5 H
A 6 H
.,,
.,,
.,,
.,,
.,,
}
s h o r t s ; / * 0 x A 6 3 7 * /
c h a r c ; / * 0 x 4 5 * /
}
s h o r t * p s ; / * 0 x 2 0 3 4 * /
}
c h a r * p c ; / * 0 x 3 0 8 8 * /
3 4 H
低 地 址
高 地 址
2 0 H
8 8 H
3 0 H
2 0 3 4 H
2 0 3 5 H
3 0 8 8 H
4 2 3 6 H
4 2 3 7 H
5 7 0 2 H
5 7 0 3 H
C语言程序设计 - 第 7章 指针 5
指针变量和指针运算
? 变量的指针和指针变量
? 指针变量的定义
? 地址运算符和指针运算符
? 指针变量的引用
? 指针的运算
C语言程序设计 - 第 7章 指针 6
变量的指针和指针变量
? 变量的指针
?内存中存储某个变量的存储单元的首地址
?指针 (地址 )实质上是一个整数 (不是 C的整型 )
?可以通过变量的地址来间接的访问变量
? 指针变量
?指针 (地址 )是一个数据,也可以用另一个变
量来存放,即指针变量
?通过指针变量可以间接访问变量或内存数据
C语言程序设计 - 第 7章 指针 7
指针变量的定义
? 一般形式
?基类型 *指针变量名 ;
? 说明
?“基类型”表示该指针指向的数据的类型
?可以定义基类型为空类型 void的指针变量
? 举例
?int *pi;
?char *pc1,c,*pc2;
?void *p;
C语言程序设计 - 第 7章 指针 8
地址运算符 (Address Operator)
? 地址运算符 &
?获得操作数的地址 (指针 )
?单目运算符,自右向左结合,优先级较高
?操作数应为各种类型的内存变量、数组元素、
结构体成员等
?操作数不能是表达式、常量、寄存器变量
? 举例
?scanf("%f",&score);
?int i,*p=&i;
C语言程序设计 - 第 7章 指针 9
指针运算符 (Indirection Operator)
? 指针运算符 *
?获得指针指向的内存数据
?又称“间接访问运算符”
?单目运算符,自右向左结合,优先级较高
?操作数为具有指针 (地址 )意义的值
? 举例
?int i,*p=&i;
(*p)++; /* i++; */
C语言程序设计 - 第 7章 指针 10
指针变量的引用
? 指针变量也要“先赋值,后使用”
? 没有赋值的指针变量所存储的地址数据
是不确定的,对它的引用非常危险
? 对指针的赋值要注意类型匹配,必要时
可以使用强制类型转换,但要慎重使用
? *p可以用于与指针 p的基类型相同类型
的 变量 可以使用的 任何场合
? 指针变量可以作为函数的参数
C语言程序设计 - 第 7章 指针 11
指针变量引用举例 (07-01.C)
int a,b,c,*pa,*pb,*pc;
pa = &a;
pb = &b;
pc = &c;
a = 100;
printf("*pa=%d\n",*pa); /* *pa=100 */
*pb = 200;
printf("b=%d\n",b); /* b=200 */
scanf("%d",pc); /* 输入 34 */
printf("c=%d\n",c); /* c=34 */
C语言程序设计 - 第 7章 指针 12
指针变量与所指变量的关系
10
20
pa
pb
a
b
int a,b;
int *pa,*pb;
pa = &a;
pb = &b;
*pa = 10;
b = 20;
pa = pb;
pb = &a;
&a,&*pa *pa,*&a
C语言程序设计 - 第 7章 指针 13
指针变量作为函数参数
? 参数传递
?仍然遵循,单向值传递,的规则
?这里的传递规则是 指针类型参数的值 的传递
?作为参数的 指针型实参的值 不会改变
?但是对 指针型实参所指向的内存数据 所作的
操作将不会随函数的返回而恢复
? 用途
?借助指针类型参数可以改变多个数据的值
C语言程序设计 - 第 7章 指针 14
指针类型函数参数举例 (07-02.C)
void swap(int *x,int *y)
{
int t;
t=*x,*x=*y,*y=t;
}
void main()
{
int a=1,b=4;
int *pa,*pb;
pa=&a,pb=&b;
swap(pa,pb);
}
&a
a
&bpb
1
4
4
1 bpa
&a
&by
x
参数传递
C语言程序设计 - 第 7章 指针 15
指针的运算
? 运算类型
?算术运算:加、减、自增、自减
?关系运算:所有关系运算
?赋值运算:一般赋值、加赋值、减赋值
?上述运算在一定约束条件下才有意义 (后详 )
? 变量说明
?p,q是同类型的指针变量
?n是整型变量
C语言程序设计 - 第 7章 指针 16
指针的算术运算
运算方式 说 明
p+n p之后第 n个元素的地址
p-n p之前第 n个元素的地址
p++ p作为当前操作数,然后后移一个 元素
++p p后移一个 元素,然后作为当前操作数
p-- p作为当前操作数,然后前移一个 元素
--p p前 移一个 元素,然后作为当前操作数
p-q 表示 p和 q两者之间的 元素 个数
? 条件,p,q是指向同一数据集合 (数组 )的指针
? 注意避免数组越界
C语言程序设计 - 第 7章 指针 17
指针的关系运算
? 条件
?p,q是指向同一数据集合 (数组 )的指针
? 运算方式
?p<q,p<=q,p==q,p!=q,p>=q,p>q
?p<q:判断 p所指元素是否在 q所指元素之前
?其他运算的含义与上述类似
?若 p,q不是指向同一数据集合的指针,则运
算无意义
C语言程序设计 - 第 7章 指针 18
指针的赋值运算
? 条件
?p,q是指向同一数据类型的指针
?n是整型数据
? 有意义的赋值方式
?p=q
?p=q+n,p=q-n (要求 q指向数组 )
?p+=n,p-=n (要求 p指向数组 )
?注意避免数组越界
C语言程序设计 - 第 7章 指针 19
指针的运算说明
? 指针的运算还包括
?指针运算
?对指向数组的指针的下标运算
?对指针变量的取地址运算
?对指向结构体的指针的指向成员运算
? 除上述运算方式 (包括约束条件 )外的其他
运算都没有意义
? 无意义的指针运算不一定会出现语法错
误,但可能造成危险的操作
C语言程序设计 - 第 7章 指针 20
指针的运算举例
short a[5],*p,*q;
p = &a[0];
q = p+2;
p += 3;
printf("%d",*p++);
scanf("%d",*--q);
if (p>q)
printf("%d",p-q);
else
printf("%d",q-p);
.,,
.,,
低 地 址
高 地 址
}
a [ 0 ]
}
a [ 1 ]
}
a [ 2 ]
}
a [ 3 ]
}
a [ 4 ]
p
q
3
个short
C语言程序设计 - 第 7章 指针 21
指向数组的指针
? 指针与数组的关系
? 指向数组的指针
? 通过指针引用数组元素
? 数组用作函数参数
? 指向二维数组的指针
C语言程序设计 - 第 7章 指针 22
指针与数组的关系
? 数组名是,常量指针,
?数组名表示数组的首地址,因此数组名也是
一种指针 (地址 )
?数组名表示的地址 (指针 )不能被修改,所以
称之为“常量指针”
? 数组的指针
?数组的起始地址
?与数组名表示的指针相同
?与数组的第一个元素 (a[0])的地址相同
C语言程序设计 - 第 7章 指针 23
数组和指针的用法
? 数组名不能被赋值和修改,若指针指向
数组,则两者的其他用法基本相同
? 定义指针时,只分配一段用来存放地址
的空间,而没有分配存放数据的空间
? 定义数组时,为所有元素分配相应的连
续的存储空间,但没有存放地址的空间
? 指针应赋值后才能使用
? 数组名不能被赋值,可以直接使用
C语言程序设计 - 第 7章 指针 24
指向数组的指针
char a[10],*p;
p = &a[0];
char a[10],*p=&a[0];
char a[10],*p;
p = a;
char a[10],*p=a;
...
...
a[0]
a[1]
a[2]
a[3]
a[4]
a[5]
a[9]
a[6]
a[8]
a[7]
ap &a[0]
C语言程序设计 - 第 7章 指针 25
通过指针引用数组元素
? 当一个指针变量指向数组或某个数组元
素时,可以通过这个指针变量引用所有
的数组元素
? 引用数组元素的方法
?下标运算符 [],例如 a[i],p[i]
?指针运算符 *,例如 *(a+i),*(p+i)
? 注意数组名不能被修改和赋值
? 注意防止下标越界
C语言程序设计 - 第 7章 指针 26
通过指针引用数组元素图示
...
...
a[0]
a[1]
a[2]
a[i]
a[9]
p[0],*p,*ap,a
p+1,a+1 p[1],*(p+1),*(a+1)
q+i-2,p+i,a+i p[i],*(p+i),*(a+i)q[i-2],*(q+i-2),
p+9,a+9 p[9],*(p+9),*(a+9)
q,p+2,a+2 p[2],*(p+2),*(a+2) q[0],*q
C语言程序设计 - 第 7章 指针 27
数组名和指针引用数组元素比较 (1)
? 指针指向数组首地址
?前提条件,int a[10],*p=a;
?a[i],p[i],*(a+i),*(p+i)等用法都
是合法的,且 它们都表示同一个数组元素
?a+i(或 p+i)不是简单的在 a(或 p)表示的地
址值上简单的加 i,而是加上 i个基类型所
需的地址偏移量,即加上 i*sizeof(int)
?指针值可以改变,如 p++为 下一元素的地址
?数组名的值不能修改,如 a++是非法操作
C语言程序设计 - 第 7章 指针 28
数组名和指针引用数组元素比较 (2)
? 指针指向某个数组元素
?前提条件,p=a+i;
?*(p++)与 a[i++]等价
?*(p--)与 a[i--]等价
?*(++p)与 a[++i]等价
?*(--p)与 a[--i]等价
?注意不能使用 *(a++)或 a=p+i这种形式
?注意区分运算顺序,*(p++)与 (*p)++
? 注意防止下标越界,注意掌握指针位置
C语言程序设计 - 第 7章 指针 29
通过指针引用数组元素举例
int a[10],i,*p;
p = a; /* 指针需要先赋值 */
while (p<a+10) /* 指针在数组范围内移动 */
scanf("%d",p++); /* 指针向下移动 */
p = a; /* 指针指向正确位置 */
for (i=0; i<10; i++)
printf("%d",p[i]); /* 指针使用 [] */
C语言程序设计 - 第 7章 指针 30
数组用作函数参数
? 数组元素用作函数实参
?与同类型的一般变量用法相同
? 数组用作函数参数
?数组类型可以作为函数参数类型
?数组可以用作函数的形参和实参
?定义函数时,数组型形参实际上作为指针型
形参处理,实参可用相同类型的数组或指针
?声明数组类型形参时,不需要指定数组长度
?一般应把数组长度作为另一个参数传递
C语言程序设计 - 第 7章 指针 31
以数组作为实参的几种方法 (1)
? 形参用数组名
实参用数组名
? 形参用指针变量
实参用数组名
f(int x[],int n)
{,..,.,}
main()
{ int a[10];
...,..
f(a,10);
}
f(int *x,int n)
{,..,.,}
main()
{ int a[10];
...,..
f(a,10);
}
C语言程序设计 - 第 7章 指针 32
以数组作为实参的几种方法 (2)
? 形参用数组名
实参用指针变量
? 形参用指针变量
实参用指针变量
f(int x[],int n)
{,..,.,}
main()
{ int a[10],*p=a;
...,..
f(p,10);
}
f(int *x,int n)
{,..,.,}
main()
{ int a[10],*p=a;
...,..
f(p,10);
}
C语言程序设计 - 第 7章 指针 33
数组用作函数参数举例
? 选择排序法
5
2
8
4
6
3
? ? ? ? ?
8
2
5
4
6
3
8
6
5
4
2
3
8
6
5
4
2
3
8
6
5
4
2
3
8
6
5
4
3
2
C语言程序设计 - 第 7章 指针 34
例 1:选择排序法 (07-03.C)
void sort(int x[],int n) /* int *x */
{
int i,j,k,t;
for (i=0; i<n-1; i++) {
k = i;
for (j=i+1; j<n; j++)
if(x[j]>x[k]) k=j;
if (k!=i)
t=x[i],x[i]=x[k],x[k]=t;
}
}
C语言程序设计 - 第 7章 指针 35
例 1:选择排序法 (续 )
void main()
{
int a[10],*p,i;
p = a;
for (i=0; i<10; i++)
scanf("%d",p++);
p = a;
sort(p,10); /* sort(a,10); */
for (p=a,i=0; i<10; i++)
printf("%d",*p++);
}
C语言程序设计 - 第 7章 指针 36
指向二维数组的指针 (1)
a[0]
a[1]
a[2]
a
a+1
a+2
char a[3][4];
*a
*(a+1)
*(a+2)
a是一个长度为 3的数组
数组元素是长度为 4的数组
a,a+1,a+2都是指针,它
们的基类型是长度为 4的字
符数组,它们与下面定义的
指针 p同类型
char (*p)[4];
C语言程序设计 - 第 7章 指针 37
指向二维数组的指针 (2)
a
a+1
a+2
a[0]
a[1]
a[2]
0,0 0,1 0,2 0,3
1,0 1,1 1,2 1,3
2,0 2,1 2,2 2,3
*a
a[0]
*a+1
a[0]+1
*a+2
a[0]+2
*a+3
a[0]+3
a[2]
*(a+2)
a[2]+1
*(a+2)+1
a[1]+3
*(a+1)+3
a[1][3]
*(*(a+1)+3)
a[1]
*(a+1)
a[2][3]
*(*(a+2)+3)
a[0][3]
*(*a+3)
char *
char
char *
基类型为
char[4]
的指针
C语言程序设计 - 第 7章 指针 38
指向二维数组的指针总结
? 表示二维数组
?a:指向二维数组的指针类型
? 表示第 i行
?a[i],*(a+i):指向一维数组的指针类型
? 表示第 i行 j列的元素
?a[i][j],*(*(a+i)+j)
?*(a[i]+j),(*(a+i))[j],char类型
? 注意 a和 *a都是指针,但是基类型不同
? 注意 *(a+i)和 *a+i的区别
C语言程序设计 - 第 7章 指针 39
指向二维数组的指针变量
? 指向数组元素的指针变量
?指向二维数组的元素
?类型为 char *p;
?根据一维数组元素和二维数组元素的对应关
系,可以访问所有的二维数组元素
? 基类型为一维数组的指针变量
?指向二维数组的行
?类型为 char (*p)[4];
?把每一行作为一个一维数组来处理
C语言程序设计 - 第 7章 指针 40
指向二维数组元素的指针变量
? 一维数组与二维数组
char a[M][N]; ? char a[M*N];
a[i][j] ? a[i*N+j]
? 使用指向元素的指针访问二维数组元素
char a[M][N];
char *p=a[0]; /* p=*a; */
则 p[i*N+j],*(p+i*N+j),a[i][j]
表示二维数组第 i行 j列的元素
C语言程序设计 - 第 7章 指针 41
指向二维数组的行的指针变量
? 二维数组是基类型为一维数组的指针
?可以使用与二维数组同类型的指针变量
? 使用指向行的指针访问二维数组元素
int a[M][N];
int (*p)[N]=a; /* p=a; */
则 p[i],*(p+i),a[i]表示数组的第 i行
且 p[i][j],*(*(p+i)+j),*(p[i]+j)、
(*(p+i))[j]表示二维数组第 i行 j列的元素
C语言程序设计 - 第 7章 指针 42
二维数组的指针作函数参数
? 二维数组的地址也可以用作函数参数
?用指向数组元素的指针作为参数
?用指向二维数组的行的指针作为参数
? 举例
void foo(int *p,int n);
void bar(int (*p)[4],int n);
int a[3][4]; /* 定义二维数组 */
foo(*a,12); /* 二维数组的行作为参数 */
bar(a,3); /* 二维数组名作为参数 */
C语言程序设计 - 第 7章 指针 43
指向字符串的指针
? 指针指向存放字符串的字符数组
?与前述,指向数组的指针,类似
? 直接用字符指针指向字符串
?字符串常量按字符数组处理,在存储器中占
有一定的空间,并有自己的地址 (指针 )
?可以把字符串常量的地址赋给字符指针变量
?通过这个字符指针变量可以修改字符串常量
?两个内容完全一样的字符串常量,在存储器
中是不同的字符串,具有不同的存储空间
C语言程序设计 - 第 7章 指针 44
直接用字符指针指向字符串
? 可以用字符指针直接指向字符串常量
? 可以用字符串常量对字符指针直接赋值
? 这是把字符串常量的 地址 赋给字符指针
? 而不是把字符串的 内容 赋给字符指针
? 使用字符指针可以修改字符串的内容
? 只有利用指针才能再次访问某字符串常量
? 注意防止越过原字符串常量的范围
? 注意字符串末尾应保留结束标志 '\0'
C语言程序设计 - 第 7章 指针 45
字符串指针举例
char *s="I love";
char *t;
t = "China!";
s[0] = 'U';
puts(s); /* U love */
s[6] = '~';
puts(s);
/* U love~China! */
s[12] ='~';
puts(t); /* China~ */
I
?
l
o
v
e
\0
C
h
i
n
a
!
\0
s s[0]
s[6]
t
s[12]
U
~
~
C语言程序设计 - 第 7章 指针 46
字符串指针作函数参数举例
void strcpy(char *s,char *t)
{
while(*t++=*s++); /* 逐个字符复制 */
}
void main()
{
char *str1="C Language",str2[20];
strcpy(str1,str2);
puts(str2); /* C Language */
}
C语言程序设计 - 第 7章 指针 47
字符数组和字符指针变量比较 (1)
? 定义
?char astr[]="Hello,World!";
?char *pstr="Hello,World!";
? 数组在定义时分配存放若干字符的空间
? 指针定义时只分配存放一个地址的空间
Hello,World!\0pstr:
Hello,World!\0astr:
C语言程序设计 - 第 7章 指针 48
字符数组和字符指针变量比较 (2)
? 数组可以直接使用
? 指针要先指向一个字符串后才能使用
? 字符串常量只能对数组赋初值,把字符
串的各个字符放到数组中,并且不能在
其他场合对数组整体赋值
? 指针可以用字符串常量或字符数组任意
赋值,但只是把字符串的地址赋给指针
? 数组名的值不能修改
? 指针可以任意修改
C语言程序设计 - 第 7章 指针 49
指向函数的指针
? 函数的指令存储在内存中的一段空间中
? 函数也有相应的内存地址
? 函数的入口地址就是函数的指针
? 函数名代表函数的入口地址
? 函数的指针可以用相应类型的指针变量
表示,即指向函数的指针变量
? 函数也可以用通过指针变量间接调用
C语言程序设计 - 第 7章 指针 50
指向函数的指针变量
? 定义形式
?类型 (*变量名 )([参数类型列表 ]);
? 说明
?与函数原型类似,函数名用 (*变量名 )代替
?“参数类型列表”可以省略,但一般不要省
略
?主要用于函数的参数
?先赋值,后使用,一般用同类型函数名赋值
?不能进行算术运算和关系运算
C语言程序设计 - 第 7章 指针 51
指向函数的指针变量使用举例
int max(int x,int y)
{ return x>y?x:y; }
void main()
{
int (*p)(int,int); /* 定义指针变量 */
int a,b,c;
scanf("%d%d",&a,&b);
p = max; /* 用函数名赋值 */
c = (*p)(a,b); /* c=max(a,b); */
}
C语言程序设计 - 第 7章 指针 52
指向函数的指针用作函数参数举例
? 一元函数定积分的梯形法数值求解
O x
f ( x )
a
b
h
?
?
?
?
?
?
????
???
?
?
??
?
?
2
)(
)(
2
)(
)(
1
1
bf
xf
af
hdxxf
hiax
n
ab
h
n
i
i
b
a
i
C语言程序设计 - 第 7章 指针 53
例:一元函数定积分 (07-04.C)
double integral(double (*f)(double),
double a,double b)
{
double s,h;
int n=100,i;
h = (b-a)/n;
s = ((*f)(a)+(*f)(b))/2.0;
for(i=1; i<n; i++)
s += (*f)(a+i*h);
return s*h;
}
C语言程序设计 - 第 7章 指针 54
例:一元函数定积分 (续 )
#include <stdio.h>
#include <math.h>
void main()
{
double y1,y2,y3;
y1 = integral(sin,0.0,1.0);
y2 = integral(cos,0.0,2.0);
y3 = integral(exp,0.0,3.5);
printf("%lf\n%lf\n%lf\n",y1,y2,y3);
}
C语言程序设计 - 第 7章 指针 55
返回指针值的函数
? 函数的返回值可以是指针类型
? 定义形式
?类型 *函数名 (参数列表 );
? 举例
?int *foo(int x,int y);
? 说明
?函数调用可以结合使用 *和 []运算符
?注意与指向函数的指针区别
int (*foo)(int x,int y);
C语言程序设计 - 第 7章 指针 56
返回指针值的函数举例 (1)
int *f(int *px,int *py) /* 返回整型指针 */
{
return *px>*py?px:py; /* 较大数的地址 */
}
void main()
{
int a=2,b=3,c=9;
*f(&a,&b)=c; /* 赋值给 a和 b中较大的数 */
printf("%d\n",b); /* 输出 9 */
}
C语言程序设计 - 第 7章 指针 57
返回指针值的函数举例 (2)
int *f(int *a,int *b) /* 返回整型指针 */
{
return *a>*b?a:b; /* 返回第一个元素 */
} /* 较大的数组地址 */
void main()
{
int i,a[]={1,2,3,4},b[]={5,6,7,8};
for (i=0; i<4; i++)
printf("%d\n",f(a,b)[i]);
} /* 打印数组 b的元素 */
C语言程序设计 - 第 7章 指针 58
指针数组和指向指针的指针
? 指针数组
?类型 *数组名 [长度 ];
?元素是指针类型的数组
?举例,char *p[4];
?注意与基类型为数组的指针区分
char (*p)[4];
? 指向指针的指针
?基类型为指针类型的指针
?举例,char **p;
C语言程序设计 - 第 7章 指针 59
指针数组举例
/* 把所有名字的所有字母全部改成大写 */
void main()
{
char *name[]={"Tom","John","Kate"};
int i,j;
for (i=0; i<3; i++)
for (j=0; *(name[i]+j); j++)
if (name[i][j]>='a' &&
name[i][j]<='z')
name[i][j]-=32;
}
C语言程序设计 - 第 7章 指针 60
指向指针的指针举例
/* 利用指向字符指针的指针打印字符串数组 */
void main()
{
char *name[]={"Tom","John","Kate"};
char **p;
int i;
p = name;
for (i=0; i<3; i++)
printf("%s\n",*p++);
}
C语言程序设计 - 第 7章 指针 61
命令行参数
? main函数的几种形式
? int main();
? int main(int argc,char *argv[]);
? int main(int argc,char **argv);
? 说明
?返回值类型一般为 int,也可以是其他类型
?argc为命令行参数的个数
?argv为命令行参数字符串数组
?命令行参数包括文件名本身
C语言程序设计 - 第 7章 指针 62
命令行参数举例 — echo命令
>echo C Language
argc == 3;
argv[0] == "echo";
argv[1] == "C";
argv[2] == "Language";
#include <stdio.h>
int main(int argc,char *argv[])
{
while(--argc > 0)
printf("%s%c",*++argv,(argc>1)?' ':'\n');
return 0;
}
C语言程序设计 - 第 7章 指针 63
复杂的声明形式
? 复杂类型变量的声明容易混淆
?指针数组和指向数组的指针
int *a[5]; int (*a)[5];
?指向函数的指针和返回指针值的函数
void (*f)(); void *f();
? 过于复杂的声明形式使程序晦涩难懂,
而且容易出错
? 可以用 typedef关键字把复杂类型的变
量声明用若干个容易理解的小步骤表示
C语言程序设计 - 第 7章 指针 64
分析声明形式的方法
? 从标识符开始,逐层分析其意义
? 按运算符优先级和结合方向的顺序进行
? 可能涉及的运算符包括
? ()自左向右结合
改变结合顺序;或声明一个函数,向外一层是函数
返回值类型声明
? []自左向右结合
声明一个数组,向外一层是数组元素类型声明
? * 自右向左结合
声明一个指针类型,向外一层是指针基类型声明
C语言程序设计 - 第 7章 指针 65
声明形式分析举例
char (*(*x[3])())[5];
x是一个长度为 3的数组
数组的元素是指针类型
指针是指向函数的
函数的返回值是指针类型
指向长度为 5的字符数组
x is an array[3] of pointer to function
returning pointer to array[5] of char
C语言程序设计 - 第 7章 指针 66
void类型指针
? 定义形式
?void *p;
? 说明
?定义一个指针,但不指定它指向的数据类型
?不能通过 *p引用它指向的数据
?void*指针可以与其他任何类型的指针相互
赋值和比较,而不需要显式的强制类型转换
?经常作为函数形参和返回值的类型
C语言程序设计 - 第 7章 指针 67
结束
The End
baixf@ustc.edu.cn
中国科学技术大学电子科学与技术系
Dept,of Elec,Sci,& Tech.,USTC
Fall,2003
第 7章 指 针
C语言程序设计 - 第 7章 指针 2
目 录
? 指针概念
? 指针变量和指针运算
? 指向数组的指针
? 指向字符串的指针
? 指向函数的指针
? 返回指针值的函数
? 指针数组和指向指针的指针
C语言程序设计 - 第 7章 指针 3
指针 (Pointer)
? 指针表示变量等的存储地址
? 使用指针可以获得紧凑、高效的代码
? 使用指针也可能使程序晦涩难懂
? 指针的使用灵活方便
? 指针操作容易出错且难以调试
? 指针与数组关系密切
C语言程序设计 - 第 7章 指针 4
指针与地址
? 地址
?通过首地址和数
据类型可以访问
内存中某一数据
?数据类型决定所
占用存储单元数
? 指针
?就是地址
?和类型有关
3 7 H
4 5 H
A 6 H
.,,
.,,
.,,
.,,
.,,
}
s h o r t s ; / * 0 x A 6 3 7 * /
c h a r c ; / * 0 x 4 5 * /
}
s h o r t * p s ; / * 0 x 2 0 3 4 * /
}
c h a r * p c ; / * 0 x 3 0 8 8 * /
3 4 H
低 地 址
高 地 址
2 0 H
8 8 H
3 0 H
2 0 3 4 H
2 0 3 5 H
3 0 8 8 H
4 2 3 6 H
4 2 3 7 H
5 7 0 2 H
5 7 0 3 H
C语言程序设计 - 第 7章 指针 5
指针变量和指针运算
? 变量的指针和指针变量
? 指针变量的定义
? 地址运算符和指针运算符
? 指针变量的引用
? 指针的运算
C语言程序设计 - 第 7章 指针 6
变量的指针和指针变量
? 变量的指针
?内存中存储某个变量的存储单元的首地址
?指针 (地址 )实质上是一个整数 (不是 C的整型 )
?可以通过变量的地址来间接的访问变量
? 指针变量
?指针 (地址 )是一个数据,也可以用另一个变
量来存放,即指针变量
?通过指针变量可以间接访问变量或内存数据
C语言程序设计 - 第 7章 指针 7
指针变量的定义
? 一般形式
?基类型 *指针变量名 ;
? 说明
?“基类型”表示该指针指向的数据的类型
?可以定义基类型为空类型 void的指针变量
? 举例
?int *pi;
?char *pc1,c,*pc2;
?void *p;
C语言程序设计 - 第 7章 指针 8
地址运算符 (Address Operator)
? 地址运算符 &
?获得操作数的地址 (指针 )
?单目运算符,自右向左结合,优先级较高
?操作数应为各种类型的内存变量、数组元素、
结构体成员等
?操作数不能是表达式、常量、寄存器变量
? 举例
?scanf("%f",&score);
?int i,*p=&i;
C语言程序设计 - 第 7章 指针 9
指针运算符 (Indirection Operator)
? 指针运算符 *
?获得指针指向的内存数据
?又称“间接访问运算符”
?单目运算符,自右向左结合,优先级较高
?操作数为具有指针 (地址 )意义的值
? 举例
?int i,*p=&i;
(*p)++; /* i++; */
C语言程序设计 - 第 7章 指针 10
指针变量的引用
? 指针变量也要“先赋值,后使用”
? 没有赋值的指针变量所存储的地址数据
是不确定的,对它的引用非常危险
? 对指针的赋值要注意类型匹配,必要时
可以使用强制类型转换,但要慎重使用
? *p可以用于与指针 p的基类型相同类型
的 变量 可以使用的 任何场合
? 指针变量可以作为函数的参数
C语言程序设计 - 第 7章 指针 11
指针变量引用举例 (07-01.C)
int a,b,c,*pa,*pb,*pc;
pa = &a;
pb = &b;
pc = &c;
a = 100;
printf("*pa=%d\n",*pa); /* *pa=100 */
*pb = 200;
printf("b=%d\n",b); /* b=200 */
scanf("%d",pc); /* 输入 34 */
printf("c=%d\n",c); /* c=34 */
C语言程序设计 - 第 7章 指针 12
指针变量与所指变量的关系
10
20
pa
pb
a
b
int a,b;
int *pa,*pb;
pa = &a;
pb = &b;
*pa = 10;
b = 20;
pa = pb;
pb = &a;
&a,&*pa *pa,*&a
C语言程序设计 - 第 7章 指针 13
指针变量作为函数参数
? 参数传递
?仍然遵循,单向值传递,的规则
?这里的传递规则是 指针类型参数的值 的传递
?作为参数的 指针型实参的值 不会改变
?但是对 指针型实参所指向的内存数据 所作的
操作将不会随函数的返回而恢复
? 用途
?借助指针类型参数可以改变多个数据的值
C语言程序设计 - 第 7章 指针 14
指针类型函数参数举例 (07-02.C)
void swap(int *x,int *y)
{
int t;
t=*x,*x=*y,*y=t;
}
void main()
{
int a=1,b=4;
int *pa,*pb;
pa=&a,pb=&b;
swap(pa,pb);
}
&a
a
&bpb
1
4
4
1 bpa
&a
&by
x
参数传递
C语言程序设计 - 第 7章 指针 15
指针的运算
? 运算类型
?算术运算:加、减、自增、自减
?关系运算:所有关系运算
?赋值运算:一般赋值、加赋值、减赋值
?上述运算在一定约束条件下才有意义 (后详 )
? 变量说明
?p,q是同类型的指针变量
?n是整型变量
C语言程序设计 - 第 7章 指针 16
指针的算术运算
运算方式 说 明
p+n p之后第 n个元素的地址
p-n p之前第 n个元素的地址
p++ p作为当前操作数,然后后移一个 元素
++p p后移一个 元素,然后作为当前操作数
p-- p作为当前操作数,然后前移一个 元素
--p p前 移一个 元素,然后作为当前操作数
p-q 表示 p和 q两者之间的 元素 个数
? 条件,p,q是指向同一数据集合 (数组 )的指针
? 注意避免数组越界
C语言程序设计 - 第 7章 指针 17
指针的关系运算
? 条件
?p,q是指向同一数据集合 (数组 )的指针
? 运算方式
?p<q,p<=q,p==q,p!=q,p>=q,p>q
?p<q:判断 p所指元素是否在 q所指元素之前
?其他运算的含义与上述类似
?若 p,q不是指向同一数据集合的指针,则运
算无意义
C语言程序设计 - 第 7章 指针 18
指针的赋值运算
? 条件
?p,q是指向同一数据类型的指针
?n是整型数据
? 有意义的赋值方式
?p=q
?p=q+n,p=q-n (要求 q指向数组 )
?p+=n,p-=n (要求 p指向数组 )
?注意避免数组越界
C语言程序设计 - 第 7章 指针 19
指针的运算说明
? 指针的运算还包括
?指针运算
?对指向数组的指针的下标运算
?对指针变量的取地址运算
?对指向结构体的指针的指向成员运算
? 除上述运算方式 (包括约束条件 )外的其他
运算都没有意义
? 无意义的指针运算不一定会出现语法错
误,但可能造成危险的操作
C语言程序设计 - 第 7章 指针 20
指针的运算举例
short a[5],*p,*q;
p = &a[0];
q = p+2;
p += 3;
printf("%d",*p++);
scanf("%d",*--q);
if (p>q)
printf("%d",p-q);
else
printf("%d",q-p);
.,,
.,,
低 地 址
高 地 址
}
a [ 0 ]
}
a [ 1 ]
}
a [ 2 ]
}
a [ 3 ]
}
a [ 4 ]
p
q
3
个short
C语言程序设计 - 第 7章 指针 21
指向数组的指针
? 指针与数组的关系
? 指向数组的指针
? 通过指针引用数组元素
? 数组用作函数参数
? 指向二维数组的指针
C语言程序设计 - 第 7章 指针 22
指针与数组的关系
? 数组名是,常量指针,
?数组名表示数组的首地址,因此数组名也是
一种指针 (地址 )
?数组名表示的地址 (指针 )不能被修改,所以
称之为“常量指针”
? 数组的指针
?数组的起始地址
?与数组名表示的指针相同
?与数组的第一个元素 (a[0])的地址相同
C语言程序设计 - 第 7章 指针 23
数组和指针的用法
? 数组名不能被赋值和修改,若指针指向
数组,则两者的其他用法基本相同
? 定义指针时,只分配一段用来存放地址
的空间,而没有分配存放数据的空间
? 定义数组时,为所有元素分配相应的连
续的存储空间,但没有存放地址的空间
? 指针应赋值后才能使用
? 数组名不能被赋值,可以直接使用
C语言程序设计 - 第 7章 指针 24
指向数组的指针
char a[10],*p;
p = &a[0];
char a[10],*p=&a[0];
char a[10],*p;
p = a;
char a[10],*p=a;
...
...
a[0]
a[1]
a[2]
a[3]
a[4]
a[5]
a[9]
a[6]
a[8]
a[7]
ap &a[0]
C语言程序设计 - 第 7章 指针 25
通过指针引用数组元素
? 当一个指针变量指向数组或某个数组元
素时,可以通过这个指针变量引用所有
的数组元素
? 引用数组元素的方法
?下标运算符 [],例如 a[i],p[i]
?指针运算符 *,例如 *(a+i),*(p+i)
? 注意数组名不能被修改和赋值
? 注意防止下标越界
C语言程序设计 - 第 7章 指针 26
通过指针引用数组元素图示
...
...
a[0]
a[1]
a[2]
a[i]
a[9]
p[0],*p,*ap,a
p+1,a+1 p[1],*(p+1),*(a+1)
q+i-2,p+i,a+i p[i],*(p+i),*(a+i)q[i-2],*(q+i-2),
p+9,a+9 p[9],*(p+9),*(a+9)
q,p+2,a+2 p[2],*(p+2),*(a+2) q[0],*q
C语言程序设计 - 第 7章 指针 27
数组名和指针引用数组元素比较 (1)
? 指针指向数组首地址
?前提条件,int a[10],*p=a;
?a[i],p[i],*(a+i),*(p+i)等用法都
是合法的,且 它们都表示同一个数组元素
?a+i(或 p+i)不是简单的在 a(或 p)表示的地
址值上简单的加 i,而是加上 i个基类型所
需的地址偏移量,即加上 i*sizeof(int)
?指针值可以改变,如 p++为 下一元素的地址
?数组名的值不能修改,如 a++是非法操作
C语言程序设计 - 第 7章 指针 28
数组名和指针引用数组元素比较 (2)
? 指针指向某个数组元素
?前提条件,p=a+i;
?*(p++)与 a[i++]等价
?*(p--)与 a[i--]等价
?*(++p)与 a[++i]等价
?*(--p)与 a[--i]等价
?注意不能使用 *(a++)或 a=p+i这种形式
?注意区分运算顺序,*(p++)与 (*p)++
? 注意防止下标越界,注意掌握指针位置
C语言程序设计 - 第 7章 指针 29
通过指针引用数组元素举例
int a[10],i,*p;
p = a; /* 指针需要先赋值 */
while (p<a+10) /* 指针在数组范围内移动 */
scanf("%d",p++); /* 指针向下移动 */
p = a; /* 指针指向正确位置 */
for (i=0; i<10; i++)
printf("%d",p[i]); /* 指针使用 [] */
C语言程序设计 - 第 7章 指针 30
数组用作函数参数
? 数组元素用作函数实参
?与同类型的一般变量用法相同
? 数组用作函数参数
?数组类型可以作为函数参数类型
?数组可以用作函数的形参和实参
?定义函数时,数组型形参实际上作为指针型
形参处理,实参可用相同类型的数组或指针
?声明数组类型形参时,不需要指定数组长度
?一般应把数组长度作为另一个参数传递
C语言程序设计 - 第 7章 指针 31
以数组作为实参的几种方法 (1)
? 形参用数组名
实参用数组名
? 形参用指针变量
实参用数组名
f(int x[],int n)
{,..,.,}
main()
{ int a[10];
...,..
f(a,10);
}
f(int *x,int n)
{,..,.,}
main()
{ int a[10];
...,..
f(a,10);
}
C语言程序设计 - 第 7章 指针 32
以数组作为实参的几种方法 (2)
? 形参用数组名
实参用指针变量
? 形参用指针变量
实参用指针变量
f(int x[],int n)
{,..,.,}
main()
{ int a[10],*p=a;
...,..
f(p,10);
}
f(int *x,int n)
{,..,.,}
main()
{ int a[10],*p=a;
...,..
f(p,10);
}
C语言程序设计 - 第 7章 指针 33
数组用作函数参数举例
? 选择排序法
5
2
8
4
6
3
? ? ? ? ?
8
2
5
4
6
3
8
6
5
4
2
3
8
6
5
4
2
3
8
6
5
4
2
3
8
6
5
4
3
2
C语言程序设计 - 第 7章 指针 34
例 1:选择排序法 (07-03.C)
void sort(int x[],int n) /* int *x */
{
int i,j,k,t;
for (i=0; i<n-1; i++) {
k = i;
for (j=i+1; j<n; j++)
if(x[j]>x[k]) k=j;
if (k!=i)
t=x[i],x[i]=x[k],x[k]=t;
}
}
C语言程序设计 - 第 7章 指针 35
例 1:选择排序法 (续 )
void main()
{
int a[10],*p,i;
p = a;
for (i=0; i<10; i++)
scanf("%d",p++);
p = a;
sort(p,10); /* sort(a,10); */
for (p=a,i=0; i<10; i++)
printf("%d",*p++);
}
C语言程序设计 - 第 7章 指针 36
指向二维数组的指针 (1)
a[0]
a[1]
a[2]
a
a+1
a+2
char a[3][4];
*a
*(a+1)
*(a+2)
a是一个长度为 3的数组
数组元素是长度为 4的数组
a,a+1,a+2都是指针,它
们的基类型是长度为 4的字
符数组,它们与下面定义的
指针 p同类型
char (*p)[4];
C语言程序设计 - 第 7章 指针 37
指向二维数组的指针 (2)
a
a+1
a+2
a[0]
a[1]
a[2]
0,0 0,1 0,2 0,3
1,0 1,1 1,2 1,3
2,0 2,1 2,2 2,3
*a
a[0]
*a+1
a[0]+1
*a+2
a[0]+2
*a+3
a[0]+3
a[2]
*(a+2)
a[2]+1
*(a+2)+1
a[1]+3
*(a+1)+3
a[1][3]
*(*(a+1)+3)
a[1]
*(a+1)
a[2][3]
*(*(a+2)+3)
a[0][3]
*(*a+3)
char *
char
char *
基类型为
char[4]
的指针
C语言程序设计 - 第 7章 指针 38
指向二维数组的指针总结
? 表示二维数组
?a:指向二维数组的指针类型
? 表示第 i行
?a[i],*(a+i):指向一维数组的指针类型
? 表示第 i行 j列的元素
?a[i][j],*(*(a+i)+j)
?*(a[i]+j),(*(a+i))[j],char类型
? 注意 a和 *a都是指针,但是基类型不同
? 注意 *(a+i)和 *a+i的区别
C语言程序设计 - 第 7章 指针 39
指向二维数组的指针变量
? 指向数组元素的指针变量
?指向二维数组的元素
?类型为 char *p;
?根据一维数组元素和二维数组元素的对应关
系,可以访问所有的二维数组元素
? 基类型为一维数组的指针变量
?指向二维数组的行
?类型为 char (*p)[4];
?把每一行作为一个一维数组来处理
C语言程序设计 - 第 7章 指针 40
指向二维数组元素的指针变量
? 一维数组与二维数组
char a[M][N]; ? char a[M*N];
a[i][j] ? a[i*N+j]
? 使用指向元素的指针访问二维数组元素
char a[M][N];
char *p=a[0]; /* p=*a; */
则 p[i*N+j],*(p+i*N+j),a[i][j]
表示二维数组第 i行 j列的元素
C语言程序设计 - 第 7章 指针 41
指向二维数组的行的指针变量
? 二维数组是基类型为一维数组的指针
?可以使用与二维数组同类型的指针变量
? 使用指向行的指针访问二维数组元素
int a[M][N];
int (*p)[N]=a; /* p=a; */
则 p[i],*(p+i),a[i]表示数组的第 i行
且 p[i][j],*(*(p+i)+j),*(p[i]+j)、
(*(p+i))[j]表示二维数组第 i行 j列的元素
C语言程序设计 - 第 7章 指针 42
二维数组的指针作函数参数
? 二维数组的地址也可以用作函数参数
?用指向数组元素的指针作为参数
?用指向二维数组的行的指针作为参数
? 举例
void foo(int *p,int n);
void bar(int (*p)[4],int n);
int a[3][4]; /* 定义二维数组 */
foo(*a,12); /* 二维数组的行作为参数 */
bar(a,3); /* 二维数组名作为参数 */
C语言程序设计 - 第 7章 指针 43
指向字符串的指针
? 指针指向存放字符串的字符数组
?与前述,指向数组的指针,类似
? 直接用字符指针指向字符串
?字符串常量按字符数组处理,在存储器中占
有一定的空间,并有自己的地址 (指针 )
?可以把字符串常量的地址赋给字符指针变量
?通过这个字符指针变量可以修改字符串常量
?两个内容完全一样的字符串常量,在存储器
中是不同的字符串,具有不同的存储空间
C语言程序设计 - 第 7章 指针 44
直接用字符指针指向字符串
? 可以用字符指针直接指向字符串常量
? 可以用字符串常量对字符指针直接赋值
? 这是把字符串常量的 地址 赋给字符指针
? 而不是把字符串的 内容 赋给字符指针
? 使用字符指针可以修改字符串的内容
? 只有利用指针才能再次访问某字符串常量
? 注意防止越过原字符串常量的范围
? 注意字符串末尾应保留结束标志 '\0'
C语言程序设计 - 第 7章 指针 45
字符串指针举例
char *s="I love";
char *t;
t = "China!";
s[0] = 'U';
puts(s); /* U love */
s[6] = '~';
puts(s);
/* U love~China! */
s[12] ='~';
puts(t); /* China~ */
I
?
l
o
v
e
\0
C
h
i
n
a
!
\0
s s[0]
s[6]
t
s[12]
U
~
~
C语言程序设计 - 第 7章 指针 46
字符串指针作函数参数举例
void strcpy(char *s,char *t)
{
while(*t++=*s++); /* 逐个字符复制 */
}
void main()
{
char *str1="C Language",str2[20];
strcpy(str1,str2);
puts(str2); /* C Language */
}
C语言程序设计 - 第 7章 指针 47
字符数组和字符指针变量比较 (1)
? 定义
?char astr[]="Hello,World!";
?char *pstr="Hello,World!";
? 数组在定义时分配存放若干字符的空间
? 指针定义时只分配存放一个地址的空间
Hello,World!\0pstr:
Hello,World!\0astr:
C语言程序设计 - 第 7章 指针 48
字符数组和字符指针变量比较 (2)
? 数组可以直接使用
? 指针要先指向一个字符串后才能使用
? 字符串常量只能对数组赋初值,把字符
串的各个字符放到数组中,并且不能在
其他场合对数组整体赋值
? 指针可以用字符串常量或字符数组任意
赋值,但只是把字符串的地址赋给指针
? 数组名的值不能修改
? 指针可以任意修改
C语言程序设计 - 第 7章 指针 49
指向函数的指针
? 函数的指令存储在内存中的一段空间中
? 函数也有相应的内存地址
? 函数的入口地址就是函数的指针
? 函数名代表函数的入口地址
? 函数的指针可以用相应类型的指针变量
表示,即指向函数的指针变量
? 函数也可以用通过指针变量间接调用
C语言程序设计 - 第 7章 指针 50
指向函数的指针变量
? 定义形式
?类型 (*变量名 )([参数类型列表 ]);
? 说明
?与函数原型类似,函数名用 (*变量名 )代替
?“参数类型列表”可以省略,但一般不要省
略
?主要用于函数的参数
?先赋值,后使用,一般用同类型函数名赋值
?不能进行算术运算和关系运算
C语言程序设计 - 第 7章 指针 51
指向函数的指针变量使用举例
int max(int x,int y)
{ return x>y?x:y; }
void main()
{
int (*p)(int,int); /* 定义指针变量 */
int a,b,c;
scanf("%d%d",&a,&b);
p = max; /* 用函数名赋值 */
c = (*p)(a,b); /* c=max(a,b); */
}
C语言程序设计 - 第 7章 指针 52
指向函数的指针用作函数参数举例
? 一元函数定积分的梯形法数值求解
O x
f ( x )
a
b
h
?
?
?
?
?
?
????
???
?
?
??
?
?
2
)(
)(
2
)(
)(
1
1
bf
xf
af
hdxxf
hiax
n
ab
h
n
i
i
b
a
i
C语言程序设计 - 第 7章 指针 53
例:一元函数定积分 (07-04.C)
double integral(double (*f)(double),
double a,double b)
{
double s,h;
int n=100,i;
h = (b-a)/n;
s = ((*f)(a)+(*f)(b))/2.0;
for(i=1; i<n; i++)
s += (*f)(a+i*h);
return s*h;
}
C语言程序设计 - 第 7章 指针 54
例:一元函数定积分 (续 )
#include <stdio.h>
#include <math.h>
void main()
{
double y1,y2,y3;
y1 = integral(sin,0.0,1.0);
y2 = integral(cos,0.0,2.0);
y3 = integral(exp,0.0,3.5);
printf("%lf\n%lf\n%lf\n",y1,y2,y3);
}
C语言程序设计 - 第 7章 指针 55
返回指针值的函数
? 函数的返回值可以是指针类型
? 定义形式
?类型 *函数名 (参数列表 );
? 举例
?int *foo(int x,int y);
? 说明
?函数调用可以结合使用 *和 []运算符
?注意与指向函数的指针区别
int (*foo)(int x,int y);
C语言程序设计 - 第 7章 指针 56
返回指针值的函数举例 (1)
int *f(int *px,int *py) /* 返回整型指针 */
{
return *px>*py?px:py; /* 较大数的地址 */
}
void main()
{
int a=2,b=3,c=9;
*f(&a,&b)=c; /* 赋值给 a和 b中较大的数 */
printf("%d\n",b); /* 输出 9 */
}
C语言程序设计 - 第 7章 指针 57
返回指针值的函数举例 (2)
int *f(int *a,int *b) /* 返回整型指针 */
{
return *a>*b?a:b; /* 返回第一个元素 */
} /* 较大的数组地址 */
void main()
{
int i,a[]={1,2,3,4},b[]={5,6,7,8};
for (i=0; i<4; i++)
printf("%d\n",f(a,b)[i]);
} /* 打印数组 b的元素 */
C语言程序设计 - 第 7章 指针 58
指针数组和指向指针的指针
? 指针数组
?类型 *数组名 [长度 ];
?元素是指针类型的数组
?举例,char *p[4];
?注意与基类型为数组的指针区分
char (*p)[4];
? 指向指针的指针
?基类型为指针类型的指针
?举例,char **p;
C语言程序设计 - 第 7章 指针 59
指针数组举例
/* 把所有名字的所有字母全部改成大写 */
void main()
{
char *name[]={"Tom","John","Kate"};
int i,j;
for (i=0; i<3; i++)
for (j=0; *(name[i]+j); j++)
if (name[i][j]>='a' &&
name[i][j]<='z')
name[i][j]-=32;
}
C语言程序设计 - 第 7章 指针 60
指向指针的指针举例
/* 利用指向字符指针的指针打印字符串数组 */
void main()
{
char *name[]={"Tom","John","Kate"};
char **p;
int i;
p = name;
for (i=0; i<3; i++)
printf("%s\n",*p++);
}
C语言程序设计 - 第 7章 指针 61
命令行参数
? main函数的几种形式
? int main();
? int main(int argc,char *argv[]);
? int main(int argc,char **argv);
? 说明
?返回值类型一般为 int,也可以是其他类型
?argc为命令行参数的个数
?argv为命令行参数字符串数组
?命令行参数包括文件名本身
C语言程序设计 - 第 7章 指针 62
命令行参数举例 — echo命令
>echo C Language
argc == 3;
argv[0] == "echo";
argv[1] == "C";
argv[2] == "Language";
#include <stdio.h>
int main(int argc,char *argv[])
{
while(--argc > 0)
printf("%s%c",*++argv,(argc>1)?' ':'\n');
return 0;
}
C语言程序设计 - 第 7章 指针 63
复杂的声明形式
? 复杂类型变量的声明容易混淆
?指针数组和指向数组的指针
int *a[5]; int (*a)[5];
?指向函数的指针和返回指针值的函数
void (*f)(); void *f();
? 过于复杂的声明形式使程序晦涩难懂,
而且容易出错
? 可以用 typedef关键字把复杂类型的变
量声明用若干个容易理解的小步骤表示
C语言程序设计 - 第 7章 指针 64
分析声明形式的方法
? 从标识符开始,逐层分析其意义
? 按运算符优先级和结合方向的顺序进行
? 可能涉及的运算符包括
? ()自左向右结合
改变结合顺序;或声明一个函数,向外一层是函数
返回值类型声明
? []自左向右结合
声明一个数组,向外一层是数组元素类型声明
? * 自右向左结合
声明一个指针类型,向外一层是指针基类型声明
C语言程序设计 - 第 7章 指针 65
声明形式分析举例
char (*(*x[3])())[5];
x是一个长度为 3的数组
数组的元素是指针类型
指针是指向函数的
函数的返回值是指针类型
指向长度为 5的字符数组
x is an array[3] of pointer to function
returning pointer to array[5] of char
C语言程序设计 - 第 7章 指针 66
void类型指针
? 定义形式
?void *p;
? 说明
?定义一个指针,但不指定它指向的数据类型
?不能通过 *p引用它指向的数据
?void*指针可以与其他任何类型的指针相互
赋值和比较,而不需要显式的强制类型转换
?经常作为函数形参和返回值的类型
C语言程序设计 - 第 7章 指针 67
结束
The End