《C编程.中级C》6.字符串操作

C中的字符串只是一个字符数组。字符串的长度由终止空字符确定:'\0'。所以,随着内容的字符串,比方说,"abc"有四个大字:'a''b''c',和终止空('\0')字符。

终止空字符的值为零。

语法

在C中,字符串常量(文字)被双引号(“)包围,例如”Hello world!“,并被编译为指定char值的数组,并带有一个额外的空终止字符(0值)代码以标记结束字符串常量的类型是char []。

反斜杠逃脱

字符串文字可能不会直接在源代码中包含嵌入的换行符或其他控制字符,或字符串中具有特殊含义的其他字符。

要在字符串中包含此类字符,可以使用反斜杠转义符,如下所示:

逃逸含义
\\字面反斜杠
\”双引号
\”单引号
\ n换行符(换行)
\ r回程
\ b退格
\ t水平标签
\F表格饲料
\一个警报(铃)
符\ v垂直标签
\?问号(用于逃避三角形)
nnn具有八进制值nnn的字符
\ x hh具有十六进制值的字符hh

宽字符串

C支持宽字符串,定义为wchar_t类型的数组,16位(至少)值。它们在字符串之前用L写成wchar_t * p = L“Hello  world!”;

该特征允许在需要多于256点不同的可能的字符(虽然也是可变长度字符串字符的字符串可以使用)。它们以零值wchar_t结束。<string.h>函数不支持这些字符串。相反,它们有自己的函数,在<wchar.h>中声明。

字符编码

除了值0x00和0x0000指定字符串的结尾而不是字符之外,C标准未指定char和wchar_t表示的哪个字符编码。它是直接受字符编码影响的输入和输出代码。其他代码不应受到太大影响。如果字符串能够在源代码中编写,编辑器也应该能够处理编码。

编码有三种主要类型:

  • 每个字符一个字节。通常基于ASCII。限制为255个不同的字符加零终止字符。
  • 可变长度字符的字符串,它允许许多多于255个不同的字符。这些字符串被写为普通的基于字符的数组。这些编码通常是基于ASCII的,例子是UTF-8或Shift JIS。
  • 宽字符串。它们是wchar_t值的数组。UTF-16是最常见的此类编码,它也是可变长度的,这意味着一个字符可以是两个wchar_t。

<string.h>标准头

因为程序员发现原始字符串很难处理,所以他们在<string.h>库中编写代码。它代表的不是协同设计的努力,而是各个作者多年来所做贡献的增加。

首先,字符串库中存在三种类型的函数:

  • 这些mem函数操纵任意字符的序列而不考虑空字符;
  • 这些str函数操纵以null结尾的字符序列;
  • 这些strn函数操纵非空字符序列。

更常用的字符串函数

字符串库中九个最常用的函数是:

  • strcat – 连接两个字符串
  • strchr – 字符串扫描操作
  • strcmp – 比较两个字符串
  • strcpy – 复制一个字符串
  • strlen – 获取字符串长度
  • strncat – 将一个字符串与另一个字符串连接起来
  • strncmp – 比较两个字符串的部分
  • strncpy – 复制字符串的一部分
  • strchr – 字符串扫描操作

strcat函数

char *strcat(char * restrict s1, const char * restrict s2);

有些人建议使用 strncat()  strlcat() 代替strcat,以避免缓冲区溢出。

strcat()函数应将由s2(包括终止空字节)指向的字符串的副本附加到指向的字符串的末尾s1。初始字节s2覆盖结尾处的空字节s1。如果在重叠的对象之间进行复制,则行为未定义。该函数返回s1

此函数用于将一个字符串附加到另一个字符串的末尾。第一个string(s1)必须具有存储两个字符串所需的空间。

例:

    #include  <stdio.h>
    #include  <string.h>
    ... 
    static  const  char  * colors []  =  { “Red” ,“Orange” ,“Yellow” ,“Green” ,“Blue” ,“Purple”  }; 
    static  const  char  * widths []  =  { “Thin” ,“Medium” ,“Thick” ,“Bold”  }; 
    ... 
    char  penText [ 20 ]; 
    ... 
    int  penColor  =  3 ,   2 ; 
    strcpy (penText , colors [ penColor ]); 
    的strcat (penText , 宽度[ penThickness ]); 
    printf (“我的笔是%s \ n ” , penText );  / *打印'我的笔是GreenThick'* /

在调用之前strcat(),目标必须当前包含空终止字符串,或者必须使用空字符初始化第一个字符(例如penText[0] = '\0';)。


以下是公共域实现strcat

 #include  <string.h>
 / * strcat * / 
 char  * (strcat )(char  * restrict  s1 , const  char  * restrict  s2 )
 { 
     char  * s  =  s1 ; 
     / *移动s使其指向s1的结尾。* / 
     while  (* s  !=  '\ 0' )
         s ++ ; 
     / *将s2的内容复制到s1末尾的空格中。* / 
     strcpy (s , s2 ); 
     返回 s1 ; 
 }

strchr函数

char *strchr(const char *s, int c);

strchr()函数应该在指向的字符串中找到第一个出现的c(转换为a chars。终止空字节被认为是字符串的一部分。该函数返回找到的字符的位置,如果找不到该字符,则返回空指针。

此函数用于查找字符串中的某些字符。

在历史的某个时刻,这个功能被命名index。这个strchr名字虽然含糊不清,但却符合命名的一般模式。

以下是公共域实现strchr

 #include  <string.h>
 / * strchr * / 
 char  * (strchr )(const  char  * s , int  c )
 { 
     char  ch  =  c ; 
     / *扫描角色。当这个循环结束时,
        s将指向字符串的结尾或
        我们正在寻找
     字符。* / while  (* s  !=  '\ 0'  &&  * s  !=  ch )
         s ++ ; 
     返回 (* s  ==  ch ) ? (char  * ) s  : NULL ; 
 }

strcmp函数

int strcmp(const char *s1, const char *s2);

使用strcmp()函数完成字符串比较的基本形式。它需要两个字符串作为参数,并且如果第一个在词义上小于第二个,则返回小于零的值,如果第一个在词义上大于第二个,则返回大于零的值,如果两个字符串相等,则返回零。通过逐字符地比较字符的编码(ascii)值来完成比较。

现在,在排序字符串列表时,这种简单类型的字符串比较通常被认为是不可接受的。存在能够以字典排序顺序产生列表的更高级算法。考虑到字符串“Alpha2”大于“Alpha12”,他们还可以解决诸如strcmp()之类的问题。(在前面的例子中,“Alpha2”比“Alpha12”更大,因为’2’在字符集中的’1’之后。)我们所说的是,不要strcmp()在任何商业广告中单独使用它进行一般的字符串排序或专业代码。

strcmp()功能应比较字符串指向s1字符串指向s2。非零返回值的符号应由unsigned char在比较的字符串中不同的第一对字节(均被解释为类型)的值之间的差的符号确定。完成后,strcmp()如果指向的字符串分别s1大于,等于或小于指向的字符串,则应返回大于,等于或小于0的整数s2

由于比较指针本身并不实际有用,除非比较同一数组中的指针,否则此函数会在词法上比较两个指针所指向的字符串。

此功能在比较中很有用,例如

if(strcmp(s,“whatever”)== 0)/ *做点什么* /
    ;

使用的整理顺序strcmp()等同于机器的本机字符集。关于订单的唯一保证是从’0’到’9’的数字是连续的顺序。

以下是公共域实现strcmp

 #include  <string.h>
 / * strcmp * / 
 int  (strcmp )(const  char  * s1 , const  char  * s2 )
 { 
     unsigned  char  uc1 , uc2 ; 
     / *将s1和s2移动到
        每个字符串中
的第一个不同字符,或者如果它们        相同
     则将字符串的末尾移动* / while  (* s1  !=  '\ 0'  &&  * s1  ==  * s2 ) { 
         s1 ++ ; 
         s2 ++ ; 
     }
     / *将字符作为unsigned char比较并
        返回差异。* / 
     uc1  =  (* (unsigned  char  * ) s1 ); 
     uc2  =  (* (unsigned  char  * ) s2 ); 
     return  ((uc1  <  uc2 ) ? - 1  : (uc1  >  uc2 )); 
 }

strcpy函数

char *strcpy(char *restrict s1, const char *restrict s2);

有些人建议总是使用 strncpy() 而不是strcpy,以避免缓冲区溢出。

strcpy()函数应将指向的C字符串s2(包括终止空字节)复制到指向的数组中s1。如果在重叠的对象之间进行复制,则行为未定义。该函数返回s1。没有用于指示错误的值:如果参数strcpy()是正确的,并且目标缓冲区足够大,则该函数将永远不会失败。

例:

    #include  <stdio.h>
    #include  <string.h>
    / * ... * / 
    static  const  char  * penType = “round” ; 
    / * ... * / 
    char  penText [ 20 ]; 
    / * ... * / 
    strcpy (penText , penType );

要点:必须确保目标缓冲区(s1)能够包含源数组中的所有字符,包括终止空字节。否则,strcpy()将覆盖缓冲区末尾的内存,导致缓冲区溢出,这可能导致程序崩溃,或者被黑客利用来破坏计算机的安全性。

以下是公共域实现strcpy

 #include  <string.h>
 / * strcpy * / 
 char  * (strcpy )(char  * restrict  s1 , const  char  * restrict  s2 )
 { 
     char  * dst  =  s1 ; 
     const  char  * src  =  s2 ; 
     / *循环复制。* / 
     while  ((* dst ++  =  * src ++ ) !=  '\ 0' )
         ;                / *此循环的主体留空。* / 
     / *返回目标字符串。* /
     返回 s1 ; 
 }

strlen函数

size_t strlen(const char *s);

strlen()函数应计算字符串中的s点数,不包括终止空字节。它返回字符串中的字节数。没有值用于表示错误。

以下是公共域实现strlen

 #include  <string.h>
 / * strlen * / 
 size_t  (strlen )(const  char  * s )
 { 
     const  char  * p  =  s ; 
     / *循环s中的数据。* / 
     while  (* p  !=  '\ 0' )
         p ++ ; 
     return  (size_t )(p  -  s ); 
 }

strncat函数

char *strncat(char *restrict s1, const char *restrict s2, size_t n);

strncat()函数应该n从指向的数组的末尾追加不超过字节(空字节及其后面的字节未附加)到指向s2的字符串的末尾s1。初始字节s2覆盖结尾处的空字节s1。终止空字节始终附加到结果。如果在重叠的对象之间进行复制,则行为未定义。该函数返回s1

以下是公共域实现strncat

 #include  <string.h>
 / * strncat * / 
 char  * (strncat )(char  * restrict  s1 , const  char  * restrict  s2 , size_t  n )
 { 
     char  * s  =  s1 ; 
     / *循环s1中的数据。* / 
     while  (* s  !=  '\ 0' )
         s ++ ; 
     / * s现在指向s1的尾随空字符,现在
        如果
        在s2中遇到空字符,则从s2 复制到n个字节为s停止
        在这里使用strncpy是不安全的,因为它完全复制n个
        字符,必要时填充NULL填充。* / 
     while  (n  !=  0  &&  (* s  =  * s2 ++ ) !=  '\ 0' ) { 
         n - ; 
         s ++ ; 
     } 
     if  (* s  !=  '\ 0' )
         * s  =  '\ 0' ; 
     返回 s1 ; 
 }

strncmp函数

int strncmp(const char *s1, const char *s2, size_t n);

strncmp()功能必须比较不超过n从阵列指向字节(跟随一个空字节字节不相比)s1到阵列指向s2。非零返回值的符号由在unsigned char比较的字符串中不同的第一对字节的值(均被解释为类型)之间的差的符号确定。有关strcmp返回值的说明,请参阅。

此功能在比较中很有用,因为strcmp函数是。

以下是公共域实现strncmp

 #include  <string.h>
 / * strncmp * / 
 int  (strncmp )(const  char  * s1 , const  char  * s2 , size_t  n )
 { 
     unsigned  char  uc1 , uc2 ; 
     / *无比比较?返回零。* / 
     if  (n  ==  0 )
         返回 0 ; 
     / *循环,比较字节。* / 
     while  (n -  >  0  &&  * s1  ==  * s2 ) {
         / *如果我们已用完字节或命中空值,则返回零,
            因为我们已经知道* s1 == * s2。* / 
         if  (n  ==  0  ||  * s1  ==  '\ 0' )
             返回 0 ; 
         s1 ++ ; 
         s2 ++ ; 
     } 
     uc1  =  (* (unsigned  char  * ) s1 ); 
     uc2  =  (* (unsigned  char  * ) s2 ); 
     返回 ((uc1  <  uc2) ? - 1  : (uc1  >  uc2 )); 
 }

strncpy函数

char *strncpy(char *restrict s1, const char *restrict s2, size_t n);

strncpy()函数应从n指向的数组复制不超过字节(未复制空字节后的字节)到指向s2的数组s1。如果在重叠的对象之间进行复制,则行为未定义。如果指向的数组s2是一个短于n字节的字符串,则应将空字节附加到指向的数组中的副本s1,直到n写入所有字节为止。该函数应返回s1; 没有保留返回值来指示错误。

函数可能不会返回以null结尾的字符串,如果s2字符串长于n字节,则会发生这种情况。

以下是公共域版本strncpy

 #include  <string.h>
 / * strncpy * / 
 char  * (strncpy )(char  * restrict  s1 , const  char  * restrict  s2 , size_t  n )
 { 
     char  * dst  =  s1 ; 
     const  char  * src  =  s2 ; 
     / *一次复制一个字节。* / 
     while  (n  >  0 ) { 
         n - ; 
         if  ((* dst ++  =  * src++ ) ==  '\ 0' ) { 
             / *如果我们到达这里,我们在
                s2 
的末尾找到了一个空字符,所以使用memset在                s1 
             的末尾放置空字节* / memset (dst , '\ 0' , n ); 
             打破; 
         } 
     } 
     返回 S1 ; 
 }

strrchr函数

char *strrchr(const char *s, int c);

strrchr功能类似于strchr功能,所不同的是strrchr将一指针返回到最后的发生cs,而不是第一个。

strrchr()函数应在指向的字符串中找到最后一次出现c(转换为a chars。终止空字节被认为是字符串的一部分。它的返回值类似于strchr返回值。

在历史的某个时刻,这个功能被命名rindex。这个strrchr名字虽然含糊不清,但却符合命名的一般模式。

以下是公共域实现strrchr

 #include  <string.h>
 / * strrchr * / 
 char  * (strrchr )(const  char  * s , int  c )
 { 
     const  char  * last  =  NULL ; 
     / *如果我们要查找的字符是终止null,
        我们只需要查找该字符,因为
        字符串中
     只有一个字符。* / if  (c  ==  '\ 0' )
         返回 strchr (s , c ); 
     / *循环,在命中NULL之前找到最后一个匹配。* / 
     同时 ((s  =  strchr (s , c )) !=  NULL ) { 
         last  =  s ; 
         s ++ ; 
     } 
     return  (char  * ) last ; 
 }

不太常用的字符串函数

较少使用的功能是:

  • memchr – 在内存中找到一个字节
  • memcmp – 比较内存中的字节
  • memcpy – 复制内存中的字节
  • memmove – 使用重叠区域复制内存中的字节
  • memset – 在内存中设置字节
  • strcoll – 根据特定于语言环境的整理顺序比较字节
  • strcspn – 获取互补子串的长度
  • strerror – 获取错误消息
  • strpbrk – 扫描一个字符串的字符串
  • strspn – 获取子字符串的长度
  • strstr – 找一个子串
  • strtok – 将字符串拆分为标记
  • strxfrm – 变换字符串

复制功能

memcpy函数

void *memcpy(void * restrict s1, const void * restrict s2, size_t n);

memcpy()函数应将n指向的对象中的字节复制到指向s2的对象中s1。如果在重叠的对象之间进行复制,则行为未定义。该函数返回s1

因为函数不必担心重叠,所以它可以做最简单的复制。

以下是公共域实现memcpy

 #include  <string.h>
 / * memcpy * / 
 void  * (memcpy )(void  *  restrict  s1 , const  void  *  restrict  s2 , size_t  n )
 { 
     char  * dst  =  s1 ; 
     const  char  * src  =  s2 ; 
     / *循环和复制。* / 
     while  (n -  !=  0 )
         * dst ++  =  * src ++ ; 
     返回 s1 ;
 }
memmove函数

void *memmove(void *s1, const void *s2, size_t n);

memmove()函数应将n指向的对象中的字节复制到指向s2的对象中s1。复制发生就好像n从物体字节指向s2首先拷贝到一个临时数组n不重叠的对象指向的字节s1s2,然后n从临时数组字节被复制到对象指向s1。该函数返回值s1

在不使用临时数组的情况下实现此操作的简单方法是检查阻止升序复制的条件,如果找到,则执行降序复制。

以下是一个公共域,但不是完全可移植的,实现memmove

 #include  <string.h>
 / * memmove * / 
 void  * (memmove )(void  * s1 , const  void  * s2 , size_t  n ) 
 { 
    / *注意:这些不必指向unsigned chars * / 
    char  * p1  =  s1 ; 
    const  char  * p2  =  s2 ; 
    / *测试重叠以防止升序复制* / 
    if  (p2  <  p1  &&  p1  <  p2  +  n ) {
        / *做一个降序复制* / 
        p2  + =  n ; 
        p1  + =  n ; 
        while  (n -  !=  0 ) 
            *  - p1  =  *  - p2 ; 
    }  else  
        while  (n -  !=  0 ) 
            * p1 ++  =  * p2 ++ ; 
    返回 s1 ;  
 }

比较功能

memcmp函数

int memcmp(const void *s1, const void *s2, size_t n);

memcmp()函数应将指向的对象的第一个n字节(每个解释为unsigned char)与指向的对象s1的第一个n字节进行比较s2。非零返回值的符号应由unsigned char在被比较的对象中不同的第一对字节(均被解释为类型)的值之间的差的符号确定。

以下是公共域实现memcmp

 #include  <string.h>
 / * memcmp * / 
 int  (memcmp )(const  void  * s1 , const  void  * s2 , size_t  n )
 { 
     const  unsigned  char  * us1  =  (const  unsigned  char  * ) s1 ; 
     const  unsigned  char  * us2  =  (const  unsigned  char  * ) s2 ; 
      (n -  !=  0) { 
         如果 (* US1  !=  * US2 )
             回报 (* US1  <  * US2 ) ? - 1  : + 1 ; 
         us1 ++ ; 
         us2 ++ ; 
     } 
     return  0 ; 
 }
strcollstrxfrm功能

int strcoll(const char *s1, const char *s2);

size_t strxfrm(char *s1, const char *s2, size_t n);

ANSI C标准指定了两个特定于语言环境的比较函数。

strcoll函数比较字符串指向s1到字符串指向s2,既解释为适合于LC_COLLATE当前区域的类别。返回值类似于strcmp

strxfrm函数转换指向的字符串,s2并将结果字符串放入指向的数组中s1。转换是这样的:如果strcmp函数应用于两个转换的字符串,则它返回大于,等于或小于零的值,对应于strcoll应用于相同的两个原始字符串的函数的结果。只有n字符放在指向的结果数组中s1,包括终止空字符。如果n为零,s1则允许为空指针。如果在重叠的对象之间进行复制,则行为未定义。该函数返回已转换字符串的长度。

这些函数很少使用,对代码也很重要,因此本节没有代码。

搜索功能

memchr函数

void *memchr(const void *s, int c, size_t n);

memchr()函数应该在指向的对象的初始字节(每个被解释为)中找到第一次出现c(转换为a unsigned char)。如果未找到,则返回空指针。 nunsigned charscmemchr

以下是公共域实现memchr

 #include  <string.h>
 / * memchr * / 
 void  * (memchr )(const  void  * s , int  c , size_t  n )
 { 
     const  unsigned  char  * src  =  s ; 
     unsigned  char  uc  =  c ; 
     while  (n -  !=  0 ) { 
         if  (* src  ==  uc )
             return  (void  * ) src ; 
         SRC++ ; 
     } 
     return  NULL ; 
 }
strcspnstrpbrkstrspn功能

size_t strcspn(const char *s1, const char *s2);

char *strpbrk(const char *s1, const char *s2);

size_t strspn(const char *s1, const char *s2);

strcspn函数计算指向的字符串的最大初始段的长度,该字符串s1完全由不是指向的字符串的字符组成s2

strpbrk函数定位指向的字符串s1中任何字符指向的字符串中的第一个匹配项s2,返回指向该字符的指针或未找到的空指针。

strspn函数计算指向的字符串的最大初始段的长度,该段的长度s1完全由指向的字符串中的字符组成s2

除了测试和返回值之外,所有这些函数都是相似的。

以下是公共领域的实施strcspnstrpbrk以及strspn

 #include  <string.h>
 / * strcspn * / 
 size_t  (strcspn )(const  char  * s1 , const  char  * s2 )
 { 
     const  char  * sc1 ; 
     for  (sc1  =  s1 ;  * sc1  !=  '\ 0' ;  sc1 ++ )
         if  (strchr (s2 , * sc1 ) !=  NULL )
             return  (sc1  -  s1 ); 
     返回 sc1  -  s1 ;             / *终止空值匹配* / 
 }
 #include  <string.h>
 / * strpbrk * / 
 char  * (strpbrk )(const  char  * s1 , const  char  * s2 )
 { 
     const  char  * sc1 ; 
     for  (sc1  =  s1 ;  * sc1  !=  '\ 0' ;  sc1 ++ )
         if  (strchr (s2 , * sc1 ) !=  NULL )
             return  (char  * )sc1 ;
     返回 NULL ;                 / *终止空值匹配* / 
 }
 #include  <string.h>
 / * strspn * / 
 size_t  (strspn )(const  char  * s1 , const  char  * s2 )
 { 
     const  char  * sc1 ; 
     for  (sc1  =  s1 ;  * sc1  !=  '\ 0' ;  sc1 ++ )
         if  (strchr (s2 , * sc1 ) ==  NULL )
             return  (sc1  -  s1 ); 
     返回 sc1 -  s1 ;             / *终止空值不匹配* / 
 }
strstr函数

char *strstr(const char *haystack, const char *needle);

strstr()函数应在由指向的字符串中haystack的字节序列(不包括终止空字节)指向的字符串中找到第一个匹配项needlehaystack如果未找到匹配项,则函数返回指向匹配字符串的指针或空指针。如果needle是空字符串,则返回该函数haystack

以下是公共域实现strstr

 #include  <string.h>
 / * strstr * / 
 char  * (strstr )(const  char  * haystack , const  char  * needle )
 { 
     size_t  needlelen ; 
     / *检查零针盒。* / 
     if  (* needle  ==  '\ 0' )
         return  (char  * ) haystack ; 
     needlelen  =  strlen的(针); 
     for  (;  (haystack  =  strchr (haystack, * needle )) !=  NULL ;  haystack ++ )
         if  (memcmp (haystack , needle , needlelen ) ==  0 )
             return  (char  * ) haystack ; 
     返回 NULL ; 
 }
strtok函数

char *strtok(char *restrict s1, const char *restrict delimiters);

一系列调用将strtok()指向的字符串s1分解为一系列标记,每个标记由指向的字符串中的一个字节分隔delimiters。序列中的第一个调用s1作为其第一个参数,然后是使用空指针作为其第一个参数的调用。指向的分隔符字符串delimiters可能与呼叫不同。

序列中的第一个调用搜索指向的字符串,查找s1当前分隔符字符串中未包含的第一个字节delimiters。如果没有找到这样的字节,则指向的字符串中没有标记,s1并且strtok()应返回空指针。如果找到这样的字节,则它是第一个令牌的开头。

strtok()然后,该函数从那里搜索当前分隔符字符串中包含的一个字节(或多个连续字节)。如果没有找到这样的字节,则当前标记扩展到指向的字符串的末尾s1,随后对标记的搜索将返回空指针。如果找到这样的字节,它将被空字节覆盖,该空字节终止当前令牌。该strtok()函数保存指向后续字节的指针,从该字节开始下一次搜索令牌。

每个后续调用,使用空指针作为第一个参数的值,从保存的指针开始搜索并按上述方式运行。

strtok()功能不必是可重入的。不需要可重入的函数不需要是线程安全的。

因为strtok()函数必须在调用之间保存状态,并且你不能同时使用两个标记器,所以Single Unix Standard定义了一个类似的函数,strtok_r()它不需要保存状态。它的原型是这样的:

char *strtok_r(char *s, const char *delimiters, char **lasts);

strtok_r()函数s将以null结尾的字符串视为由分隔符字符串中的一个或多个字符的跨度分隔的零个或多个文本标记的序列delimiters。该参数持续指向用户提供的指针,该指针指向strtok_r()继续扫描相同字符串所需的存储信息。

在第一次调用中strtok_r()s指向以null结尾的字符串,delimiters以空字符结尾的分隔符字符串,并lasts忽略指向的值。该strtok_r()函数应返回指向第一个标记的第一个字符的指针,在s返回的标记之后立即写入空字符,并更新指向哪个lasts点的指针。

在后续调用中,s是一个空指针,并且lasts应与前一个调用保持不变,以便后续调用应在字符串中移动s,返回连续的令牌,直到没有令牌保留。分隔符字符串delimiters可以与呼叫不同。如果没有令牌s,则返回NULL指针。

以下公共域代码,strtok并将strtok_r前者编码为后者的特例:

 #include  <string.h>
 / * strtok_r * / 
 char  * (strtok_r )(char  * s , const  char  * delimiters , char  ** lasts )
 { 
     char  * sbegin , * send ; 
     sbegin  =  s  ? s  : * 持续; 
     sbegin  + =  strspn (sbegin , delimiters ); 
     if  (* sbegin  ==  '\ 0' ) { 
         *lasts  =  “” ; 
         返回 NULL ; 
     } 
     send  =  sbegin  +  strcspn (sbegin , delimiters ); 
     if  (* send  !=  '\ 0' )
         * send ++  =  '\ 0' ; 
     * 持续 =  发送; 
     返回 sbegin ; 
 } 
 / * strtok * / 
 char  * (strtok )(char  * restrict  s1 , const  char * 限制 分隔符)
 { 
     static  char  * ssave  =  “” ; 
     return  strtok_r (s1 , delimiters , &ssave ); 
 }

杂项功能

这些功能不适合上述类别之一。

memset函数

void *memset(void *s, int c, size_t n);

memset()函数转换cunsigned char,然后将字符存储到n指向的内存的第一个字节s

以下是公共域实现memset

 #include  <string.h>
 / * memset * / 
 void  * (memset )(void  * s , int  c , size_t  n )
 { 
     unsigned  char  * us  =  s ; 
     unsigned  char  uc  =  c ; 
     while  (n -  !=  0 )
         * us ++  =  uc ; 
     返回 小号; 
 }
strerror函数

char *strerror(int errorcode);

此函数返回与参数对应的特定于语言环境的错误消息。根据具体情况,这个功能可能很容易实现,但是这个作者不会这样做,因为它有所不同。

单Unix系统版本3有一个变体strerror_r,有这个原型:

int strerror_r(int errcode, char *buf, size_t buflen);

此函数存储消息buf,其长度大小buflen

示例

要确定字符串中的字符数,请使用以下strlen()函数:

    #include  <stdio.h>
    #include  <string.h>
    ... 
    int  length , length2 ; 
    char  * turkey ; 
    static  char  * flower =  “begonia” ; 
    static  char  * gemstone = “ruby” ;
    
    length  =  strlen (flower ); 
    printf (“长度=%d \ n ” , 长度);  //打印'长度= 7'长度
    2  =  strlen (宝石);
    
    火鸡 =  malloc的( 长度 +  长度2  +  1 ); 
    if  (turkey ) { 
      strcpy ( turkey , gemstone ); 
      strcat ( 土耳其, 花); 
      printf ( “%s \ n ” , 土耳其);  // 
      免费打印'红宝石秋海棠' ( 火鸡 ); 
    }

请注意,为“turkey”分配的内存量是一个加上要连接的字符串长度的总和。这是用于终止空字符,不计入字符串的长度。

练习

  1. 字符串函数使用大量循环结构。有没有办法可以解开循环?
  2. 现在库中可能缺少哪些功能?

猜你想读:《C编程.中级C》7.进一步教学

THE END
分享