1. ANSI C中有20多个用于处理字符串的函数:

注意:const 形参使用了const限定符,表示该函数不会改变传入的字符串。因为源字符串是不能更改的。

strlen函数:

函数原型:unsigned int strlen(const char*)

用于统计字符串的长度。举例如下

  1. void fit(char *,unsigned int);
  2.  
  3. int main(void)
  4. {
  5. char mesg [] = "Things should be as simple as possible,""but not simpler.";
  6.  
  7. puts(mesg);
  8. fit(mesg, );
  9. puts(mesg);
  10. puts("Let's look at some more of the string.");
  11. puts(mesg + ); //我们在38位置(空字符\0)后的39位置开始打印缓冲区余下的字符串。
  12.  
  13. return ;
  14. }
  15.  
  16. void fit(char *string, unsigned int size) //利用strlen函数,设计一个函数可以缩短字符串的长度。
  17. {
  18. if(strlen(string)>size)
  19. string[size] = '\0';
  20. }

strcat()函数:

函数原型:char *strcat(char *strDest, const char *strSrc)

接受两个字符串作为参数,把第2个字符串的备份附加在第1个字符串的末尾。并把拼接后形成的新字符串作为第1个字符串。第2个字符串不变。

  1. #include <stdio.h>
  2. #include <string.h>
  3. #define SIZE 80
  4.  
  5. char * s_gets(char * st, int n);
  6.  
  7. int main()
  8. {
  9. char flower[SIZE];
  10. char addon [] = "s smell like old shoes.";
  11.  
  12. puts("What is your favorite flower?");
  13. if(s_gets(flower,SIZE))
  14. {
  15. strcat(flower,addon); //使用了strcat函数进行字符串拼接
  16. puts(flower);
  17. puts(addon);
  18. }
  19. else
  20. puts("End of file encountered!");
  21. puts("bye");
  22.  
  23. return ;
  24. }
  25.  
  26. char * s_gets(char * st, int n)
  27. {
  28. char * ret_val;
  29. int i=;
  30.  
  31. ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;
  32. if(ret_val)
  33. {
  34. while(st[i]!='\n' && st[i]!='\0')
  35. i++;
  36. if(st[i] =='\n') //fgets会把换行符也吃进来了,fgets会在末尾自动加上\0;
  37. st[i]='\0';
  38. else
  39. while(getchar() != '\n')
  40. continue;
  41. }
  42. return ret_val;
  43. }

strncat()函数:

strcat()函数有个缺点就是无法检查第1个数组是否能容纳第2个字符串。如果给第1个数组的空间不够大,多出来的字符溢出到相邻存储单元时就会出问题。

函数原型:extern char *strncat(char *dest,char *src,int n);

参数说明:第3个参数指定了最大添加字符数;

这段代码会拼接两个字符,检查第1个数组的大小,重点是确定最大能添加多少字符数;

  1. #include<stdio.h>
  2. #include<string.h>
  3.  
  4. #define SIZE 30
  5. #define BUGSIZE 13
  6.  
  7. char * s_gets(char * st,int n);
  8.  
  9. int main(void)
  10. {
  11. char flower[SIZE];
  12. char addon [] = "s smell like old shoes.";
  13. char bug[BUGSIZE];
  14. int available;
  15.  
  16. puts("What is your favorite flower?");
  17. s_gets(flower,SIZE);
  18. if((strlen(addon)+strlen(flower)+)<=SIZE) //important
  19. strcat(flower,addon);
  20. puts(flower);
  21. puts("What is your favorite bug?");
  22. s_gets(bug,BUGSIZE);
  23. available= BUGSIZE -strlen(bug)-;
  24. strncat(bug,addon,available);
  25. puts(bug);
  26. return ;
  27. }
  28.  
  29. char * s_gets(char * st, int n)
  30. {
  31. char * ret_val;
  32. int i=;
  33.  
  34. ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;
  35. if(ret_val)
  36. {
  37. while(st[i]!='\n' && st[i]!='\0')
  38. i++;
  39. if(st[i] =='\n') //fgets会把换行符也吃进来了,fgets会在末尾自动加上\0;
  40. st[i]='\0';
  41. else //其实是'\0'
  42. while(getchar() != '\n') //会把缓冲区后续的字符都清空
  43. continue;
  44. }
  45. return ret_val;
  46. }

我们发现strcat()也会造成缓冲区溢出。但是它没有像gets()一样被废除。gets()的安全隐患来自使用程序的人。而strcat()的安全隐患来自粗心的程序员。我们无法控制用户会进行什么操作,但是可以控制程序做什么。因此C语言相信程序员。程序员也有责任保证strcat()使用的安全。

缓冲区溢出漏洞:程序员必须保证strcat的第一个参数有足够的空间。编译器无法报错是因为,这个函数的参数是指针类型,函数中也只是通过指针来读写这些内存的。函数根本不知道第一个参数所指的内存空间到底够不够大,函数本身不会对此进行检查。函数的大致行为是找到第一个参数所指的内存中字符串结尾的位置,然后从此处开始写入第二个参数的字符,直到写完。如果向第一个参数写入过多的字符,有可能会引起问题,也有可能不会。这取决于内存空间后面的内存是否可用来读写。万一覆盖了内存空间重要数据,就会引起错误。所以这是严重的安全隐患。

strcmp()函数

函数原型:int strcmp(const char *str1,const char *str2);

strcmp()函数返回的具体值不重要,我们只在意该值是0还是非0;比较两个字符串是否相等;我们关注的是字符串是否相等;

如果真要关心返回值的话,要理解比较的机制:其实是ASCII码值的比较;大写的字母ASCII值比小写的字母小;

比较的是:第一个字符串,相对第二个字符串的大小

str1<str2 返回负值;(ASCII的差值)

str1=str2 等于0;

str1>str2 返回正值;(ASCII的差值)

  1. //检查程序是否要停止读取输入
  2.  
  3. #include <stdio.h>
  4. #include <string.h>
  5.  
  6. #define SIZE 80
  7. #define LIM 10
  8. #define STOP "quit"
  9.  
  10. char * s_gets(char *st, int n);
  11.  
  12. int main(void)
  13. {
  14. char input[LIM][SIZE];
  15. int ct =;
  16.  
  17. printf("Enter up to %d lines(type quit to quit):\n",LIM);
  18. while(ct<LIM && s_gets(input[ct],SIZE)!=NULL && strcmp(input[ct],STOP)!=)
  19. ct++;
  20. printf("%d strings entered\n",ct);
  21.  
  22. return ;
  23. }
  24.  
  25. char * s_gets(char * st, int n)
  26. {
  27. char * ret_val;
  28. int i=;
  29.  
  30. ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;
  31. if(ret_val)
  32. {
  33. while(st[i]!='\n' && st[i]!='\0')
  34. i++;
  35. if(st[i] =='\n') //fgets会把换行符也吃进来了,fgets会在末尾自动加上\0;
  36. st[i]='\0';
  37. else //其实是'\0'
  38. while(getchar() != '\n') //会把缓冲区后续的字符都清空
  39. continue;
  40. }
  41. return ret_val;
  42. }

strncmp()函数:

函数原型:extern int strcmp(char *str1,char * str2,int n)

参数说明:str1为第一个要比较的字符串,str2为第二个要比较的字符串,n为指定的str1与str2的比较的字符数。

函数功能:比较字符串str1和str2的前n个字符。

