字符串与数组

来源:互联网 发布:ubuntu mysql 配置 编辑:程序博客网 时间:2024/05/16 08:25

5.字符串与数组
    在许多程序中,字符串(或字符数组)是很重要的一部分。在GNU C库中提供了广泛字符串工具函数,包括字符串复制、串联、比较、搜索。这些函数中的大多数都能够在内存的任何地方操作;例如,函数memcpy能够用于任何一种数组中拷贝内容。
    通常,一些C语言的初学者是直接将这些复制到自己的代码中,但当他们越来越熟悉的时候,在使用这些函数时,通常考虑更多的是可维护性、效率和可移植性。
    举例说,你可以在两行C代码中比较两个字符串,但如果你使用内置strcmp函数,你出错的机会会更少。同时,由于这些库函数是经过了优化的,所以使用它们会使你的程序运行得更快。
    5.1字符串表示法
    这个小节是对一个C程序设计初学者做一个关于字符串概念的概要介绍。这里将说明在C语言中如何表示一个字符串,以及一些通常的缺陷。如果你已经很熟悉它们,可以跳过这一小节。
    一个字符串是字符数组。但字符串变量通常被说明成一个字符型指针char *。这种字符串变量不包括空格符,它将被存话在内存中的某个地方,或者是一个常量,或者是一个动态分配的内存。在内存中的地址将存入这个指针变量,当然,你也可以将一个空指针存入指针变量。空指针没有指向任何东西,所以用空指针表示字符串将出错。
    按习惯,在字符串后面加上一个空字符“。例如,你想测试字符型指针p是不是指向一个以空字符结束字符串,你可以使用!*p或*p=’ '。
     一个空字符与一个空指针在概念上是很不同的,尽管它们都表示为整数0。
字符串在C语言源程序中,将其包含在双引号(" ")之内。在ISO C中,"a" "b"与"ab"相同。在GNU C中不允许修改字符串中的内容,因为它是被存放为只读的。
    字符数组如果声明为const,则不能修改。而通常更好的方法是将其定义为const char *类型,因为这样,C编译器会检测到想修改这个字符串的企图。
    通常字符数组在分配内存时,会加上一个用于存放空字符串(这个空字符串用来标识字符串结束)。在这个文档中,内存分配大小(allocation size)用来表示这个字符串所占用的内存总和,而长度(length)则用来表示不包括空字符在内的总长度。
    尝试往字符串变量中存放超过其分配大小的字符是一个声名狼籍的程序错误。当你在编写程序时,请一定要提起注意。有许多库函数可以帮助你完成这个任务。另外,请牢记,你需要为表示字符串终了的空字符留下一个内存空间。
5.2字符串与数组函数的惯例
    这一小节将描述所有基于任意数组或任意内存块的函数,讲述这些函数的一些通性的东西。
    对任意内存块操作的函数的名字都是以mem开头的(如memcpy),并且总是带上一个参数,用来指定所操作的内存块大小。这些函数返回 void *类型的数组,数组的成员是bytes型的。你可以传送任何一种类型的指针给这些函数,而且可以使用sizeof操作符来计算它的大小。
    相对应的,专门处理字符串的函数则是以str开头的(如strcpy),这些函数都是以用空字符结束的字符串代替显式的size参数。(虽然有些函数也接受指定的最大长度,但它们同样要检测结束字符串的空字符。这个函数返回char *类型的数组,这些数组的成员是char型的。
    5.3字符串长度
    我们可以使用strlen函数获得一个字符串的长度。这个函数在头文件string.h中声明。
    函数:size_t strlen(const char *s)
    这个函数将返回以空字符结束的字符串s的长度。
    例如:
    strlen ("hello, world")    (值为12,加上一个空字符)
    当用于字符数组时,strlen函数将返回已存放的字符串内存分配大小,而非整个数组的内存分配大小。我们可以使用sizeof操作符来获取字符数组的内存分配大小:
    char string[32] = "hello, world";
    sizeof (string) (其值为32)
    strlen (string) (其值为12,加上一个空字符)
    5.4复制与联接字符串
    我们可以使用这一小节中的函数复制字符串和字符数组中的内容,或者将一个字符串的内容附加到另一个字符串中去。这些函数在头文件string.h中声明:
    有一个规律可以帮助你记住这一小节中所有函数的参数位置:目标数组都在源数组的左边!所有的函数都返回目标数组的地址。
    如果源数组与目标数组或在物理地址上有重迭的话,大多数函数都无法正常地工作。例如,如果目标数组的头与源数组的尾在物理地址上重迭,那么源数组中的一部分内容就会在复制之前被覆盖。甚至可能出现使得标识字符串结束的空字符丢失,而使拷贝无休止地无意义地进行着。
    所有会因为这个问题而出错的函数,都会在本手册中显式标识出来。除了这个小节里的函数外,还有sprintf函数(参见格式化输出函数章节)以及scanf函数(参见格式化输入函数章节)。
    函数:void * memcpy (void *to, const void *from, size_t size)
这个函数会从数组from的开头处,复制size个字符,并从头写入数组to中。这个函数的参数from和to如果是有重迭的两个数组,那么就会出错。这种情况,请使用memmove函数来代替它。
    Memcpy函数返回to的地址;
    以下是一个使用memcpy复制一个数组中内容的例子:
    struct foo *oldarray, *newarray;
    int arraysize;
    ...
    memcpy (new, old, arraysize * sizeof (struct foo));
    函数:void * memmove (void *to, const void *from, size_t size)
    从from中拷贝size字节到to中,即使这两个内存块有重迭也不影响执行效果。
    函数:void * memccpy (void *to, const void *from, int c, size_t size)
    这个函数将从form中拷贝不超过size字节到to中去,在拷贝中如果有一个字节与c匹配,就中止拷贝。该函数将返回一个指针。如果在拷贝时发现了c,这个指针指向to,如果没有,就是一个空指针。
    函数:void * memset (void *block, int c, size_t size)
    该函数将复制size个c(转换成为char型)到block中,返回block的值。
    函数:char * strcpy (char *to, const char *from)
    复制字符串from到字符串to中去。就象memcpy一样,这个函数也无法处理两个字符串有重迭部分的情况。该返回to的值。
    函数:char * strncpy (char *to, const char *from, size_t size)
    这个函数与strcpy类似,区别在于strncpy将精确地拷贝size字节到to中去。
如果from的长度大于size,那么strncpy仅拷贝from中的前size个字符。要注意的是,这种情况下,将不会往to中写入表示结束的空字符。
如果from的长度小于size,那么strncpy将拷贝from中所有内容,然后加上一些空字符,使其够size字节。这是十分有用的,但仅在ISO C中可用。
    Strncpy也无法正确处理from和to有重迭的情况。
    使用strncpy代替strcpy可以避免尝试对to所分配空间之后的操作。但是,如果你要把一个较小的字符串,写到一个大的缓冲中,会使你的程序运行得更慢,因为这时由于size很大,程序花了许多时间做无谓的工作:填写大量的空字符。
    函数:char * strdup (const char *s)
    拷贝一个以空字符结束的字符串到一个新分配的字符串中。这个新字符串将自动调用malloc函数来分配。如果malloc函数无法为这个新字符串分配空间,strdup将返回一个空指针。如果能够为其分配空间,将返回这个新字符串的地址指针。
    函数: char * strndup (const char *s, size_t size)
    它与strdup类似,区别在于strndup将复制不多于size字节的字符到新字符串中。
    如果s的长度大于size,那么strndup将复制size个字符,再添上一个空字符串。否则,就会完整地被复制。
    这个函数与strncpy不同的是,它将保证拷贝出来的字符串一定有表示结束的空字符。
    函数:char * stpcpy (char *to, const char *from)
    与strcpy类似,区别在于,stpcpy将返回一个指向字符串to结尾的指针(也就是,指向那个表示结束的空字符),而不指向字符串的开始。
例如,下面这个程序使用stpcpy将’foo’和’bar’连接成为’foobar’,然后再打印出来:
#include <string.h>
#include <stdio.h>
int
main (void)
{
  char buffer[10];
  char *to = buffer;
  to = stpcpy (to, "foo");
  to = stpcpy (to, "bar");
  puts (buffer);
  return 0;
}
    这个函数不属于ISO和POSIX标准,所以并不经常在UNIX系统上使用,但别自己去创建这个函数,因为可能在MS-DOS中就有。
    这个函数也无法正确处理两个字符串有重迭部分的情况。
    函数:char * stpncpy (char *to, const char *from, size_t size)
    它与stpcpy类似,区别在于,stpncpy将精确地只拷贝size个字符。
如果字符串from的长度比size大,那么stpncpy将只复制前size个字符,然后返回一个指向最后拷贝的那个字符的地址。要注意的是,在这种情况下,最后并没有一个表示字符串结束的空字符。
    如果from的长度小于size,那么,stpncpy将拷贝from中的所有字符串,然后在后面加上(size-form长度)个空字符。它将返回一个指向第一个空字符的指针。
    这个函数并不属于ISO和POSIX标准,但却在GNU C库的开发经常用到。
它也无法正确地处理源、目标两个字符串有重迭部分的情况。
    函数:char * strdupa (const char *s)
    它与strdup函数十分类似,区别在于,它不使用malloc来分配一个新字符串,而是使用alloc来分配。
    很明显,strdupa仅适合于宏,也就是你无法获得这个函数的地址。虽然有这个限制,但还是有它有用的一面。下面这个程序说明的有时使用malloc将付出更大的代价。
#include <paths.h>
#include <string.h>
#include <stdio.h>
const char path[] = _PATH_STDPATH;
int
main (void)
{
  char *wr_path = strdupa (path);
  char *cp = strtok (wr_path, ":");
  while (cp != NULL)
     {
      puts (cp);
       cp = strtok (NULL, ":");
     }
  return 0;
}
    请注意直接使用目录调用strtok是非法的。
    这个函数仅在GNU C中能够使用。
    函数:char * strndupa (const char *s, size_t size)
    完成功能与strndup类似,不过它像strdupa一样使用alloca来为新字符串分配内存空间。它的优缺点与strdupa一样。
这个函数也只能用于宏,因为无法得到这个函数的地址。
    它仅在GNU C中能够使用。
    函数:char * strcat (char *to, const char *from)
    与strcpy类似,区别在于,它是将字符串from中的内容增加到字符串to的后面。而不是覆盖字符串to。字符串from中的第一个字符将覆盖掉to中原来最后的空字符。
    以下是一个与strcat等价的定义:
char *
strcat (char *to, const char *from)
{
  strcpy (to + strlen (to), from);
  return to;
}
    它无法正确处理from与to两个字符串有重迭部分的情况。
    函数:char * strncat (char *to, const char *from, size_t size)
    它与strcat类似,区别在于附加到字符串to后面的字符将不超过size个。在to的最后将保证有一个空字符,也就是说添加后,总的分配空间将新增size+1。
    这个函数可以使用下面这个程序实现:
char *
strncat (char *to, const char *from, size_t size)
{
  strncpy (to + strlen (to), from, size);
  return to;
}
    同样的,它也无法正确处理from与to有重迭部分的情况。
    以下是一个使用strncpy和strncat函数的实例。注意它们使用的方法,如何避免size过大。
#include <string.h>
#include <stdio.h>
#define SIZE 10
static char buffer[SIZE];
main ()
{
  strncpy (buffer, "hello", SIZE);
  puts (buffer);
  strncat (buffer, ", world", SIZE - strlen (buffer) - 1);
  puts (buffer);
}
    这个程序的输出为:
hello
hello, wo
    函数:void * bcopy (void *from, const void *to, size_t size)
    这个函数已经被memmove取代,它起源于BSD系统。注意,它并不等同于memmove函数,参数的顺序不同。
    函数:void * bzero (void *block, size_t size)
    这个函数已经被memset取代,它起源于BSD系统。注意,它并不如memset那么通用,因为bzero只能存入0值。
    5.5字符串与数组的比较
    你可以使用这一小节里的函数进行字符串或字符数组内容比较。它们不仅可以用来检查字符串是否相同,还可以在字符串排序时起作用。
    与C语言的其它函数不大相同,字符串比较函数返回非零值,是表示它们不相等,而非相等。返回值是负数代表第一个字符串小于第二个字符串,如果返回的是正数则代表第一个字符串大于第二个字符串。
    这些函数通常仅用于检查两个字符串是否相等。如:`! strcmp (s1, s2)'.
    所有的这些函数都在头文件string.h中声明。
    函数:int memcmp (const void *a1, const void *a2, size_t size)
    函数memcmp用于比较字符串s1与s2的前size个字符。
    如果两上字符块相同,memcmp将返回0。
    对于任意的字符数组,memcmp函数通常用于测试它们是否相等。而不常进行byte-wise的字符串比较。如果是byte-wise比较,将返回一个表示两个字符串之间的关系的浮点数。
    如果要比较的对象中包含一些由于边界对齐需求而填入结构对象中的空格、联合(union)结束的额外空格、字符串所分配的空间未使用完的部分引起的“holes”的话,最好使用memcmp来完成。这些“holes”的内容是不确定的,在执行byte-wise比较时结果也是不明确的。
    例如,给出一个如下的结构定义:
struct foo
  {
    unsigned char tag;
    union
       {
         double f;
        long i;
          char *p;
       } value;
  };
    如果你要比较两个struct foo对象的话,建议最好使用memcmp。
    函数:int strcmp (const char *s1, const char *s2)
    这个函数用来比较s1和s2字符串,这个函数将返回一个值,它的符号与第一对不同的字符的比较结果相关。
    如果两个字符串相等的话,strcmp将返回0。
    如果s1是s2的一个子串的话,s1小于s2。
    函数:int strcasecmp (const char *s1, const char *s2)
    与strcmp类似,不同之处在于,strcasecmp不区分大小写。
    Strcasecmp源于BSD系统。
    函数:int strncasecmp (const char *s1, const char *s2, size_t n)
    与strncmp类似,不同之处在于,strncasecmp不区分大小写。
    Strncasecmp是GNU扩展函数。
    函数:int strncmp (const char *s1, const char *s2, size_t size)
    此函数与strcmp极为类似。不同之处是,strncmp函数是指定比较size个字符。也就是说,如果字符串s1与s2的前size个字符相同,函数返回值为0。
    这里是两个使用strcmp和strncmp的实例。在本例中,假定使用ASCII字符集(如果你是使用其它字符集--如EBCDIC--的话,返回的值可能不同,因为在不同的字符集中顺序不同。)
strcmp ("hello", "hello")
    => 0    /* 这两个字符串相同。 */
strcmp ("hello", "Hello")
    => 32   /* 大小写敏感,h-H=32 */
strcmp ("hello", "world")
     => -15  /* h-w=-15 */
strcmp ("hello", "hello, world")
     => -44  /* 空字符与逗号不同 */
strncmp ("hello", "hello, world", 5)
    => 0    /* 前5个值是相同的,所以返回0 */
strncmp ("hello, world", "hello, stupid world!!!", 5)
     => 0    /* 前5个值是相同的,所以返回0 */
    函数:int bcmp (const void *a1, const void *a2, size_t size)
    这是一个过时的memcmp函数的别名,起源于BSD。
    5.6 Collation函数
    在相同的地区,词典序与严格的字符序不尽相同。例如,在西班牙文字中常不考虑整理的需要,使用一些标识来表示重音。另一方面,字符序列“ll”将被认为是一个单独的字符“l”。
    我们可以使用strcoll和strxfrm函数(在头文件string.h中声明)来实现按当地字符序来整理并比较字符串。使用的不同地区的字符集,可在LC_COLLATE类中设置,具体参见地区和国际化那一章节。
    在标准C方言中,strcoll与strcmp相同。
    使用这些函数进行比较时,它们需先将字符串映射成为本地字符序,然后再进行比较。
    函数strcoll为了完成这样的比较,会自动地暗中完成这个映射工作。与此相反,strxfrm函数则是明确地完成映射。如果你要使用一个相同的字符串进行多次比较,那么更有效的方法可能是使用strxfrm函数将它们一次转换完成,尔后再使用strcmp进行比较。
    函数:int strcoll (const char *s1, const char *s2)
    此函数与strcmp类似,区别在于,它使用本地字符充(LC_COLLATE设置的)。
    以下是一个字符串排序的例子,在此例中使用了strcoll进行字符串比较。实际的排序算法未在此处写出,它出自qsort(参见数组排序函数小节)。以下的代码仅说明比较的工作。(在本节的后面部分,还可以看到使用strxfrm实现)。
/* This is the comparison function used with qsort. */
int
compare_elements (char **p1, char **p2)
{
  return strcoll (*p1, *p2);
}
/* This is the entry point--the function to sort
    strings using the locale's collating sequence. */
void
sort_strings (char **array, int nstrings)
{
  /* Sort temp_array by comparing the strings. */
  qsort (array, sizeof (char *),
          nstrings, compare_elements);
}
    函数:size_t strxfrm (char *to, const char *from, size_t size)
    函数strxfrm根据本地字符集进行转换、整理,然后存入数组中。它只转换前size个(包括结束的空字符),并存盘。
    要注意的是,当from和to有重迭部分将导致结果不明确。参见复制与连接小节。
    这个函数的返回值是转换后的字符长度。这个值不受size的影响,但如果返回值大于或等于size的话,表示并未转换完数组中所有的内容。在这种情况下,你仅能得到部分转换的值,如果要整个字串,则带上一个更大的size,重新调用一遍strxfrm。
    转换完后的字符串可能比原来的字符串长,也可能更短。
    如果size是0的话,将没有字符串被转换。在这种情况下,strxfrm简单地返回字符串的字符个数。这对于决定需要多少的存储空间十分有用。
这儿是一个使用strxfrm进行多次字符串比较的例子。它完成与上例中一样的功能,但运行得更快,因为strxfrm将转换工作一次完成,无须每次比较时进行转换。
struct sorter { char *input; char *transformed; };
/* This is the comparison function used with qsort
      to sort an array of struct sorter. */
int
compare_elements (struct sorter *p1, struct sorter *p2)
{
  return strcmp (p1->transformed, p2->transformed);
}
/* This is the entry point--the function to sort
      strings using the locale's collating sequence. */
void
sort_strings_fast (char **array, int nstrings)
{
  struct sorter temp_array[nstrings];
  int i;
  /* Set up temp_array.  Each element contains
      one input string and its transformed string. */
  for (i = 0; i < nstrings; i++)
     {
      size_t length = strlen (array[i]) * 2;
       char *transformed;
         size_t transformed_lenght;
      temp_array[i].input = array[i];
       /* First try a buffer perhaps big enough.  */
          transformed = (char *) xmalloc (length);
      /* Transform array[i].  */
       transformed_length = strxfrm (transformed, array[i], length);
      /* If the buffer was not large enough, resize it
          and try again.  */
         if (transformed_length >= length)
         {
           /* Allocate the needed space. +1 for terminating
              NUL character.  */
           transformed = (char *) xrealloc (transformed,
                                           transformed_length + 1);
         /* The return value is not interesting because we know
              how long the transformed string is.  */
            (void) strxfrm (transformed, array[i], transformed_length + 1);
           }
          temp_array[i].transformed = transformed;
       }
  /* Sort temp_array by comparing transformed strings. */
   qsort (temp_array, sizeof (struct sorter),nstrings, compare_elements);
  /* Put the elements back in the permanent array
      in their sorted order. */
  for (i = 0; i < nstrings; i++)
     array[i] = temp_array[i].input;
  /* Free the strings we allocated. */
       for (i = 0; i < nstrings; i++)
   free (temp_array[i].transformed);
}
    兼容性提示:字符串collation函数是ISO C的新功能。老的C版本无此功能。
    5.7查找函数
    这一小节讲述一些字符串、字符数组内进行各种各样的搜索操作的函数,这些函数在头文件string.h中声明。
    函数:void * memchr (const void *block, int c, size_t size)
    此函数在字符串block的前size的字符中查找字符c(参数的数据类型是int,运行是将转换成为cahr类型)。如果找到,该函数将返回指向这个值的指针;如果无匹配的结果,将返回空指针。
    函数:char * strchr (const char *string, int c)
    此函数在字符串string(以空字符结束的字符串)中查找字符c参数的数据类型是int,运行是将转换成为cahr类型)。如果找到,该函数将返回指向这个值的指针;如果无匹配的结果,将返回空指针。
    例如:
strchr ("hello, world", 'l')
     => "llo, world"
strchr ("hello, world", '?')
     => NULL
    表示结束的空字符被认为是字符串的一部分,所以你可以使用这个函数获得指向字符串结尾处的指定(也就是用NULL作参数)。
    函数:char * index (const char *string, int c)
    index是strchr的另一个名字,它们完全一样。
    函数:char * strrchr (const char *string, int c) 
本文的链接为:http://oldsite.linuxaid.com.cn/training/showtri.jsp?i=90
作者为: fjxufeng(风过留枫)
    此函数与strchr类似,区别在于,strchr是从头往后找,而strrchr则是从最后面往前找。例如:
strrchr ("hello, world", 'l')
     => "ld"
    函数:char * rindex (const char *string, int c)
rindex是strrchr的另一个名字,它们完全一样。
    函数:char * strstr (const char *haystack, const char *needle)
    此函数与strchr类似,不同之处是strstr是在字符串haystack中查找子串needle,而不是一个字符。它将返回这个子串所在位置,如果没有找到,将返回空指针。如果needle是一个空字符串,函数将返回haystack。
    例如:
strstr ("hello, world", "l")
    => "llo, world"
strstr ("hello, world", "wo")
    => "world"
    函数:void * memmem (const void *haystack, size_t haystack-len,const void *needle, size_t needle-len)
    此函数与strstr类似,不同之处是字符串needle和haystack都是字符数组,而不是以空字符结束的字符串。Needle-len是字符串needle的长度,haystack-len则是haystack的长度。这个函数是GNU C扩展的。
    函数:size_t strspn (const char *string, const char *skipset)
    函数strcspn(字符串例外范围)用于统计字符串string中包括skipset的最大子串长度,在skipset中的字符顺序无关紧要。例如:
strspn ("hello, world", "abcdefghijklmnopqrstuvwxyz")
     => 5
    函数:size_t strcspn (const char *string, const char *stopset)
    函数strcspn(字符串例外范围)用于统计字符串string中不包括stopset的最大子串长度,例如:
strcspn ("hello, world", "  ,.;!?")
     => 5
    函数:char * strpbrk (const char *string, const char *stopset)
函数strpbrk与strcspn关,它将返回一个指针,指向不包括stopset的子串后第1个字符,如果在字符串string中没找到stopset中的字符,将返回空指针。例如:
strpbrk ("hello, world", "  ,.;!?")
     => ", world"
5.8在字符串中查找
    有时在你的程序中会需要进行一些词法分析、句法分析,例如分解一个命令行。你可以使用strtok函数,这个函数在头文件string.h中声明。
    函数:char * strtok (char *newstring, const char *delimiters)
    可以通过调用strtok函数将一个字符串分成几个部分。
    第一次调用strstok函数时,应该是字符串newstring做为参数。Strtok函数会通过这个调用设置一些状态信息。后面的 strtok函数调用,将以null为参数(newstring),继续进行分解。当遇到一个新的不是null为参数的strstok函数调用,将重新初始化状态信息。库函数保证不会中途影响。
    参数delimiters是用来指定分割不同部分的字符。所有这些字符都将被丢弃。第一个不是delimiters的成员的字符是下一个token的开始,当另一个成员字符被发现,则表示这个token结束。函数返回这个token。
    在下一次调用strtok时,将继续上一次的工作,找下一个token。要注意的是,每个分隔符不一定要是完全相同的,只要属于delimiters就行。
    当字符串newstring被分隔完,或找不到属于delimiter的字符中,strtok将返回一个空指针。
    警告:由于strtok会在分解时修改字符串的值,所以你应该在使用strtok分割时,先将其复制到临时的缓冲区去。如果你让strtok修改了一个程序其它部分的字符串函数,你将会遇到麻烦;因为它们可能还有其他作用。
    如果你操作的字符串是一个常量,而strtok又会试图去修改它,这时程序会导致一个致命错误。
Strtok函数是不可重入的。
以下是一个使用strtok的实例:
#include <string.h>
#include <stddef.h>
...
char string[] = "words separated by spaces -- and, punctuation!";
const char delimiters[] = " .,;:!-";
char *token;
...
token = strtok (string, delimiters);  /* token => "words" */
token = strtok (NULL, delimiters);    /* token => "separated" */
token = strtok (NULL, delimiters);    /* token => "by" */
token = strtok (NULL, delimiters);    /* token => "spaces" */
token = strtok (NULL, delimiters);    /* token => "and" */
token = strtok (NULL, delimiters);    /* token => "punctuation" */
token = strtok (NULL, delimiters);    /* token => NULL */
GNU C库包括两个可以重入的strtok函数。
    函数:char * strtok_r (char *newstring, const char *delimiters, char **save_ptr)
    就象strtok函数一样,strtok_r函数能够连续调用,以将一个字符串分解成为几个token。不同的时下一个strtok_r函数不会破坏这个函数的状态。因为它提供了一个指向不同函数的**save_ptr指针。
    这个函数是POSIX.1b提出的建议,它被许多系统支持,以提供多线程的字符分解。
    函数:char * strsep (char **string_ptr, const char *delimiter)
    另一个可重入的方法是取消了第一个参数。初始时的指针由用户指定,后面调用的指针则由delimiter决定。返回下一个被分解的token。
    这个函数是在4.3BSD系统中引入的,因此被广泛使用着。
以下是一个使用strsep的实例:
#include <string.h>
#include <stddef.h>
...
char string[] = "words separated by spaces -- and, punctuation!";
const char delimiters[] = " .,;:!-";
char *running;
char *token;
...
running = string;
token = strsep (&running, delimiters);    /* token => "words" */
token = strsep (&running, delimiters);    /* token => "separated" */
token = strsep (&running, delimiters);    /* token => "by" */
token = strsep (&running, delimiters);    /* token => "spaces" */
token = strsep (&running, delimiters);    /* token => "and" */
token = strsep (&running, delimiters);    /* token => "punctuation" */
token = strsep (&running, delimiters);    /* token => NULL */

 

 

补充:

memcpy是把source   指向的对象中的n个字符拷贝到destin所指向的对象中,返回指向结果对象的指针。   
memmove也是把source   指向的对象中的n个字符拷贝到destin所指向的对象中,但过程就好象是先把source所指向的对象拷贝到临时数组中,然后在从临时数组拷贝到destin所指的对象中,返回指向结果对象的指针。   
但要注意,除memmove之外的字符串操作函数在拷贝同一个字符串中的字符时,其结果是不确定的。也就是说,memmove可以把自己的一部分拷贝给自己的另一部分。其他函数不行,比如memcpy.

原创粉丝点击