你可以使用这一节说明的函式来复制字串和阵列的内容,或是添加字串的内容到另一个字串, ‘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
wcsncatfunction 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/Array Comparison,上一节: String Length,这一章: String and Array Utilities