返回说明:返回整数值:当str1<str2时,返回值<0; 当str1=str2时,返回值=0; 当str1>str2时,返回值>0。

  1. //比较前五个字符是否相等
  2. #include <stdio.h>
  3. #include <string.h>
  4.  
  5. #define LISTSIZE 6
  6.  
  7. int main()
  8. {
  9. const char *list[LISTSIZE]=
  10. {
  11. "astronomy","astounding",
  12. "astrophysics","ostracize",
  13. "asterism","astrophobia"
  14. };
  15. int count =;
  16. int i;
  17.  
  18. for(i=;i<LISTSIZE;i++)
  19. {
  20. if(strncmp(list[i],"astro",)==)
  21. printf("Found:%s\n",list[i]);
  22. count++;
  23. }
  24. printf("The list contained %d words beginning" " with astro.\n",count);
  25.  
  26. return ;
  27. }

strcpy()函数:

函数原型:char *strcpy(char *strDest, const char *strSrc)

这个函数相当于字符串的赋值运算,拷贝字符串;

  1. #include <stdio.h>
  2. #include <string.h>
  3. #define SIZE 40
  4. #define LIM 5
  5. char * s_gets(char * st, int n);
  6.  
  7. int main(void)
  8. {
  9. char qwords[LIM][SIZE];
  10. char temp[SIZE];
  11. int i = ;
  12.  
  13. printf("Enter %d words beginning with q:\n",LIM);
  14. while(i<LIM && s_gets(temp,SIZE))
  15. {
  16. if(temp[]!='q')
  17. printf("%s doesn't begin with q!\n",temp);
  18. else
  19. {
  20. strcpy(qwords[i],temp);
  21. i++;
  22. }
  23. }
  24. puts("Here are the words accepted:");
  25. for(i=;i<LIM;i++)
  26. {
  27. puts(qwords[i]);
  28. }
  29. return ;
  30. }

声明数组将分配储存数据的空间,声明指针只分配储存一个地址的空间;

使用strcpy函数的时候,程序员有责任保证目标字符串有足够的空间储存源字符串的副本;

strcpy的一些属性:其返回类型是char *,第一,该函数返回的是第1个参数的值,即一个字符的地址;第二,第1个参数不必指向数组的开始。这个属性可用于拷贝数组的一部分。代码如下:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #define WORDS "beast"
  4. #define SIZE 40
  5.  
  6. int main(void)
  7. {
  8. const char * orig = WORDS;
  9. char copy[SIZE]= "Be the best that you can be.";
  10. char *ps;
  11.  
  12. puts(orig);
  13. puts(copy);
  14. ps = strcpy(copy+,orig);
  15. puts(copy);
  16. puts(ps);
  17.  
  18. return ;
  19. }

注意:源字符串也会把空字符也拷贝在内。

strncpy()函数:更谨慎的选择

函数原型:char *strncpy(char *dest, char *src, int n);

strcpy()和strcat()都有同样的问题,就是不能检查目标空间能否容纳源字符串的副本。拷贝字符串用strncpy()更安全。第3个参数指明可拷贝的最大字符数

  1. //还是输入五个q开头的单词,但是对单词输入的长度有限制
  2. #include <stdio.h>
  3. #include <string.h>
  4. #define SIZE 40
  5. #define TARGSIZE 7
  6. #define LIM 5
  7.  
  8. char * s_gets(char * st, int n);
  9.  
  10. int main(void)
  11. {
  12. char qwords[LIM][TARGSIZE];
  13. char temp[SIZE];
  14. int i=;
  15.  
  16. printf("Enter %d words beginning with q:\n",LIM);
  17. while(i<LIM && s_gets(temp,SIZE))
  18. {
  19. if(temp[]!='q')
  20. printf("%s doesn't begin with q!\n",temp);
  21. else
  22. {
  23. strncpy(qwords[i],temp,TARGSIZE-);
  24. qwords[i][TARGSIZE-] ='\0';
  25. i++;
  26. }
  27. }
  28. puts("Here are the words accepted:");
  29. for (i=;i<LIM;i++)
  30. {
  31. puts(qwords[i]); //puts末尾自动加上换行符
  32. }
  33.  
  34. return ;
  35. }
  36.  
  37. char * s_gets(char * st, int n)
  38. {
  39. char * ret_val;
  40. int i=;
  41.  
  42. ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;
  43. if(ret_val)
  44. {
  45. while(st[i]!='\n' && st[i]!='\0')
  46. i++;
  47. if(st[i] =='\n') //fgets会把换行符也吃进来了,fgets会在末尾自动加上\0;
  48. st[i]='\0';
  49. else //其实是'\0'
  50. while(getchar() != '\n') //会把缓冲区后续的字符都清空
  51. continue;
  52. }
  53. return ret_val;
  54. }

strncpy(target,source,n)把source中的n个字符或空字符之前的字符(先满足哪个条件就执行哪个)拷贝到target中。

如果source中的字符数小于n,则拷贝整个字符串,包括空字符。

但是有一种情况就是万一没有把末尾的空字符拷贝进去的话,就不是存的字符串了。所以一般要把n设置成比目标数组的大小少1,然后把数组最后一个元素设置为空字符。

代码如下:

  1. strncpy(qwords[i],temp,TARGSIZE-);
  2. qwords[i][TARGSIZE-] ='\0';

这样做确保是一个字符串。

sprintf()函数

函数原型:int sprintf( char *buffer, const char *format [, argument] … );

注意:它函数声明在stdio.h中,而不是在string.h中;该函数和printf()有点像。但是它是把数据写入字符串中,而不是打印在显示器上。

第一个参数是目标字符串的地址。其余参数和printf()相同,即格式字符串和待写入项的列表

sprintf 是个变参函数,使用sprintf 对于写入buffer的字符数是没有限制的,这就存在了buffer溢出的可能性。

  1. //格式化字符串
  2. #include <stdio.h>
  3. #define MAX 20
  4. char * s_gets(char * st, int n);
  5.  
  6. int main(void)
  7. {
  8. char first[MAX];
  9. char last[MAX];
  10. char formal[*MAX+];
  11. double prize;
  12.  
  13. puts("Enter your first name:");
  14. s_gets(first,MAX);
  15. puts("Enter your last name:");
  16. s_gets(last,MAX);
  17. puts("Enter your prize money:");
  18. scanf("%lf",&prize);
  19. sprintf(formal,"%s, %-19s: $%6.2f\n",last,first,prize);
  20. puts(formal);
  21.  
  22. return ;
  23. }
  24.  
  25. char * s_gets(char * st, int n)
  26. {
  27. char * ret_val;
  28. int i=;
  29.  
  30. ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;
  31. if(ret_val)
  32. {
  33. while(st[i]!='\n' && st[i]!='\0')
  34. i++;
  35. if(st[i] =='\n') //fgets会把换行符也吃进来了,fgets会在末尾自动加上\0;
  36. st[i]='\0';
  37. else //其实是'\0'
  38. while(getchar() != '\n') //会把缓冲区后续的字符都清空
  39. continue;
  40. }
  41. return ret_val;
  42. }

strchr函数:

函数原型:char *strchr(const char *s, int c)

如果s字符串中包含c字符,该函数返回指向s字符串首位置(指向字符)的指针;如果在字符串中未找到c字符,该函数则返回空指针;

strrchr函数:

函数原型:char *strrchr(const char * s,int c)

该函数返回s字符串中c字符的最后一次出现的位置(末尾的空字符也是字符串的一部分,所以在查找范围内)。如果未找到c字符,则返回空指针;

strstr函数:

函数原型:char *strstr(const char * s1, const char * s2);

返回值是指向s1字符串中s2字符串出现的首位置。如果在s1中没有找到s2,则返回空指针。

strpbrk函数:

函数原型:char *strpbrk(const char * s1, const char * s2);

如果s1字符中包含s2字符串中的任意字符,该函数返回指向s1字符串首位置的指针;如果在s1字符串中未找到任何s2字符串中的字符,则返回空指针。

size_t strlen(const char * s)

该函数返回s字符串中的字符数,不包括末尾的空字符

size_t类型是sizeof运算符返回的类型。

C规定sizeof运算符返回一个整数类型,但是并未指定是哪种整数类型

所以size_t在一个系统中可以是unsigned int,而在另一个系统中可以是unsigned long。

string.h头文件针对特定系统定义了size_t。这样就可以跨平台了,屏蔽平台之间的差异性。

//fgets()读入一行输入时,在目标字符串的末尾添加换行符

//处理末尾换行符的方法之一是循环检测换行符,然后替换成\0

  1. char * s_gets(char * st, int n)
  2. {
  3. char * ret_val;
  4. int i=;
  5.  
  6. ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;
  7. if(ret_val)
  8. {
  9. while(st[i]!='\n' && st[i]!='\0')
  10. i++;
  11. if(st[i] =='\n') //fgets会把换行符也吃进来了,fgets会在末尾自动加上\0;
  12. st[i]='\0';
  13. else //其实是'\0'
  14. while(getchar() != '\n') //会把缓冲区后续的字符都清空
  15. continue;
  16. }
  17. return ret_val;
  18. }

有其他办法,使用strchr()代替s_gets():

  1. #include <stdio.h>
  2.  
  3. char line[];
  4. char * find;
  5.  
  6. fgets(line, , stdin);
  7. find = strchr(line, '\n');
  8. if(find)
  9. * find ='\0';

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

注意点:

  1. while(* string)
  2.  
  3. 2 while(*string != '\0')

许多程序员会在while循环条件中使用第一种的测试条件;string指向空字符时,*string的值是0,即测试条件为假,while循环结束。作为C语言程序员应该熟悉方法,第二种的测试条件没有第一种简洁。

const char * string和const char string[]的区别:

从技术方面讲,两者等效且都有效;

使用方括号是为了提醒用户,实际处理的参数是数组;

如果要处理字符串,使用指针形式的话,实际参数可以是数组名,双引号括起来的字符串或声明为char *类型的变量。这种写法是为了提醒用户,实际参数不一定是数组;

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

演示1:嵌套函数的调用

  1. #include <stdio.h>
  2.  
  3. void put1(const char *);
  4. int put2(const char *);
  5.  
  6. int main(void)
  7. {
  8. put1("If I'd as much money");
  9. put1(" as I could spend,\n");
  10. printf("I count %d characters.\n",
  11. put2("I never would cry old chairs to mend."));
  12.  
  13. return ;
  14. }
  15.  
  16. void put1(const char * string)
  17. {
  18. while(*string)
  19. putchar(* string++);
  20.  
  21. }
  22.  
  23. int put2(const char * string)
  24. {
  25. int count = ;
  26. while(*string)
  27. {
  28. putchar(*string++);
  29. count++;
  30. }
  31. putchar('\n');
  32.  
  33. return(count);
  34. }

分析:使用printf()打印put2的值,但是为了获得put2的返回值,计算机必须先执行put2(),因此执行put2()的过程中,打印了put2中的字符串。

