首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

C基础教程 第十一章 指 针(下)

C基础教程 第十一章 指 针(下)

9.4
字符串的指针和指向字符串的指针变量

字符串在内存中的起始地址称为字符串的指针,可以定义一个字符指针变量指向一个字符串。

9.4.1
字符串的表示与引用

在C语言中,既可以用字符数组表示字符串,也可用字符指针变量来表示;引用时,既可以逐个字符引用,也可以整体引用。

1.逐个引用

[案例9.8] 使用字符指针变量表示和引用字符串。

/*案例代码文件名:AL9_8.C*/

main()


{char *string=”I love Beijing.”;


for(; *string!=’\0’; string++) printf(“%c”, *string);


printf(“\n”);


}


程序运行结果:


I love Beijing.

程序说明:char*string="I love Beijing.";语句

定义并初始化字符指针变量string:用串常量“I love Beijing.”的地址(由系统自动开辟、存储串常量的内存块的首地址)给string赋初值。

该语句也可分成如下所示的两条语句:


char*string


string="I love Beijing."

注意:字符指针变量string中,仅存储串常量的地址,而串常量的内容(即字符串本身),是存储在由系统自动开辟的内存块中,并在串尾添加一个结束标志’\0’。

2.整体引用

[案例9.9] 采取整体引用的办法,改写[案例9.8]

/*案例代码文件名:AL9_9.C*/

/*程序功能:使用字符指针变量表示和引用字符串*/

main()


{char *string=”I love Beijing.”;


printf(“%s\n”,string);


}
[程序演示]

程序说明:printf("%s\n",string);语句

通过指向字符串的指针变量string,整体引用它所指向的字符串的原理:系统首先输出string指向的第一个字符,然后使string自动加1,使之指向下一个字符;重复上述过程,直至遇到字符串结束标志。

注意:其它类型的数组,是不能用数组名来一次性输出它的全部元素的,只能逐个元素输出。

例如:


int array[10]={……};


......


printf("%d\n",array);
/*这种用法是非法的*/


......

3.字符指针变量与字符数组之比较

虽然用字符指针变量和字符数组都能实现字符串的存储和处理,但二者是有区别的,不能混为一谈。

1)存储内容不同。

字符指针变量中存储的是字符串的首地址,而字符数组中存储的是字符串本身(数组的每个元素存放一个字符)。

2)赋值方式不同。

对字符指针变量,可采用下面的赋值语句赋值:


char
*pointer;


pointer="This is a example.";

而字符数组,虽然可以在定义时初始化,但不能用赋值语句整体赋值。下面的用法是非法的:


char
char_array[20]


char_array="This is a example.";
/*非法用法*/

3)指针变量的值是可以改变的,字符指针变量也不例外;而数组名代表数组的起始地址,是一个常量,而常量是不能被改变的。

9.4.2
字符串指针作函数参数

[案例9.10] 用函数调用方式,实现字符串的复制。

/*案例代码文件名:AL9_10.C*/

/**********************************************************/

/*string_copy()函数:复制一个字符串
*/

/*形参:字符指针str_from接收源串,字符指针 str_to存储目标串 */

/*返回值:无
*/

/**********************************************************/

void string_copy(char *str_from, char*str_to)


{int i=0;


for(; (*(str_to+i)=*(str_from+i))!=\0; i++) ; /*循环体为空语句*/


}

main()


{char array_str1[20]=”I am a teacher.”;


char array_str2[20];


string_copy(array_str1, array_str2); /*数组名作实参*/


printf(“array_str2=%s\n”, array_str2);


}

程序运行结果:


I am a teacher.

程序说明:for(;(*(str_to+i)=*(str_from+i))!=\0; i++) ;

语句的执行过程为:首先将源串中的当前字符,复制到目标串中;然后判断该字符(即赋值表达式的值)是否是结束标志。如果不是,则相对位置变量i的值增1,以便复制下一个字符;如果是结束标志,则结束循环。其特点是:先复制、后判断,循环结束前,结束标志已经复制。

C语言中,用赋值运算符、而不是赋值语句来实现赋值操作,能给某些处理带来很大的灵活性,该语句(实现字符串的复制)的用法就是最好的例证。

9.5
返回指针值的函数


一个函数可以返回一个int型、float型、char型的数据,也可以返回一个指针类型的数据。 返回指针值的函数(简称指针函数)的定义格式如下:


函数类型
*函数名([形参表])




[案例9.11] 某数理化三项竞赛训练组有3个人,找出其中至少有一项成绩不合格者。要求使用指针函数实现。
/*案例代码文件名:AL9_11.C*/

/*************************************************************/
/*seek()函数:判断是否有不合格成绩
*/
/*形参:指向由3int型元素组成的1维数组的行指针变量
*/
/*返回值:(1)有不合格成绩,则返回指向本行首列的一个()指针;
*/
/*
(2)没有有不合格成绩,返回值为指向下一行的一个()指针 */
/*************************************************************/

int
*seek( int
(*pnt_row)[3] )


{int i=0, *pnt_col;
/*定义一个()指针变量pnt_col */


pnt_col=*(pnt_row+1);
/*使pnt_col指向下一行之首(作标志用)*/


for(; i<3; i++)


if(*(*pnt_row+i)<60)
/*某项成绩不合格*/


{ pnt_col=*pnt_row; /*使pnt_col指向本行之首*/


break;
/*退出循环*/


}


return(pnt_col);


}

/*主函数main()*/

main()


{int grade[3][3]={{55,65,75},{65,75,85},{75,80,90}};


int i,j,*pointer;
/*定义一个()指针变量pointer */


for(i=0; i<3; i++)
/*控制每个学生*/


{ pointer=seek(grade+i);
/*用行指针作实参,调用seek()函数*/


if(pointer==*(grade+i))
/*该学生至少有一项成绩不合格*/


{ /*输出该学生的序号和各项成绩*/


printf(“No.%d gradelist: ”, i+1);


for(j=0; j<3; j++)printf(“%d
”,*(pointer+j));


printf(“\n”);


}


}


}
[程序演示]

程序运行结果:

No.1 grade list: 55
65
75

程序说明:

1主函数中的pointer=seek(grade+i);语句

调用seek()函数时,将实参grade+i(行指针)的值,复制到形参pnt_row(行指针变量)中,使形参pnt_row指向grade数组的第i行。

2)在指针函数seek()中:


1 pnt_col=*(pnt_row+1);语句

*(pnt_row+1)将行指针转换为列指针,指向grade数组的第i+1行第0列,并赋值给(列)指针变量pnt_col

2 if(*(*pnt_row+i)<60)

pnt_row是一个行指针,指向数组grade的第i行;*pnt_row使指针由行转换为列,指向数组grade的第i行0列;*pnt_row+j的值还是一个指针,指向数组的第i行第j列;*(*pnt_rowj)是一个数据(数组元素grade[j]的值)。

9.6
指针数组与主函数main()的形参

9.6.1
指针数组

1.概念

数组的每个元素都是一个指针数据。指针数组比较适合用于指向多个字符串,使字符串处理更加方便、灵活。

2.定义格式


数据类型
*数组名[元素个数]

注意:与行指针变量定义格式“<数据类型>(*行指针变量)[<元素个数>]”的差别。



[案例9.12] 有若干计算机图书,请按字母顺序,从小到大输出书名。解题要求:使用排序函数完成排序,在主函数中进行输入输出。
/*案例代码文件名:AL9_12.C*/
/*程序功能:指针数组应用示例*/

/***********************************************/

/* sort()函数:对字符指针数组进行排序
*/

/*形参:name--字符指针数组,count--元素个数*/

/*返回值:无
*/

/***********************************************/

void
sort(char *name[], int count)


{char *temp_p;


int i,j,min;


/*使用选择法排序*/


for(i=0; i<count-1; i++)
/*外循环:控制选择次数*/


{ min=i;
/*预置本次最小串的位置*/


for(j=i+1; j<count; j++)
/*内循环:选出本次的最小串*/


if(strcmp(name[min],name[j])>0)
/*存在更小的串*/


min=j;
/*保存之*/


if(min!=i)
/*存在更小的串,交换位置*/


temp_p=name,name=name[min],name[min]=temp_p;


}


}

/*主函数main()*/

main()


{char *name[5]={“BASIC”,”FORTRAN”,”PASCAL”,”C”,”FoxBASE”};


int i=0;


sort(name,5);
/*使用字符指针数组名作实参,调用排序函数sort()*/


/*输出排序结果*/


for(; i<5; i++) printf(“%s\n”,name);


}
[程序演示]

程序运行结果:

BASIC

C

FORTRAN

FoxBASE

PASCAL

程序说明:

1)实参对形参的值传递:


sort(
name
,
5 )





void sort(char *name[], int count)

2)字符串的比较只能使用strcmp()函数。形参字符指针数组name的每个元素,都是一个指向字符串的指针,所以有strcmp(name[min],name[j])

