你可以使用这一节说明的函式来复制字串和阵列的内容,或是添加字串的内容到另一个字串, ‘str’和 ‘mem’函式宣告在标头档string.h中而 ‘wstr’跟 ‘wmem’函式宣告在档案wchar.h里,要记得这一节里所提函式的引数顺序有帮助的方法就是跟指定表示式一样,有目的阵列指定在来源阵列的左边,所有这些函式都会传回目的阵列的位址。

[adsense][/adsense]

假如来源跟目的阵列重叠大部分的函式无法正确运作,例如,目的阵列的开头跟来源阵列结尾重叠,来源阵列的部份原始内容可能在复制前就被覆写,更糟的是,在这个情况下的字串函式标记字串结尾的空字元会遗失,复制函式可能在回圈中卡住然后丢弃配置给你程式所有的记忆体。

在重叠阵列之间有复制问题的所有函式都会在手册中说明清楚,除了本节的函式外,有一些函式像是sprintf (见 Formatted Output Functions)和 scanf (见 Formatted Input Functions)。

— 函式: void * memcpy (void *restrict to, const void *restrict from, size_t size)

memcpy 函式复制 from 物件最前面的 size 位元组到 to 物件的最前面,如果 to 和 from 阵列重叠的话,这个函式会变成未定义的;假如有可能重叠可以改用 memmove 。

memcpy 的传回值是 to的值。

这里有一个如何使用memcpy 来复制阵列内容的例子:

          struct foo *oldarray, *newarray;
          int arraysize;
          ...
          memcpy (new, old, arraysize * sizeof (struct foo));

— 函式: wchar_t * wmemcpy (wchar_t *restrict wto, const wchar_t *restrict wfrom, size_t size)

wmemcpy 函式复制 wfrom 物件最前面的 size 宽字元到 wto物件的最前面,如果wto 和 wfrom  阵列重叠的话,这个函式会变成未定义的;假如有可能重叠可以改用 wmemmove 。

下面是 wmemcpy 可能实作的方式但还有最佳化的可能。

          wchar_t *
          wmemcpy (wchar_t *restrict wto, const wchar_t *restrict wfrom,
                   size_t size)
          {
            return (wchar_t *) memcpy (wto, wfrom, size * sizeof (wchar_t));
          }

wmemcpy 的传回值是 wto的值。

此函式在ISO C90 修订1时被提出。

— 函式: void * mempcpy (void *restrict to, const void *restrict from, size_t size)

mempcpy 函式跟 memcpy 函式几乎相同,它复制 from 物件最前面的 size 位元组到 to,它不是传回 to 的值而是传回一个指向 to 物件最前面后的 size 位址的指标,例如,值是((void *) ((char *) to + size))。

这在连续不断的记忆体位置做一些物件的复制是有用的。

          void *
          combine (void *o1, size_t s1, void *o2, size_t s2)
          {
            void *result = malloc (s1 + s2);
            if (result != NULL)
              mempcpy (mempcpy (result, o1, s1), o2, s2);
            return result;
          }

这个函式是GNU扩充的。

— 函式: wchar_t * wmempcpy (wchar_t *restrict wto, const wchar_t *restrict wfrom, size_t size)

wmempcpy 函式跟 wmemcpy 函式几乎相同,它复制 wfrom 物件最前面的 size 宽字元到 wto 物件,它不是传回 wto 的值而是传回一个指向 wto 物件最前面后的size 位址的指标,例如值是 wto + size

这在连续不断的记忆体位置做一些物件的复制是有用的。

下面是 wmemcpy 可能实作的方式但还有最佳化的可能。

          wchar_t *
          wmempcpy (wchar_t *restrict wto, const wchar_t *restrict wfrom,
                    size_t size)
          {
            return (wchar_t *) mempcpy (wto, wfrom, size * sizeof (wchar_t));
          }

这个函式是GNU扩充的。

— 函式: void * memmove (void *to, const void *from, size_t size)

memmove 从 from 复制 size 位元组到 to 的 size 位元组即使这两个空间的区块有重叠,假如碰上重叠的情形,memmove 会小心地复制 from 区块原始值,包括那些也属于 to 区块的重叠位元组。

memmove 的传回值是 to的值。

— 函式: wchar_t * wmemmove (wchar_t *wto, const wchar_t *wfrom, size_t size)

wmemmove 从 wfrom 复制 size 宽字元到 wto 的 size 宽字元即使这两个空间的区块有重叠,假如碰上重叠的情形,memmove 会小心地复制 wfrom 区块的原始值,包括那些也属于 wto区块的重叠位元组。

下面是 wmemcpy 可能实作的方式但还有最佳化的可能。

          wchar_t *
          wmempcpy (wchar_t *restrict wto, const wchar_t *restrict wfrom,
                    size_t size)
          {
            return (wchar_t *) mempcpy (wto, wfrom, size * sizeof (wchar_t));
          }

wmemmove 的传回值是 wto 的值。

这个函式是GNU扩充的。

— 函式: void * memccpy (void *restrict to, const void *restrict from, int c, size_t size)

这个函式会从 from 复制不超过 size 位元组到 to,假如发现一个位元跟 c 匹配的话,传回值是一个到 c 的指标被复制,或是假如在 from 最前面的 size 位元组没有出现 c 的匹配位元组时则传回一个空指标。

范例:

#include<string.h>
main()
{
char a[]=”string[a]”;
char b[]=”string(b)”;
memccpy(a,b,’b’,sizeof(b));
printf(“memccpy():%s\n”,a);
}

执行:memccpy():string(b]

— 函式: void * memset (void *block, int c, size_t size)

这个函式会把记忆体空间 block 前面的 size 位元组的范围,用字元 c 把它填满(转换成非负整数),它传回 block 指标。

— 函式: wchar_t * wmemset (wchar_t *block, wchar_t wc, size_t size)

这个函式会把 block 前面的 size 宽字元的范围,用宽字元 wc 把它填满,它传回 block 指标。

— 函式: char * strcpy (char *restrict to, const char *restrict from)

这会从字串 from(包括结束的空字元)复制字元到字串 to,像 memcpy一样,假如字串有重叠函式会变成未定义,传回值是 to的值。

— 函式: wchar_t * wcscpy (wchar_t *restrict wto, const wchar_t *restrict wfrom)

这会从字串 wfrom (包括结束的空宽字元)复制宽字元到字串 wto,像 wmemcpy一样,假如字串有重叠函式会变成未定义,传回值是 to的值。

— 函式: char * strncpy (char *restrict to, const char *restrict from, size_t size)

这个函式跟 strcpy 类似但是只会复制 size 个字元到 to。

假如 from 的长度大于 size,那么 strncpy 只会复制前面的 size 个字元,注意这里不会有空值终止符写到 to里。

假如 from 长度小于 size,那么 strncpy 会复制所有的 from, 后面会会填满空字元到 size 个字元,这很少用,但是由 ISO C 标准指定。

假如字串有重叠 strncpy 会变成未定义。

使用 strncpy 而不使用 strcpy 是避免关于写超过 to配置空间的结束错误,然而它也会使你的程式比一般的使用还慢:复制一个可能很小的字串到一个相当大的缓冲区里,在这种情况下, size 可能很大,而这时候 strncpy 会浪费很可观的时间在复制空字元。

— 函式: wchar_t * wcsncpy (wchar_t *restrict wto, const wchar_t *restrict wfrom, size_t size)

这个函式跟 wcscpy 类似但是只会复制 size 个宽字元到 wto。

假如 wfrom 的长度大于 size,那么 wcsncpy 只会复制前面的 size 个宽字元,注意这里不会有空值终止符写到 wto里。

假如 wfrom 的长度小于 size,那么 wcsncpy 会附制所有的 wfrom,后面会填满空的宽字元到 size 个宽字元,这很少用,但是 ISO C 标准指定。

假如字串有重叠 wcsncpy 会变成未定义。

使用 wcsncpy 而不使用 wcscpy 是避免关于写超过 wto 配置空间的结束错误,然而它也会使你的程式比一般的使用还慢:复制一个可能很小的字串到一个相当大的缓冲区里,在这种情况下, size 可能很大,而这时候 wcsncpy 会浪费很可观的时间再复制空的宽字元。

— 函式: char * strdup (const char *s)

这函式复制具空字元结束的字串 s 到新配置的字串,这个字串是使用 malloc配置的;见 Unconstrained Allocation,假如 malloc 不能配置新字串的空间, strdup 传回一个空指标,否则它会传回新字串的指标。

— 函式: wchar_t * wcsdup (const wchar_t *ws)

这函式复制具空字元结束的宽字元字串 ws 到新配置的字串,这个字串是使用 malloc配置的;见 Unconstrained Allocation,假如 malloc 不能配置新字串的空间, wcsdup 传回一个空指标,否则它会传回新的宽字元字串的指标。

这个函式是GNU扩充的。

— 函式: char * strndup (const char *s, size_t size)

这函式类似 strdup 但最多只能复制 size 个字元到新配置的字串。

假如 s 的长度大于 size,那么 strndup 只会复制前面 size 个字元并新增一个结束的空值终止符,否则所有的字元会被覆制,字串会有终止符。

这函式不同于 strncpy 差别在于目的字串会有终止符。

strndup 是GNU扩充的。

— 函式: char * stpcpy (char *restrict to, const char *restrict from)

这函式像 strcpy,除了它是传回字串 to 结尾的指标(也就是,to + strlen (from)及结束字元的位址)而不是最前面的位址。

例如,这个程式使用 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-DOG。

假如字串有重叠的话函式会变成未定义的,这个函式宣告在 string.h。

— 函式: wchar_t * wcpcpy (wchar_t *restrict wto, const wchar_t *restrict wfrom)

这函式像 wcscpy,除了它传回字串 wto 结尾的指标(也就是, wto + strlen (wfrom)及结束自元的地址)而不是最前面的位址。

这函式不是 ISO 或 POSIX 标准,但在开发自己的GNU C 函式库时候很有用。

假如字串有重叠的话 wcpcpy 会变成未定义的。

wcpcpy 是 GNU 扩充而且宣告在 wchar.h

— 函式: char * stpncpy (char *restrict to, const char *restrict from, size_t size)

这函式跟 stpcpy 类似但是会复制 size 个字元到 to

假如 from 长度大于 size,那么 stpncpy 只会复制前面 size 个字元并传回最后面复制的字元指标,注意在这种情况下不会有空值终止符写入 to

假如 from 长度小于 size,那么 stpncpy 复制所有的 from,之后会填满空字元直到 size 个字元,这很少用到,但是在使用 strncpy 的实作下是有用的, stpncpy 传回第一个写入的空字元指标。

这函式不是 ISO 或 POSIX 标准,但在开发自己的GNU C 函式库时候很有用。

假如字串有重叠的话,这函式会变成未定义的,这函式宣告在 string.h

— 函式: wchar_t * wcpncpy (wchar_t *restrict wto, const wchar_t *restrict wfrom, size_t size)

这函式类似 wcpcpy 但是只复制 wsize 个字元到 wto

假如 wfrom 长度大于 size,那么 wcpncpy 只会复制前面 size 个宽字元并传回最后面复制的非空宽字元的指标,注意再这种情况下不会有空值终止符写入 wto

假如 wfrom 长度小于 size,那么 wcpncpy 复制所有的 wfrom,之后会填满空字元直到 size 个字元,这很少用到,但是在使用 wcsncpy 的实作下是有用的, wcpncpy 传回第一个写入的空字元指标。

这函式不是 ISO 或 POSIX 标准,但在开发自己的GNU C 函式库时候很有用。

假如字串有重叠的话,这函式会变成未定义的。

wcpncpy 是 GNU 扩充且宣告在 wchar.h

— 巨集: char * strdupa (const char *s)

这个巨集类似 strdup 但是会使用 alloca 而不是使用 malloc 来配置新字串(见 Variable Size Automatic), 当然这意味着传回的字串有跟使用 alloca配置记忆体区块一样的限制。

出于显而易见的原因,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;
          }

请注意呼叫直接使用 path 来呼叫 strtok 是不正确的,它也不允许在 strtok 的引数列表中呼叫 strdupa ,因为 strdupa 使用alloca (见 Variable Size Automatic)会影响传递的参数。

这函式只在GNU CC使用时才能用。

— 巨集: char * strndupa (const char *s, size_t size)

这函式类似 strndup 但是像 strdupa 一样,它使用 alloca 配置新的字串见 Variable Size Automatic,  strndupa 跟 strdupa 一样有相同的好处跟限制。

这函式以巨集的方式实作,就像 strdupa 一样, 就像 strdupa 一样这个巨集也必须不能在函式呼叫中做为参数列表来使用。

strndupa 只在GNU CC使用时才能用。

— 函式: char * strcat (char *restrict to, const char *restrict from)

strcat 函式类似 strcpy,但是 from 的字元会加到 to的后面,而不会覆写它,那就是, from 的第一个字元会覆写 to 结尾的空字元。

跟 strcat 一样的定义是:

          char *
          strcat (char *restrict to, const char *restrict from)
          {
            strcpy (to + strlen (to), from);
            return to;
          }

假如字串有重叠这函式会变成未定义的。

— 函式: wchar_t * wcscat (wchar_t *restrict wto, const wchar_t *restrict wfrom)

wcscat 函式类似 wcscpy,但是 wfrom 的字元会加到 wto的后面,而不会覆写它,那就是, wfrom 的第一个字元会覆写 wto结尾的空字元。

跟 wcscat 一样的定义是:

          wchar_t *
          wcscat (wchar_t *wto, const wchar_t *wfrom)
          {
            wcscpy (wto + wcslen (wto), wfrom);
            return wto;
          }

假如字串有重叠这函式会变成未定义的。

使用 strcat 或 wcscat 函式的程式设计师(或是下面的 strncat 或 wcsncar 函式)很容易地会被认为是偷懒跟不顾后果的,几乎所有的情况下参与的字串是已知的(最好是如此不然你如何确认缓冲区的配置是足够的?), 或至少,假如我们持续追踪不同函式呼叫的结果,我们就会了解,使用 strcat/wcscat是很没有效的,为了找到字串的结尾真正的复制才会开始,这样很多时间会浪费掉,一个常见的例子:

     /* This function concatenates arbitrarily many strings.  The last
        parameter must be NULL.  */
     char *
     concat (const char *str, ...)
     {
       va_list ap, ap2;
       size_t total = 1;
       const char *s;
       char *result;

       va_start (ap, str);
       va_copy (ap2, ap);

       /* Determine how much space we need.  */
       for (s = str; s != NULL; s = va_arg (ap, const char *))
         total += strlen (s);

       va_end (ap);

       result = (char *) malloc (total);
       if (result != NULL)
         {
           result[0] = '\0';

           /* Copy the strings.  */
           for (s = str; s != NULL; s = va_arg (ap2, const char *))
             strcat (result, s);
         }

       va_end (ap2);

       return result;
     }

这看起来相当简单,特别是真正字串复制是在第二个回圈,但是这无害的几行隐藏了一个重大的效能缺失,只要想一下10个100个位元组的字串必须串,对第二个字串来说我们必须搜寻100个位元组来知道要加入下一个字串,对所有的字串要找到中间结果的结尾总共要比较5500!假如我们使用搜寻的配置来结合复制,我们可以更有效率地改写这个函式:

     char *
     concat (const char *str, ...)
     {
       va_list ap;
       size_t allocated = 100;
       char *result = (char *) malloc (allocated);

       if (result != NULL)
         {
           char *newp;
           char *wp;
           const char *s;

           va_start (ap, str);

           wp = result;
           for (s = str; s != NULL; s = va_arg (ap, const char *))
             {
               size_t len = strlen (s);

               /* Resize the allocated memory if necessary.  */
               if (wp + len + 1 > result + allocated)
                 {
                   allocated = (allocated + len) * 2;
                   newp = (char *) realloc (result, allocated);
                   if (newp == NULL)
                     {
                       free (result);
                       return NULL;
                     }
                   wp = newp + (wp - result);
                   result = newp;
                 }

               wp = mempcpy (wp, s, len);
             }

           /* Terminate the result string.  */
           *wp++ = '\0';

           /* Resize memory to the optimal size.  */
           newp = realloc (result, wp - result);
           if (newp != NULL)
             result = newp;

           va_end (ap);
         }

       return result;
     }

知道了输入字串可以调整记忆体的配置,在这里我们要指出的差异就是我们根本不需要使用 strcat,我们一直追踪目前中间结果的长度,这样我们可以安全地搜寻字串结尾然后使用mempcpy,请注意因为我们处理字串所以我们也不用看起来很自然的 stpcpy ,因为我们已经知道字串的长度而这就变成不需要了,因此可以使用较快速的记忆体复制的函式,这个范例一样可以用在处理宽字元的情形。

当程式设计师觉得需要使用 strcat 时要三思,看看程式码是否能重新改写为可以计算结果的好处,再次提醒:几乎不需要使用 strcat。

— 函式: char * strncat (char *restrict to, const char *restrict from, size_t size)

这函式像 strcat 除了 from 不能超过 size 个字元附加到 to 的结尾,字串的空字元也会附加到 to,所以 to 全部配置的大小至少是 size + 1 位元组的长度会比原来的长度长。

strncat 函式会像这样实作:

          char *
          strncat (char *to, const char *from, size_t size)
          {
            to[strlen (to) + size] = '\0';
            strncpy (to + strlen (to), from, size);
            return to;
          }

假如字串有重叠 strncat 会变成未定义的。

— 函式: wchar_t * wcsncat (wchar_t *restrict wto, const wchar_t *restrict wfrom, size_t size)

这函式像 wcscat 除了 wfrom 不能超过 size 个字元附加到 wto 的结尾,字串的空字元也会附加到 wto,所以 wto 全部配置的大小至少是 size + 1 位元组的长度会比原来的长度长。

The wcsncat function could be implemented like this:

          wchar_t *
          wcsncat (wchar_t *restrict wto, const wchar_t *restrict wfrom,
                   size_t size)
          {
            wto[wcslen (to) + size] = L'\0';
            wcsncpy (wto + wcslen (wto), wfrom, size);
            return wto;
          }

假如字串有重叠 wcsncat 会变成未定义的。

这里有一个范例说明 strncpy 跟 strncat 的使用(宽字元的版本也是一样),注意在 strncat 呼叫里,size 参数如何计算来避免字元阵列的缓冲区溢出。

     #include <string.h>
     #include <stdio.h>

     #define SIZE 10

     static char buffer[SIZE];

     int
     main (void)
     {
       strncpy (buffer, "hello", SIZE);
       puts (buffer);
       strncat (buffer, ", world", SIZE - strlen (buffer) - 1);
       puts (buffer);
     }

这个程式的输出像这样:

     hello
     hello, wo

— 函式: void bcopy (const void *from, void *to, size_t size)

这是 memmove 的替代函式已经有些废弃,源自 BSD,注意它不完全跟 memmove一样,因为引数的顺序不同,而且没有传回值。

— 函式: void bzero (void *block, size_t size)

这是 memset 的替代函式已经有些废弃,源自 BSD,注意它也不跟 memset 一样,因为它只能储存的值是0。

呼,翻的真累,读到这里给个赞吧,或是有错来个留言吧,

下一节: ,上一节: String Length,这一章: String and Array Utilities

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *