zoukankan      html  css  js  c++  java
  • C语言常用字符串函数总结

    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, 38);
     9     puts(mesg);
    10     puts("Let's look at some more of the string.");
    11     puts(mesg + 39);  //我们在38位置(空字符)后的39位置开始打印缓冲区余下的字符串。
    12 
    13     return 0;
    14 }
    15 
    16 void fit(char *string, unsigned int size)  //利用strlen函数,设计一个函数可以缩短字符串的长度。
    17 {
    18     if(strlen(string)>size)
    19         string[size] = '';
    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 0;
    24 }
    25 
    26 char * s_gets(char * st, int n)
    27 {
    28     char * ret_val;
    29     int i=0;
    30 
    31     ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;
    32     if(ret_val)
    33     {
    34         while(st[i]!='
    ' && st[i]!='')
    35             i++;
    36         if(st[i] =='
    ') //fgets会把换行符也吃进来了,fgets会在末尾自动加上;
    37             st[i]='';
    38         else
    39             while(getchar() != '
    ')
    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)+1)<=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)-124     strncat(bug,addon,available);
    25     puts(bug);
    26     return 0;
    27 }
    28 
    29 
    30 
    31 char * s_gets(char * st, int n)
    32 {
    33     char * ret_val;
    34     int i=0;
    35 
    36     ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;
    37     if(ret_val)
    38     {
    39         while(st[i]!='
    ' && st[i]!='')
    40             i++;
    41         if(st[i] =='
    ') //fgets会把换行符也吃进来了,fgets会在末尾自动加上;
    42             st[i]='';
    43         else   //其实是''
    44             while(getchar() != '
    ')  //会把缓冲区后续的字符都清空
    45                 continue;
    46     }
    47     return ret_val;
    48 }

    我们发现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 =0;
    16 
    17     printf("Enter up to %d lines(type quit to quit):
    ",LIM);
    18     while(ct<LIM && s_gets(input[ct],SIZE)!=NULL && strcmp(input[ct],STOP)!=0)
    19         ct++;
    20     printf("%d strings entered
    ",ct);
    21 
    22     return 0;
    23 }
    24 
    25 
    26 char * s_gets(char * st, int n)
    27 {
    28     char * ret_val;
    29     int i=0;
    30 
    31     ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;
    32     if(ret_val)
    33     {
    34         while(st[i]!='
    ' && st[i]!='')
    35             i++;
    36         if(st[i] =='
    ') //fgets会把换行符也吃进来了,fgets会在末尾自动加上;
    37             st[i]='';
    38         else   //其实是''
    39             while(getchar() != '
    ')  //会把缓冲区后续的字符都清空
    40                 continue;
    41     }
    42     return ret_val;
    43 }

    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 =0;
    16     int i;
    17 
    18     for(i=0;i<LISTSIZE;i++)
    19     {
    20         if(strncmp(list[i],"astro",5)==0)
    21             printf("Found:%s
    ",list[i]);
    22             count++;
    23     }
    24     printf("The list contained %d words beginning" " with astro.
    ",count);
    25 
    26     return 0;
    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 = 0;
    12 
    13     printf("Enter %d words beginning with q:
    ",LIM);
    14     while(i<LIM && s_gets(temp,SIZE))
    15     {
    16         if(temp[0]!='q')
    17             printf("%s doesn't begin with q!
    ",temp);
    18         else
    19         {
    20             strcpy(qwords[i],temp);
    21             i++;
    22         }
    23     }
    24     puts("Here are the words accepted:");
    25     for(i=0;i<LIM;i++)
    26     {
    27         puts(qwords[i]);
    28     }
    29     return 0;
    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+7,orig);
    15     puts(copy);
    16     puts(ps);
    17 
    18     return 0;
    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=0;
    15     
    16     printf("Enter %d words beginning with q:
    ",LIM);
    17     while(i<LIM && s_gets(temp,SIZE))
    18     {
    19             if(temp[0]!='q')
    20                 printf("%s doesn't begin with q!
    ",temp);
    21             else
    22             {
    23                 strncpy(qwords[i],temp,TARGSIZE-1);
    24                 qwords[i][TARGSIZE-1] ='';
    25                 i++;
    26             }
    27     }
    28     puts("Here are the words accepted:");
    29     for (i=0;i<LIM;i++)
    30     {
    31         puts(qwords[i]); //puts末尾自动加上换行符
    32     }
    33     
    34     return 0;
    35 }
    36 
    37 
    38 char * s_gets(char * st, int n)
    39 {
    40     char * ret_val;
    41     int i=0;
    42 
    43     ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;
    44     if(ret_val)
    45     {
    46         while(st[i]!='
    ' && st[i]!='')
    47             i++;
    48         if(st[i] =='
    ') //fgets会把换行符也吃进来了,fgets会在末尾自动加上;
    49             st[i]='';
    50         else   //其实是''
    51             while(getchar() != '
    ')  //会把缓冲区后续的字符都清空
    52                 continue;
    53     }
    54     return ret_val;
    55 }

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

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

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

    代码如下:

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

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

     

    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[2*MAX+10];
    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
    ",last,first,prize);
    20     puts(formal);
    21 
    22     return 0;
    23 }
    24 
    25 
    26 
    27 
    28 
    29 char * s_gets(char * st, int n)
    30 {
    31     char * ret_val;
    32     int i=0;
    33 
    34     ret_val = fgets(st, n, stdin); //读取成功,返回一个指针,指向输入字符串的首字符;
    35     if(ret_val)
    36     {
    37         while(st[i]!='
    ' && st[i]!='')
    38             i++;
    39         if(st[i] =='
    ') //fgets会把换行符也吃进来了,fgets会在末尾自动加上;
    40             st[i]='';
    41         else   //其实是''
    42             while(getchar() != '
    ')  //会把缓冲区后续的字符都清空
    43                 continue;
    44     }
    45     return ret_val;
    46 }

    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()读入一行输入时,在目标字符串的末尾添加换行符

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

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

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

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

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

    注意点:

    1 while(* string)

    2 while(*string != '')

    许多程序员会在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,
    ");
    10     printf("I count %d characters.
    ",
    11            put2("I never would cry old chairs to mend."));
    12 
    13     return 0;
    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 = 0;
    26     while(*string)
    27     {
    28         putchar(*string++);
    29         count++;
    30     }
    31     putchar('
    ');
    32 
    33     return(count);
    34 }

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

  • 相关阅读:
    AS出现Connection timed out
    关于eclipse出现The selection cannot be launched,and there are no recent launches
    第十周周赛题解
    FJUT 2401 尼克的任务
    关于3月份的学习总结
    人生的第一题图论
    第六周周赛题解
    Drupal8 社区文档之积极的Drupal版本
    Drupal8 社区文档之Drupal安全吗
    Drupal8 社区文档之技术堆栈
  • 原文地址:https://www.cnblogs.com/grooovvve/p/9937189.html
Copyright © 2011-2022 走看看