c++char字符相等⽐较_C语⾔处理字符串的7个函数
C库提供了多个处理字符串的函数,ANSI-C把这些函数的原型放在string.h头⽂件中。其中最常⽤的函数有strlen()、strcat()、
strcmp()、strncmp()、strcpy()和strncpy()。另外,还有sprintf()函数,其原型在stdio.h头⽂件中。
1 strlen()函数
strlen()函数⽤于统计字符串的长度。下⾯的函数可以缩短字符串的长度,其中⽤到了strlen():
void fit(char *string, unsigned int size){ if (strlen(string) > size) string[size] = '0';}
该函数要改变字符串,所以函数头在声明形式参数string时没有使⽤const限定符。程序test_fit.c中的程序测试了fit()函数。注意代码中使
⽤了C字符串常量的串联特性。
/* test_fit.c -- try the string-shrinking function */#include #include /* contains string function prototypes */void fit(char *, unsigned int);int main(void){ char mesg[] =下⾯是该程序的输出:
Things should be as simple as possible, but not simpler.
Things should be as simple as possible
Let's look at some more of the string.
but not simpler.
fit()函数把第39个元素的逗号替换成'0'字符。puts()函数在空字符处停⽌输出,并忽略其余字符。然⽽,这些字符还在缓冲区中,下⾯的函
数调⽤把这些字符打印了出来:
puts(mesg + 39);
表达式mesg + 39是mesg[39]的地址,该地址上存储的是空格字符。所以puts()显⽰该字符并继续输出直⾄遇到原来字符串中的空字符。
下图演⽰了这⼀过程。
The puts() function and the null character.
注意
⼀些ANSI之前的系统使⽤strings.h头⽂件,⽽有些系统可能根本没有字符串头⽂件。
string.h头⽂件中包含了C字符串函数系列的原型,因此程序test_fit.c要包含该头⽂件。
2 strcat()函数
strcat()(⽤于拼接字符串)函数接受两个字符串作为参数。该函数把第2个字符串的备份附加在第1个字符串末尾,并把拼接后形成的新字符
串作为第1个字符串,第2个字符串不变。strcat()函数的类型是char *(即,指向char的指针)。strcat()函数返回第1个参数,即拼接第2个
字符串后的第1个字符串的地址。
程序str_cat.c演⽰了strcat()的⽤法。该程序还使⽤了程序清单11.10的s_gets()函数。回忆⼀下,该函数使⽤fgets()读取⼀整⾏,如果有
换⾏符,将其替换成空字符。
/* str_cat.c -- joins two strings */#include #include /* declares the strcat() function */#define SIZE 80char * s_gets(char * st, int n);int main(void){ char flower[SIZ
该程序的输出⽰例如下:
What is your favorite flower?
wonderflower
wonderflowers smell like old shoes.
s smell like old shoes.
bye
从以上输出可以看出,flower改变了,⽽addon保持不变。
3 strncat()函数
strcat()函数⽆法检查第1个数组是否能容纳第2个字符串。如果分配给第1个数组的空间不够⼤,多出来的字符溢出到相邻存储单元时就会
出问题。当然,可以⽤strlen()查看第1个数组的长度。注意,要给拼接后的字符串长度加1才够空间存放末尾的空字符。或者,⽤
strncat(),该函数的第3个参数指定了最⼤添加字符数。例如,strncat(bugs, addon, 13)将把addon字符串的内容附加给bugs,在加到
第13个字符或遇到空字符时停⽌。因此,算上空字符(⽆论哪种情况都要添加空字符),bugs数组应该⾜够⼤,以容纳原始字符串(不包含空
字符)、添加原始字符串在后⾯的13个字符和末尾的空字符。程序join_chk.c 使⽤这种⽅法,计算avaiable变量的值,⽤于表⽰允许添加的
最⼤字符数。
/* join_chk.c -- joins two strings, check size first */#include #include #define SIZE 30#define BUGSIZE 13char * s_gets(char * st, int n);int main(void){ char flower 下⾯是该程序的运⾏⽰例:
What is your favorite flower?RoseRoses smell like old shoes.What is your favorite bug?AphidAphids smell
读者可能已经注意到,strcat()和gets()类似,也会导致缓冲区溢出。为什么C11标准不废弃strcat(),只留下strncat()?为何对gets()那
么残忍?这也许是因为gets()造成的安全隐患来⾃于使⽤该程序的⼈,⽽strcat()暴露的问题是那些粗⼼的程序员造成的。⽆法控制⽤户会
进⾏什么操作,但是,可以控制你的程序做什么。C语⾔相信程序员,因此程序员有责任确保strcat()的使⽤安全。
4 strcmp()函数
假设要把⽤户的响应与已存储的字符串作⽐较,如程序nogo.c所⽰。
/* nogo.c -- will this work? */#include #define ANSWER "Grant"#define SIZE 40char * s_gets(char * st, int n);int main(void){ char try[SIZE]; puts("Who is buried
这个程序看上去没问题,但是运⾏后却不对劲。ANSWER和try都是指针,所以try !=ANSWER检查的不是两个字符串是否相等,⽽是这两
个字符串的地址是否相同。因为ANSWE和try存储在不同的位置,所以这两个地址不可能相同,因此,⽆论⽤户输⼊什么,程序都提⽰输⼊
不正确。这真让⼈沮丧。
该函数要⽐较的是字符串的内容,不是字符串的地址。读者可以⾃⼰设计⼀个函数,也可以使⽤C标准库中的strcmp()函数(⽤于字符串⽐
较)。该函数通过⽐较运算符来⽐较字符串,就像⽐较数字⼀样。如果两个字符串参数相同,该函数就返回0,否则返回⾮零值。修改后的版
本如程序compare.c 所⽰。
/* compare.c -- this will work */#include #include // declares strcmp()#define ANSWER "Grant"#define SIZE 40char * s_gets(char * st, int n);int main(void){ char
注意
由于⾮零值都为“真”,所以许多经验丰富的C程序员会把该例main()中的while循环头写成:while (strcmp(try, ANSWER))
strcmp()函数⽐较的是字符串,不是整个数组,这是⾮常好的功能。虽然数组try占⽤了40字节,⽽存储在其中的"Grant"只占⽤了6字节
(还有⼀个⽤来放空字符),strcmp()函数只会⽐较try中第1个空字符前⾯的部分。所以,可以⽤strcmp()⽐较存储在不同⼤⼩数组中的字
符串。
如果⽤户输⼊GRANT、grant或Ulysses S. Grant会怎样?程序会告知⽤户输⼊错误。希望程序更友好,必须把所有正确答案的可能性包
含其中。这⾥可以使⽤⼀些⼩技巧。例如,可以使⽤#define定义类似GRANT这样的答案,并编写⼀个函数把输⼊的内容都转换成⼤写,
就解决了⼤⼩写的问题。但是,还要考虑⼀些其他错误的形式,这些留给读者完成。
1.strcmp()的返回值
如果strcmp()⽐较的字符串不同,它会返回什么值?请看程序compback.c的程序⽰例。
/* compback.c -- strcmp returns */#include #include int main(void){ printf("strcmp("A", "A") is "); printf("%dn", strcmp("A", "A")); printf("strcmp("A", "B") is "); 在我们的系统中运⾏该程序,输出如下:
strcmp("A", "A") is 0
strcmp("A", "B") is -1
strcmp("B", "A") is 1
strcmp("C", "A") is 1
strcmp("Z", "a") is -1
strcmp("apples", "apple") is 1
strcmp()⽐较"A"和本⾝,返回0;⽐较"A"和"B",返回-1;⽐较"B"和"A",返回1。这说明,如果在字母表中第1个字符串位于第2个字符
串前⾯,strcmp()中就返回负数;反之,strcmp()则返回正数。所以,strcmp()⽐较"C"和"A",返回1。其他系统可能返回2,即两者的
ASCII码之差。ASCII标准规定,在字母表中,如果第1个字符串在第2个字符串前⾯,strcmp()返回⼀个负数;如果两个字符串相
同,strcmp()返回0;如果第1个字符串在第2个字符串后⾯,strcmp()返回正数。然⽽,返回的具体值取决于实现。例如,下⾯给出在不
同实现中的输出,该实现返回两个字符的差值:
strcmp("A", "A") is 0
strcmp("A", "B") is -1
strcmp("B", "A") is 1
strcmp("C", "A") is 2
strcmp("Z", "a") is -7
strcmp("apples", "apple") is 115
如果两个字符串开始的⼏个字符都相同会怎样?⼀般⽽⾔,strcmp()会依次⽐较每个字符,直到发现第1对不同的字符为⽌。然后,返回相应的值。例如,在上⾯的最后⼀个例⼦中,"apples"和"apple"只有最后⼀对字符不同("apples"的s和"apple"的空字符)。由于空字符在ASCII中排第1。字符s⼀定在它后⾯,所以strcmp()返回⼀个正数。
最后⼀个例⼦表明,strcmp()⽐较所有的字符,不只是字母。所以,与其说该函数按字母顺序进⾏⽐较,不如说是按机器排序序列(machine collating sequence)进⾏⽐较,即根据字符的数值进⾏⽐较(通常都使⽤ASCII值)。在ASCII中,⼤写字母在⼩写字母前⾯,所
以strcmp("Z", "a")返回的是负值。
⼤多数情况下,strcmp()返回的具体值并不重要,我们只在意该值是0还是⾮0(即,⽐较的两个字符串是否相等)。或者按字母排序字符
串,在这种情况下,需要知道⽐较的结果是为正、为负还是为0。
--------------
字符串比较函数实现注意
strcmp()函数⽐较的是字符串,不是字符,所以其参数应该是字符串(如"apples"和"A"),⽽不是字符(如'A')。但是,char类型实际上是整
数类型,所以可以使⽤关系运算符来⽐较字符。假设word是存储在char类型数组中的字符串,ch是char类型的变量,下⾯的语句都有效:if (strcmp(word, "quit") == 0) // use strcmp() for strings puts("Bye!");if (ch == 'q') // use == for chars puts("Bye!");
尽管如此,不要使⽤ch或'q'作为strcmp()的参数。
--------------
程序quit_chk.c⽤strcmp()函数检查程序是否要停⽌读取输⼊。
/* quit_chk.c -- beginning of some program */#include #include #define SIZE 80#define LIM 10#define STOP "quit"char * s_gets(char * st, int n);int main(vo 该程序在读到EOF字符(这种情况下s_gets()返回NULL)、⽤户输⼊quit或输⼊项达到LIM时退出。
顺带⼀提,有时输⼊空⾏(即,只按下Enter键或Return键)表⽰结束输⼊更⽅便。为实现这⼀功能,只
需修改⼀下while循环的条件即可:while (ct < LIM && s_gets(input[ct], SIZE) != NULL && input[ct][0] != '0')
这⾥,input[ct]是刚输⼊的字符串,input[ct][0]是该字符串的第1个字符。如果⽤户输⼊空⾏,s_gets()便会把该⾏第1个字符(换⾏符)替换成空字符。所以,下⾯的表达式⽤于检测空⾏:
input[ct][0] != '0'
2.strncmp()函数
strcmp()函数⽐较字符串中的字符,直到发现不同的字符为⽌,这⼀过程可能会持续到字符串的末尾。⽽strncmp()函数在⽐较两个字符串时,可以⽐较到字符不同的地⽅,也可以只⽐较第3个参数指定的字符数。例如,要查以"astro"开头的字符串,可以限定函数只查这5
个字符。程序starsrch.c演⽰了该函数的⽤法。
/* starsrch.c -- use strncmp() */#include #include #define LISTSIZE 6int main(){ const char * list[LISTSIZE] = { "astronomy", "astounding", "astr 下⾯是该程序的输出:
Found: astronomyFound: astrophysicsFound: astrophobiaThe list contained 3 words beginning with astro.
5 strcpy()和strncpy()函数
前⾯提到过,如果pts1和pts2都是指向字符串的指针,那么下⾯语句拷贝的是字符串的地址⽽不是字符串本⾝:
pts2 = pts1;
如果希望拷贝整个字符串,要使⽤strcpy()函数。程序copy1.c要求⽤户输⼊以q开头的单词。该程序把输⼊拷贝⾄⼀个临时数组中,如果
第1个字母是q,程序调⽤strcpy()把整个字符串从临时数组拷贝⾄⽬标数组中。strcpy()函数相当于字符串赋值运算符。
/* copy1.c -- strcpy() demo */#include #include // declares strcpy()#define SIZE 40#define LIM 5char * s_gets(char * st, int n);int main(void){ char qwords[LIM][S 下⾯是该程序的运⾏⽰例:
Enter 5 words beginning with q:
quackery
quasar
quilt
quotient
no more
no more doesn't begin with q!
quiz
Here are the words accepted:
quackery
quasar
quilt
quotient
quiz
注意,只有在输⼊以q开头的单词后才会递增计数器i,⽽且该程序通过⽐较字符进⾏判断:
if (temp[0] != 'q')
这⾏代码的意思是:temp中的第1个字符是否是q?当然,也可以通过⽐较字符串进⾏判断:
if (strncmp(temp, "q", 1) != 0)
这⾏代码的意思是:temp字符串和"q"的第1个元素是否相等?
请注意,strcpy()第2个参数(temp)指向的字符串被拷贝⾄第1个参数(qword[i])指向的数组中。拷贝出来的字符串被称为⽬标字符串,最
初的字符串被称为源字符串。参考赋值表达式语句,很容易记住strcpy()参数的顺序,即第1个是⽬标字符串,第2个是源字符串。
char target[20];int x;x = 50; /* assignment for numbers */strcpy(target, "Hi ho!"); /* assignment for strings */target = "So long"; /* syntax error 程序员有责任确保⽬标数组有⾜够的空间容纳源字符串的副本。下⾯的代码有点问题:
char * str;strcpy(str, "The C of Tranquility"); // a problem
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论