? 第一章 C语言概述
? 第二章 数据类型、运算符与表达式
? 第三章 最简单的 C程序设计
? 第四章 逻辑运算和判断选取控制
? 第五章 循环控制
? 第六章 数组
? 第八章 编译预处理
? 第九章 指针
? 第十章 结构体与共用体
? 第十二章 文件的基本操作
? 第十三章 位运算
§ 9.4 字符串指针和
指向字符串的指针变量
一、字符串指针的定义
例, #include <stdio.h>
main( )
{ char ?p;
char s[ ]="I am a student!" ;
p=s;
printf("p=%s",p);}
形式 char ?p;
表示 p为指针变量,可指向一个字符串的首地址。
运行结果为,p=I am a student!
可以在定义的时候赋初值,
main( )
{ char ?p="I am a student!";

或者,main ( )
{ char ?p;
p="I am a student!";

则,?p代表 I ?(p+3)代表 m
1,― …‖ 一个串名代表示该串的首地址
2,在输入 (scanf)和输出 (printf)中,也可用 %s
将整个串一次输入 /输出
例,将字符串 a复制到字符串 b
1)用字符数组实现
1) main ( )
{ char a[ ]="I am a teacher!";
char b[20];
int i;
for (i=0; ?(a+i)!=' \0'; i++)
?(b+i)= ?(a+i);
?(b+i)= ' \0';
printf("string a is,%s\n",a);
printf("string b is:");
for (i=0; b[i]= ' \0'; i++)
printf("%c",b[i]);
printf("\n");
}
等价于,
printf("string b is,%s\n",b);
运行结果,
string a is,I am a teacher!
string b is,I am a teacher!
main ( )
{ char a[ ]= "I am a teacher!";
char b[20],?p1,?p2;
p1=a; p2=b;
for (; ?p1!='\0'; p1++,p2++)
?p2= ?p1;
?p2= ' \0';
printf("string a is,%s\n",p1);
printf("string b is,%s\n",p2);
}
2) 用指针变量实现
运行结果,
string a is, I am a teacher!
string b is, I am a teacher!
请思考:对上面的程序作如下改变,
main ( )
{ char a[ ]="I am a teacher";
char b[20],*p1,*p2;
p1=a;
p2=b;
p2=p1;
则 b数组中的内容是否已复制了 a数组中的内容
结论,
p1=a;
p2=a;
p1?a;
p2?b;
p1?a;
p2
p2=p1后 ;
b
二、字符串指针作函数参数
例, 用函数调用实现字符串的复制
与数值变量指针一样,字符串指针,字符串数
组均可作为函数参数
作用,可在函数中改变实参内容。
方法, (1)字符数组作参数
void copy_string (from,to)
char from[ ],to[ ];
{ int i=0;
while (from[i]!='\0')
{to[i]=from[i]; i++}
to[i]='\0 ';
}
main ( )
{char a[ ]="I am a teacher";
char b[ ]="You are a student";
printf("string_a=%s\n string_b=%s\n",a,b);
copy_string(a,b);
printf("\n string_a=%s\n string_b=%s\n",a,b)
}
运行结果, string_a=I am a teacher
string_b=You are a student
string_a=I am a teacher
string_b=I am a teacher
可以在 main中使用字符串指针,
char ?a="I am a teacher".;
char ?b="You are a student."

但以字符串的方式输出 b中内容时,遇到第一
个 '\0'时结束。
实际上,数组 b中的内容为,
I a m a t e a c h e r \0 n t \0
(2) 形参用字符指针变量
void copy_string (from,to)
char ?from,?to;
{ for (; ?from!='\0 '; from ++,to++)
?to = ?from;
?to = ' \0 ';
}
或,将 for改用 while
while (?from!= ' \0 ' )
{?to= ?from; to++;
from++;}
或, while((?to = ?from)!='\0') {from++;to++;}
或, while ( (?to++ = ?from++)!= '\0' );
实际上 '\0'的 ASCII码为 0,故可将
while ((?to ++ = ?from++)!=0)
简化为, while (?to++ = ?from++)
字符数组作参数的实、形参调用的四种情况
实参 形参
数组名 数组名
数组名 指针型
指针型 指针型 ……
指针型 数组名
小结,
三、字符数组与字符指针变量
?若用指针变量,即可将整个字符串赋给指针名,
char ?a
a= "Good Morning! ";
前面介绍中,字符数组与字符指针变量在使用
中具有一定的统一性,但它们之间仍有以下区别,
1,赋值方式不同,
?对字符数组只能对各个元素赋值,不可将整个
串赋给数组名,
即,char a[14];
a ="Good Morning! "; —是错误的
2,定义数组后,系统给它分配内存单元。具有确
定的内存地址,但指针变量定义后,若未对它赋地
址,则它并不指向任何单元。
如果, char ?a;
scanf("%s",a);
则,系统十分危险,由于 a可能指向一个系统
单元,因此,就会破坏该单元的值。
应改为, char str[10],?a;
a=&str[0]; 或 a=str;
scanf("%s",a);
3,指针变量的值可以改变,而数组名 (首地址 )是不
可改变的,即:在程序中不可直接对数组名赋值。
下面的用法不允许,
char str[ ]="Good! ";
str=str+7; ?
4,指针变量在确定了值后,可以采用数组元素的
方法引用指向的值,
char a[ ]="Good";
char ?b=&a[0];
printf("%c",b[2]),
5,可用指针变量 (代表一个字符串 )存放格式控制序
列,即,
char ?format
format="a=%d,b=%f \n";
printf(format,a,b);
?
当然,format也可为一数组,但赋值时不如指
针变量那样方便。
§ 9.5 函数的指针及
指向函数的指针变量
基本概念,前面已述, 每一个变量有地址, 于
是可用一个指针变量来保存, 而一个函数实际上为
存放在内存中的一段程序, 它有一个入口地址 ––––
称为函数的指针 。
存放函数指针的变量 –––指向函数的指针变量。
一、用函数指针变量调用函数
1,函数指针变量的定义
形式,类型标识符 (?变量名 ) ( )
例, int (?p) ( );
表示 p为一个函数指针变量,用于存放一个函
数的入口地址,但该函数的返回值必须为 int型。
2,给函数指针变量赋值
函数指针变量=函数名;
它不是实参,不是调用,而是将入口地址赋给
该变量。
3,通过函数指针变量调用函数的方法
(?函数指针变量名 ) (实参表列 )
例,求 a,b中最大者函数。
int max(x,y)
int x,y;
{ int z;
z=(x>y)? x:y;
return(z);
}
main ( )
{ int max( );
int (?p)( );
int a,b,c;
p=max;
scanf("a=%d,b=%d",&a,&b);
c=(?p) (a,b)
printf("max value=%d",c)
/*将 p指向函数 max*/
/*调用函数 */
二、函数指针变量作为函数参数
意义,当一个函数被调用后,执行过程中可以
根据实参的函数名来调用不同的函数。
前面介绍过,简单变量、数组名、指针变量均可
作为函数的参数。
可以用函数指针变量作为函数的参数。
例, sub (x1,x2)
int (?x1 )( ),(?x2 )( );
{ int a,b,i,j;
a=(?x1) (i);
b=(?x2) (i,j)
?
}
于是,可用 sub(f1,f2)或
sub(f3,f4)调用 sub,表
示执行 sub时,根据实
参传递过来的函数入口
地址而调用 f1,f2或 f3,f4,
例 2,设计一个函数 process,每次实现不同的功能,
当用不同的函数名作实参调用 process时,process再
去调用相应的函数。
程序如下,
#include <stdio.h>
main ( )
{int max( ),min( ),add( );
int a,b;
printf("enter a and b:");
scanf("%d,%d",&a,&b);
printf("max=");
process(a,b,max);
printf("min=")
process(a,b,min);
printf("sum=");
process(a,b,add);
}
max(x,y)
int x,y;
{int z;
if (x>y) z=x;
else z=y;
return(z);
}
min(x,y)
int x,y;
{int z;
if (x<y) z=x;
else z=y;
return(z);
}
add(x,y)
int x,y;
{int z;
z=x+y;
return(z);
}
process (x,y,fun)
int x,y;
int (* fun) ( );
{int result;
result=(*fun) (x,y);
printf("%d\n",result);
}
注,当用函数名作参数时,不论函数返值类型如
何均应作说明,以与变量名相区别。
运行情况如下,
enter a and b:2,6?
max=6
min=2
sum=8
§ 9.6 返回指针值的函数
既然函数返回值可以是整、实型等数据。当
然也可以是指针值,只是函数定义形式略有不同,
例,有若干个学生的成绩 (每个学生有 4门课程 ),
要求在用户输入学生序号以后, 能输出该学生的
全部成绩 。 用指针函数来实现 。
类型标识符 ?函数名 (形参表列 )
float *search (float(*pointer[4],int n););
float *p;
int i,m;
printf("enter the number of student:");
scanf("%d",&m);
printf("The scores of No,%d are,\n",m);
程序如下,
{static float score [ ] [4]={{60,70,80,90},
{56,89,67,88},
{34,78,90,66}};
main ( )
p=search (score,m); /*函数调用 */
for (i=0; i<4; i++)
printf("%5.2f\t",* (p+i));
}
float * seaarch (pointer,n) /*返回指针值的函数 */
float (* pointer) [4];
int n;
{float * pt;
pt= * (pointer +n);
return (pt);
}
运行情况如下,
enter the number of student,1?
The scores of No,1 are,
56.00 89.00 67.00 88.00
§ 9.7 指针数组
和指向指针的指针
一、指针数组
1,定义形式
类型说明符 ?数组名 [常量 ]
数组 –––同种类型的数据集合。
当每一个元素均为指针类型数据时,该数组
被称为指针数组。
例, int ?p[10];
p为指针型数组,其每一个元素为一指针型变
量。用来存入一组地址。
灵活。
? 字符串长度不一,于是只得以最长字符串的
长度作为二维数组列数,造成空间浪费。
一般情况下,存放一组字符串,如一组书名,也
可用二维字符数组存放,但存在二个问题,
2,优越性
如,存放一组字符串
如,A p p l i c a t i o n o f c o m p u t e r \0
E n g l i s h \0
用指针数组 (一维 )保存各字符串首地址,且
交换时只需交换指针数组各元素 ––首地址即可解
决上述二个问题。
? 在对字符串排序时,若交换数组元素,时间
太长。
例,将若干字符串按字母顺序 (由小到大 )输出。
#include <stdio.h>
#include <string.h>
main ( )
{void sort ( );
void print ( );
static char * name[ ]={"Follow me","BASIC","Great Wall","FORTRAN",
"Computer design"};
int i; n=5;
sort (name,n);
print(name,n);
}
printf("Before sort:\n");
for (i=0; i<5; i++)
printf("mane[%d]=%s\n",i,name[i]);
void sort (name,n)
char *name [ ]; int n;
{char *temp;
int i,j,k;
for (i=0; i<n- 1; i++)
{k=i;
for (j=i+1; j<n; j++)
if (strcmp (name [k],name[j])>0) k=j;
if (k ! =i)
{ temp=name[i],
name[i]=name[k];
name[k]=temp;}
}
}
}
void print (name,n)
char * name[ ];
int n;
{int i;
printf("After sort:\n");
for (i=0; i<n; i++)
printf ("name[%d]=%s\n",i,name[i]);
}
运行结果为,
Before sort,
name[1]=BASIC
name[2]=Great Wall
name[3]=FORTRAN
name[4]=Computer design
After sort,
name[1]=Computer design
name[2]=FORTRAN
name[3]=Follow me
name[4]=Great Wall
name[0]=Follow me
name[0]=BASIC
一个数据变量有地址,可用一指针变量来存放
该地址。那么一指针变量也有地址,可否用另一个
指针变量来存放?回答是肯定的。
&p &x
pp p x
定义形式, int ?p,??pp;
二、指向指针的指针
将指针变量的概念深化,
例,main( )
{ static char * name [ ]={"Follow me","BASIC",
"Great Wall","FORTRAN","Computer design"};
char * * p;
int i;
for (i=0; i<5; i++)
{p=name+i;
printf ("%s\n",* p);}
}
运行结果如下,
Follow me
BASIC
Great Wall
FORTRAN
Computer design
name[1]
name[0]
name[2]
name[3]
name[4]
a[1]=3
a[0]=1
a[2]=5
a[3]=7
a[4]=9
p
注意,一组字符串只能用指针数组存放,
char ?name[ ]={"Good","Bad ","Are ","Teacher ",};
于是每一个元素 name[i]为字符串指针变量
char ??p;
p=&name[i]; 或 p=name+i;
则, ?p就表示第 i个字符串的首地址,可用 ?p输出
字符串,指向指针的指针称为二级间接访问。如:
int x,?p,??pp;
则 p=&x; pp=&p; 则 ??pp表示 x
三、指针数组作 main( )函数的形式,
那么它的实参从何而来?实参代表的含义是什么?
观察 DOS系统下的一种命令,
c:\> copy FILE1.C FILE2.C
main( )既可为无参函数,也可为有参函数
有参函数形式,
main (argc,argv)
int argc;
char ?argv[ ];

其中, copy为命令 FILE1.C 和 FILE2.C为其参数。
对于一个在 DOS下运行的 C程序,也可以给
一些参数,
如,c:> pop 参数 1 参数 2 … 参数 n–1?
当以这种方式运行 C程序,则 argc?n,argv为指针数
组,每一个元素指向包含命令在内的 n个字符串。
即, argv[0]?"pop"
argv[1]? "参数 1"

argv[n –1] ? "参数 n –1 "
#include <stdio.h>
main (argc,argv)
int argc;
char ?argv[ ];
{ printf("argc=%d",argc);
while (argc>1)
{ ++argv;
printf("%s\n",?argv);
– – argc;
}
}
例,编写 main( )函数,将后面的参数输出,
上述文件设为 file1 则运行时
file1 China Beijing Changsha?
argc=4
China
Beijing
Changsha