一、字符串处理函数
字符串处理函数库提供了很多有用的函数用于字符串处理操作(如复制字符串和拼接字符串等)以及确定字符串的长度。若要使用这些字符串处理函数,必须在程序的开头将头文件<string.h>包含到源头文件。
例题1:编程实现按奥运会参赛国国名在字典中的顺序对其入场次序进行排序。假设参赛国不超过150个。
#include <stdio.h>
#include <string.h>
#define max_len 10
#define N 150
void sortstring(char str[][max_len],int n);
int main(void)
{
int i,n;
char name[N][max_len];
printf("How many countries?");
scanf("%d",&n);
getchar();
printf("Input their names:\n");
for(i=0;i<n;i++)
{
gets(name[i]);
}
sortstring(name,n);
printf("Sorted results:\n");
for(i=0;i<n;i++)
{
puts(name[i]);
}
return 0;
}
void sortstring(char str[][max_len],int n)
{
int i,j;
char temp[max_len];
for(i=0;i<n-1;i++)
{
for(j=i+1;j<n;j++)
{
if(strcmp(str[j],str[i])<0)
{
strcpy(temp,str[i]);
strcpy(str[i],str[j]);
strcpy(str[j],temp);
}
}
}
}
程序第27~43行是用交换法实现的字符串按字典顺序排序的函数。
注意:程序37~39行的字符串赋值操作不同于单个字符的赋值操作,对单个字符进行赋值操作可以使用赋值运算符,但是赋值运算符不能用于字符串的赋值操作,字符串赋值只能使用函数strcpy()。例如本例使用下面的赋值操作来替换第37-39的赋值操作就是错误的。
temp = str [i];
str[i] = str[j];
str[j] = temp;
另外,程序第35行比较字符串的方法不同于比较单个字符的方法。比较单个字符可以使用关系运算符,但比较字符串不能直接使用关系运算符。
例如,不能使用: if (str[j]<str[i])
而应使用函数strcmp()来比较字符串的大小,如本例题第35行语句所示。
字符串比大小是,实际上是根据两字符对比是出现的第一对不相等的字符的大小来决定它们所在字符串的大小。例如。字符串“American”小于“Australia”,即strcmp(“American”,“Australia”)的函数值小于0,是因为字符’m’<‘u’。再如,字符串“Hello China”大于字符串“Hello”,即strcmp(“Hello China”,“Hello”)的函数值大于0,这是因为’\0’的ASCII码值为0,其是ASCII码表中ASCII码值最小的,所以若一个字符串是另一个字符串的子串,即字符串中前面的字符都相同,那么长的字符串一定大于短的字符串。
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
那么计算机是如何直到一个特定的字母是否排在另外一个字母之前呢?其实,所有的字母在计算机中都是被表示成数字编码(Numeric Codes)的。当计算机比较字符串时,实际比较的是字符串中字符的数字编码。在不同的计算机中,表示字符的内部数字编码可能是不同的。为了使字符表示标准化,绝大多数计算机生产产商都采用主流的编码方案ASCII(American Standard Code for Information Interchange,美国信息交换标准码)或EBCDIC(Extended Binary Coded Decimal Interchange Code,扩充的二-十进制交换码)来设计它们的机器。
对于字符串和字符的操作实际上是对相应的数字编码而非字符本身的操作。这就是C语言字符和短整型数据具有可交换性的原因。既然一个数字编码大于、小于或者等于另外一个数字编码是有意义的,那么同通过数字编码就可以建立不同字符串或字符之间的关系了
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
二、向函数传递字符串
因为字符数组和字符指针都可以存取C字符串,因此,向函数传递字符串时,既可以使用字符数组作函数参数,也可以使用字符指针作函数参数。
例题2:从键盘输入一个字符串a,将字符串a复制到字符串b中,在输出字符串b,即编程实现字符串处理函数strcpy()的功能,但要求不能使用字符串处理函数strcpy()。
#include <stdio.h>
#define N 80
void mystrcpy(char datastr[],char stcstr[]);
int main(void)
{
char a[N],b[N];
printf("Input a string:");
gets(a);
mystrcpy(b,a);
printf("The copy is:");
puts(b);
return 0;
}
void mystrcpy(char datastr[],char stcstr[])
{
int i=0;
while(stcstr[i]!='\0')
{
datastr[i]=stcstr[i];
i++;
}
datastr[i]='\0';
}
用字符数编程实现字符串复制的示意图如下图所示。字符数组的下标从0开始变化(如程序第17~21行所示),控制当前复制的是字符数组srcstr中的第几个字符。
注意:与使用其他类型数组不同的是,通常不使用长度即计数控制的循环来判断数组元素是否遍历结束,而使用条件控制的循环,利用字符串结束标志’\0’判断字符串中的字符是否遍历结束(如第18行所示)。若当前取出的字符srcstr[i]不是’\0’,则继续执行第20行的字符赋值操作,否则结束循环,在datastr的末尾添加’\0’表示datastr中字符串的结束。
如果将第23行语句注释掉,那么在输出复制后的字符串时,将会在实际复制的字符后面显示出一些乱码,具体结果与系统和用户输入的字符串长度有关。
例题3:利用指针实现例题2的功能。
#include <stdio.h>
#define N 80
void mystrcpy(char *datastr,char *stcstr);
int main(void)
{
char a[N],b[N];
printf("Input a string:");
gets(a);
mystrcpy(b,a);
printf("The copy is:");
puts(b);
return 0;
}
void mystrcpy(char *datastr,char *srcstr)
{
while(*srcstr!='\0')
{
*datastr = *srcstr;
srcstr++;
datastr++;
}
*datastr='\0';
}
结果与例题2一致。
例题4:从键盘任意输入一个字符串,计算其实际字符个数并打印输出,即不适用字符串处理函数strlen()编程实现strlen()的功能。
#include <stdio.h>
#define N 89
unsigned int mystrlen(const char str[]);
int main(void)
{
char str[N];
unsigned int a;
printf("Input the str:");
gets(str);
a=mystrlen(str);
printf("The strlen is a=%d",a);
return 0;
}
unsigned int mystrlen(const char str[])
{
int i;
unsigned int len=0;
for(i=0;str[i]!='\0';i++)
{
len++;
}
return len;
}
例题4:方法2,使用指针实现。
#include <stdio.h>
#define N 89
unsigned int mystrlen(const char *str);
int main(void)
{
char str[N];
unsigned int a;
printf("Input the str:");
gets(str);
a=mystrlen(str);
printf("The strlen is a=%d",a);
return 0;
}
unsigned int mystrlen(const char *str)
{
unsigned int len=0;
for(;*str!='\0';str++)
{
len++;
}
return len;
}
本例题程序在函数mystrlen()的数组或指针形参前加上了const类型限定符,这是希望在被调函数中不会被修改数组元素的值。
当在形参类型前加上类型限定符const后,就可以保护相应的形参不会再函数体内被修改。