9.6.2
主函数main()的形参

在以往的程序中,主函数main()都使用其无参形式。实际上,主函数main()也是可以指定形参的。

[案例9.13] 用同一程序实现文件的加密和解密。约定:程序的可执行文件名为lock.exe 其用法为:lock +|- <被处理的文件名>,其中“+”为加密,“-”为解密。

/*案例代码文件名:AL9_13.C*/

/*程序功能:带参主函数的应用示例*/

main(int argc, char *argv[])


{char c;


if (argc != 3) printf("参数个数不对!\n");


else


{ c=*argv[1];
/*截取第二个实参字符串的第一个字符*/


switch(c)


{ case '+':
/*执行加密*/


{ /*加密程序段*/



printf("执行加密程序段。\n");


}


break;


case '-':
/*执行解密*/


{ /*解密程序段*/


printf("执行解密程序段。\n");


}


break;


default: printf("第二个参数错误!\n");


}


}

}


1.主函数main()的有参形式


main(int argc char *argv[])


{ … …}

2.实参的来源

运行带形参的主函数,必须在操作系统状态下,输入主函数所在的可执行文件名,以及所需的实参,然后回车即可。

命令行的一般格式为:


可执行文件名实参[
实参2……]

例如,本案例程序的用法:lock
+|-
<被处理的文件名>←┘

●在TC的集成环境下,也可直接利用Options | Arguments 项,输入主函数所需要的实参:只须输入各参数(相邻参数间用空格分开),可执行文件名可省略。

就本案例而言,输入“+|-
<被处理的文件名>”即可。

3.形参说明

1)形参argc是命令行中参数的个数(可执行文件名本身也算一个)。

在本案例中,形参argc的值为3lock+|-、文件名)。

2)形参argv是一个字符指针数组,即形参argv首先是一个数组(元素个数为形参argc的值),其元素值都是指向实参字符串的指针。

在本案例中,元素argv[0]指向第1个实参字符串“lock”,元素argv[1] 指向第2个实参字符串“+|-”,元素argv[2]指向第3个实参字符串“被处理的文件名”。

3.形参说明

1)形参argc是命令行中参数的个数(可执行文件名本身也算一个)。

在本案例中,形参argc的值为3lock+|-、文件名)。

2)形参argv是一个字符指针数组,即形参argv首先是一个数组(元素个数为形参argc的值),其元素值都是指向实参字符串的指针。

在本案例中,元素argv[0]指向第1个实参字符串“lock”,元素argv[1] 指向第2个实参字符串“+|-”,元素argv[2]指向第3个实参字符串“被处理的文件名”。

9.6.3
指向指针的指针变量简介

[案例9.12]的主函数main()中,数组name是一个字符指针数组,即数组的每一个元素都是一个指向字符串的指针。

既然name是一个数组,则它的每一个元素也同样有相应的地址,因此可以设置一个指针变量pointer,使其指向指针数组的元素(元素的值还是一个指针),称pointer为指向指针的指针变量。显然,指向指针的指针变量是一个两级的指针变量。

1.指向指针的指针变量的定义


数据类型
**指针变量[, **指针变量2……]

2.指向指针的指针变量的赋值


指针变量 = 指针数组名 + i


9.7
函数的指针和指向函数的指针变量简介

1.函数指针的概念

一个函数在编译时,被分配了一个入口地址,这个地址就称为该函数的指针。

可以用一个指针变量指向一个函数,然后通过该指针变量调用此函数。

2.指向函数的指针变量

1)定义格式


函数类型
(*指针变量)( )

注意:“*指针变量”外的括号不能缺,否则成了返回指针值的函数。

例如,int (*fp)();
/* fp为指向int函数的指针变量*/

2)赋值

函数名代表该函数的入口地址。因此,可用函数名给指向函数的指针变量赋值。

指向函数的指针变量=[&]函数名;


注意:函数名后不能带括号和参数;函数名前的“&”符号是可选的。

(3)调用格式


(*函数指针变量)([实参表])

3.指向函数的指针变量作函数参数

指向函数的指针变量的常用用途之一,就是将函数指针作参数,传递到其它函数。

函数名作实参时,因为要缺省括号和参数,造成编译器无法判断它是一个变量还是一个函数,所以必须加以说明。函数说明的格式,与第7章中介绍的一样。

注意:对指向函数的指针变量,诸如p+ip++/p--等运算是没有意义的。
返回列表