C语言常用字符串函数总结的更多相关文章

  1. C语言常用字符串函数

    string.h头文件中常用的函数 C 库函数 - strcat() char *strcat(char *dest, const char *src) 把 src 所指向的字符串追加到 dest 所 ...

  2. php常用字符串函数小结

    php内置了98个字符串函数(除了基于正则表达式的函数,正则表达式在此不在讨论范围),能够处理字符串中能遇到的每一个方面内容,本文对常用字符串函数进行简单的小结,主要包含以下8部分:1.确定字符串长度 ...

  3. [转]MySQL常用Json函数和MySQL常用字符串函数

    MySQL常用Json函数:https://www.cnblogs.com/waterystone/p/5626098.html MySQL常用字符串函数:https://www.cnblogs.co ...

  4. js进阶js中支持正则的四个常用字符串函数(search march replace split)

    js进阶js中支持正则的四个常用字符串函数(search march replace split) 一.总结 代码中详细四个函数的用法 search march replace split 二.js进 ...

  5. Delphi常用字符串函数

    Delphi常用字符串函数   一.字符转换函数1.ord(input[i])返回字符表达式 input 左端起第 I 字符的ASCII 码值.2.CHAR()将ASCII 码转换为字符.如果没有输入 ...

  6. C语言入门(6)——C语言常用数学函数

    在编码过程中会经遇到数学运算,幸运的是C语言提供了非常丰富的数学函数库. 在数学中使用函数有时候书写可以省略括号,而C语言要求一定要加上括号,例如sin(pi/2)这种形式.在C语言的术语中,pi/2 ...

  7. MySQL最常用字符串函数

    字符串函数 是最常用的的一种函数,在一个具体应用中通常会综合几个甚至几类函数来实现相应的应用: 1.LOWER(column|str):将字符串参数值转换为全小写字母后返回 mysql> sel ...

  8. MySQL常用字符串函数

    字符串函数 是最常用的的一种函数,在一个具体应用中通常会综合几个甚至几类函数来实现相应的应用: 1.LOWER(column|str):将字符串参数值转换为全小写字母后返回 mysql> sel ...

  9. PHP 常用字符串函数整理

    PHP语言中的字符串函数也是一个比较易懂的知识.今天我们就为大家总结了将近12种PHP字符串函数,希望对又需要的朋友有所帮助,增加读者朋友的PHP知识库. 1.查找字符位置函数 strpos($str ...

随机推荐

  1. oracle 之sys 、system区别

    角色 1)最重要的区别,存储的数据的重要性不同sys--所有oracle的数据字典的基表和视图都存放在sys用户中,这些基表和视图对于oracle的运行是至关重要的,由数据库自己维护,任何用户都不能手 ...

  2. css3(border-radius)边框圆角详解(转)

    css3(border-radius)边框圆角详解 (2014-05-19 16:16:29) 转载▼ 标签: divcss html it css3 分类: 网页技术 传统的圆角生成方案,必须使用多 ...

  3. a标签中href=""的几种用法(转)

    a标签中href=""的几种用法   标签: html / a标签 / javascript 46371 众所周知,a标签的最重要功能是实现超链接和锚点.而且,大多数人认为a标签最 ...

  4. repeater的command事件用法

    当Repeater里面循环控件时就会用到command, 是Repeater控件的原生事件用法 Repeater里面如果循环控件,控件的ID是会被改变的 repeater.itemcommand+= ...

  5. Blender 基础 骨架 01

    Blender 基础 骨架 01 我使用的Blender版本:Blender V 2.77 前言 本讲介绍: 骨架的基本使用方式. 骨架是角色动画里面最常使用的元素,它可以准确控制一个模型的变形,尤其 ...

  6. JDK并发包2-线程池

  7. 简单VBS教程.RP

    Mimick同菜鸟==.文转豆瓣~:https://www.douban.com/note/88562379/ 讲一下VBScript.主要面向菜鸟,懂得编程的朋友就不要浪费时间了,如果你想接触以下V ...

  8. C# SendMessage用法一二

    函数功能:该函数将指定的消息发送到一个或多个窗口.此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回.而函数PostMessage不同,将一个消息寄送到一个线程的消息队列后立即返回.  函数 ...

  9. UINavigationController + UIScrollView组合,视图尺寸的设置探秘(一)

    UINavigationController和UIScrollView是iOS下几种主要的交互元素,但当我搭配二者在一起时,UIScrollView的滚动区域出现了很诡异的现象.我希望UIScroll ...

  10. RPM软件包管理以及使用方法

    Red Hat Package Manager(简称RPM)工具包由于其使用简单操作方便,可以实现软件的查询.安装.卸载.升级和验证等功能,为Linux使用者节省大量的时间,所以被广泛的用于Linux ...