📄 tc12.dat
字号:
第9章 指 针(下)
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()函数:判断是否有不合格成绩 */
/*形参:指向由3个int型元素组成的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 grade list: ”, 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_row+j)是一个数据(数组元素grade[i][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[i],name[i]=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[i]);
} [程序演示]
程序运行结果:
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.实参的来源
运行带形参的主函数,必须在操作系统状态下,输入主函数所在的可执行文件名,以及所需的实参,然后回车即可.
命令行的一般格式为:
可执行文件名
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -