第九章 字符串处理
磨刀不误砍柴工
本章将要讨论的是字符串、字符串的操作方法、字符串与指针的关系。
9.1 原来如此:
许多语言在内部实现的时候,将字符串当做字符数组来处理,但不知道为什么对程序员却掩盖了这一点。
字符串常量是一个以空白符结尾的一维字符数组,例如:
char name[]={‘y’,’a’,’n’,’g’,’f’,’e’,’n’,’g’,’\0’};
但是呢,C语言允许频繁使用字符串,对字符串的初始化提供了简单易行的方法,例如,可以使用下面的方法对字符串进行初始化:
char name[]=“yangfeng”;
9.2 请看几个简单的输出字符串的例子
方法一:
#include <stdio.h>
int main(void)
{
char name[]="yangfeng";
int i=0;
while(i<=7)
{
printf("%c",name[i]);
i++;
}
}
方法二:
#include <stdio.h>
int main(void)
{
char name[]="yangfeng";
int i=0;
while(name[i]!='\0')
{
printf("%c",name[i]);
i++;
}
}
方法三:
/*利用指针来输出字符串,这种方法重点掌握一下*/
#include <stdio.h>
int main(void)
{
char name[]="yangfeng";
char *ptr;
ptr=name;
while(*ptr!='\0')
{
printf("%c",*ptr);
ptr++;
}
}
方法四:
/*但是呢,C语言提供了更简单的方法来输出字符串。这种方法也重点掌握下*/
#include <stdio.h>
int main(void)
{
char name[]="yangfeng";
printf("%s",name);
}
9.3 关于%s:
%s是输出字符串的格式说明,也可以用于从键盘接受字符输入。例如:
#include <stdio.h>
int main(void)
{
char name[25];
printf("Enter your name");
scanf("%s",name);
printf("Hello %s!",name);
}
有两点需要注意的是:
① 声明char name[25] 的时候留出了25字节的空间,注意字符串的长度不要超过字符数组的大小。
② scanf()不能接收多个单词的字符串。
9.4 因为scanf()不能接收多个单词的字符串,那么该如何解决这个问题呢?gets()函数吧!与之对应的是puts()函数。用法如下:
#include <stdio.h>
int main(void)
{
char name[25];
printf("Enter your full name:");
gets(name);
puts("Hello!");
puts(name);
system("pause");
}
要注意的是,puts()一次只能输出一个字符串,且puts()会将光标移到下一行。
9.5 保存”hello”的两种方法
方法一:直接存储在字符串中 char str[]=”hello”
方法二:存储在内存中,将内存地址赋给一个char型指针 char *q=”hello”
需要注意的是,不可以将一个字符串赋给另外一个字符串,但是可以将一个char型指针赋给另外一个char型指针。
例如:char str1[]=”Hello”;
char str2[10];
str2=str1;
这种做法是错误的。
可以如下这样做:
char *s=”Good morning”;
char *q;
q=s;
同样,定义了字符串以后,就不可以将另外一个字符串再赋给它。但是char指针可以这样做。
例题:
char *str = “hello world”;
printf(“%s\n”, str);
*str = “goodbye world”;
printf(“%s\n”, str);
代码有没有问题?
第三行*str = “goodbye world”出错,第一行中将字符串常量“hello world”的首地址给了字符指针变量str,第三行试图将“goodbye world”的首地址,通过*str的访问方式覆盖str指向的字符串常量“hello world”。这句话理解起来都比较费劲,因为这里有两个错误:
●试图向常量里写数据。
“hello world” 是字符串常量,那么这个字符串空间里的内容不能改变。
●指针变量里应该放地址,字符串都是以首地址为地址。
向一个地址里写入字符串应该使用strcpy。*str只是代表了str指向的字符串中的第一个字符,将字符串地址写入到一个字符里肯定不行。
其实,只需把*str="goodbye world"改为str="goodbye world"即可。上述说的稍显罗嗦。
9.6 每一个C编译器都提供了大量有用的字符串处理函数库,从第6点开始来讨论几个常用的函数,还是通过实例来说明在处理字符串的时候,怎样使用库函数。
9.7 strlen():该函数的功能是计算字符串中字符的个数。
#include <stdio.h>
int main(void)
{
char name[]="yang feng";
int len1,len2;
len1=strlen(name);
len2=strlen("hello yang feng");
printf("%s %d",name,len1);
printf("\n");
printf("%s %d","hello yang feng",len2);
system("pause");
}
能否自己写一个函数xstrlen(),来模拟标准库函数strlen()的功能呢?
答案当然是肯定的!
#include <stdio.h>
int xstrlen(char *);
int main(void)
{
char name[]="yang feng";
int len1,len2;
len1=xstrlen(name);
len2=xstrlen("hello yang feng");
printf("%s %d",name,len1);
printf("%s %d","hello yang fang",len2);
system("pause");
}
int xstrlen(char *s)
{
int length=0;
while(*s!='\0')
{
length++;
s++;
}
return(length);
}
9.8 strcpy():该函数的功能是将一个字符串的内容复制到另一个字符串中。
#include <stdio.h>
int main(void)
{
char source[]="hello Yangfeng";
char target[20];
strcpy(target,source);
printf("%s",source);
printf("%s",target);
system("pause");
}
同样,咱来模拟一下strcpy()函数的功能吧,将它命名为xstrcpy(),原来生活中还有这么多有意思的事情。
#include <stdio.h>
void xstrcpy(char *,char *);
int main(void)
{
char source[]="hello Yangfeng";
char target[20];
xstrcpy(target,source);
printf("%s",source);
printf("%s",target);
system("pause");
}
void xstrcpy(char *t,char *s)
{
while(*s!='\0')
{
*t=*s;
s++;
t++;
}
*t='\0';
}
注意一下,将整个源字符串复制到目标字符串时,不要忘记将’\0’也加到目标字符串中作为结束的标志。
还有一点值得注意的是,如果你了解strcpy()的标准库函数原型后,就会看到函数的原型是这样的:
strcpy(char *t,const char *s);
通过将char *s声明成const,可以是源字符串恒为常量,防止因为偶然的因素而改变源字符串。
9.9 strcat():该函数的功能是将源字符串连接到目标字符串的尾部。
#include <stdio.h>
int main(void)
{
char source[]="Yangfeng";
char target[25]="Hello!";
strcat(target,source);
printf("%s",source);
printf("\n");
printf("%s",target);
system("pause");
}
自己再设计一个函数xstrcat()来模仿strcat的功能呗!
#include <stdio.h>
void xstrcat(char *,char *);
int main(void)
{
char source[]="Yangfeng";
char target[25]="Hello!";
xstrcat(target,source);
printf("%s",source);
printf("%s",target);
system("pause");
}
void xstrcat(char *t,char *s)
{
t=t+6;
while(*s!='\0')
{
*t=*s;
s++;
t++;
}
*t='\0';
}
9.10 strcmp():该函数的功能是比较两个字符串是否相同。两个字符串会不断地对字符进行比较,直到不匹配,或者其中一个字符串到达了结尾。如果两个字符串是相同的,那么strcmp()函数的返回值为0;如果两个字符串不相等,则返回一个差值,该差值为第一对不相等字符的ASCII码值的差。
#include <stdio.h>
#include <string.h>
int main(void)
{
char string1[]="Jerry";
char string2[]="Ferry";
int i,j,k;
i=strcmp(string1,"Jerry");
j=strcmp(string1,string2);
k=strcmp(string1,"Jerry boy");
printf("%d%d%d",i,j,k);
system("pause");
}
注意,我们很少关心不匹配的准确值。常常只需要了解第一个字符串按字母顺序排列是否在第二个字符串的前面。如果是,就返回一个负数,如果不是,就返回一个正数。任何非0的返回值就表示不匹配。
9.11 二维字符数组
/*输入你的名字,然后在masterlist里查找你输入的名字是否在里面*/
#include <stdio.h>
#include <string.h>
#define FOUND 1
#define NOTFOUND 0
int main(void)
{
char masterlist[6][10]={
"beijing",
"shanghai",
"guangzhou",
"shenzhen",
"xi'an",
"yangfeng"
};
int i,flag,a;
char yourname[10];
printf("Enter your name");
scanf("%s",yourname);
flag=NOTFOUND;
for(i=0;i<=5;i++)
{
a=strcmp(&masterlist[i][0],yourname);
if(a==0)
{
printf("welcome ,you can enter the palace");
flag=FOUND;
break;
}
}
if(flag==NOTFOUND)
{
printf("sorry,you are a trespasser");
}
system("pause");
}
9.12 字符串指针数组
与二维字符数组相比,使用字符串指针的两个好处:
●可以更加有效的利用可用的内存空间。
●处理字符串方便。
/*交换beijing和shanghai,这种方法要进行十次交换*/
#include <stdio.h>
int main(void)
{
char names[6][10]={
"beijing",
"shanghai",
"guangzhou",
"shenzhen",
"xi'an",
"yangfeng"
};
int i;
char t;
printf("Original:%s%s",&names[0][0],&names[1][0]);
for(i=0;i<=9;i++)
{
t=names[1][i];
names[1][i]=names[0][i];
names[0][i]=t;
}
printf("\n");
printf("New:%s%s",&names[0][0],names[1][0]);
system("pause");
}
/*交换beijing和shanghai,这种方法简单使用。*/
#include <stdio.h>
int main(void)
{
char *names[]={
"beijing",
"shanghai",
"guangzhou",
"shenzhen",
"xi'an",
"yangfeng"
};
char *temp;
printf("Original:%s %s",names[0],names[1]);
temp=names[0];
names[0]=names[1];
names[1]=temp;
printf("\n");
printf("New:%s %s",names[0],names[1]);
system("pause");
}
例题: