C 编程/字符串操作
在 C 中,字符串只是一个字符数组。字符串的长度由一个终止空字符决定:'\0'
。因此,一个内容为"abc"
的字符串包含四个字符:'a'
、'b'
、'c'
和终止空 ('\0'
) 字符。
终止空字符的值为零。
在 C 中,字符串常量 (字面量) 用双引号包围 ("),例如"Hello world!"并在编译时转换为一个指定类型的字符数组char值,并附加一个空终止字符 (0 值) 代码来标记字符串的结尾。字符串常量的类型为char [].
字符串字面量可能不能在源代码中直接包含嵌入的新行符或其他控制字符,或者字符串中某些具有特殊含义的字符。
要在字符串中包含此类字符,可以使用反斜杠转义,如下所示
转义 | 含义 |
---|---|
\\ | 字面反斜杠 |
\" | 双引号 |
\' | 单引号 |
\n | 换行符 (换行) |
\r | 回车 |
\b | 退格 |
\t | 水平制表符 |
\f | 换页 |
\a | 警报 (响铃) |
\v | 垂直制表符 |
\? | 问号 (用于转义 三元组) |
\nnn | 具有八进制值 nnn 的字符 |
\xhh | 具有十六进制值 hh 的字符 |
C 支持宽字符字符串,定义为类型为wchar_t的数组,至少为 16 位值。它们用字符串前面的 L 表示,如下所示
- wchar_t *p = L"Hello world!";
此功能允许字符串,其中需要超过 256 个不同的可能字符 (尽管也可以使用可变长度char字符串)。它们以一个零值的wchar_t结尾。这些字符串不受<string.h>
函数支持。相反,它们有自己的函数,在<wchar.h>
.
中声明
字符编码[编辑 | 编辑源代码]charchar
和wchar_twchar_t
代表的字符编码不受 C 标准的限制,只是 0x00 和 0x0000 值表示字符串的结尾,而不是字符。直接受到字符编码影响的是输入和输出代码。其他代码不应该受到太大影响。如果要在源代码中编写字符串,编辑器也应该能够处理编码。
主要有三种类型的编码
- 每个字符一个字节。通常基于 ASCII。最多有 255 个不同的字符,加上零终止字符。
- 可变长度char字符串,允许超过 255 个不同的字符。此类字符串以正常char为基础的数组编写。这些编码通常是基于 ASCII 的,例如 UTF-8 或 Shift JIS。
- 宽字符字符串。它们是wchar_t值的数组。UTF-16 是最常见的此类编码,它也是可变长度的,这意味着一个字符可以是两个wchar_t.
因为程序员发现原始字符串难以处理,他们编写了 <string.h>
库中的代码。它不代表一个协同的设计工作,而是多年来各种作者贡献的累积。
首先,字符串库中存在三种类型的函数
mem
函数操作任意字符序列,不考虑空字符;str
函数操作以空字符结尾的字符序列;strn
函数操作非空字符序列。
字符串库中九个最常用的函数是
strcat
- 连接两个字符串strchr
- 字符串扫描操作strcmp
- 比较两个字符串strcpy
- 复制一个字符串strlen
- 获取字符串长度strncat
- 连接一个字符串和另一个字符串的一部分strncmp
- 比较两个字符串的部分strncpy
- 复制字符串的一部分strrchr
- 字符串扫描操作
其他函数,例如 strlwr
(转换为小写)、strrev
(返回反转的字符串) 和 strupr
(转换为大写) 可能很受欢迎;但是,它们既不受 C 标准的限制,也不受单一 Unix 标准的限制。这些函数是否返回原始字符串的副本或就地转换字符串也是未指定的。
char *strcat(char * restrict s1, const char * restrict s2);
有些人建议使用 strncat()
或 strlcat()
来代替 strcat,以避免缓冲区溢出。
strcat()
函数将把指向 s2
的字符串的副本 (包括终止空字节) 附加到指向 s1
的字符串的末尾。s2
的初始字节将覆盖 s1
末尾的空字节。如果在重叠的对象之间进行复制,则行为是未定义的。该函数返回 s1
。
此函数用于将一个字符串附加到另一个字符串的末尾。必须保证第一个字符串 (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, penThickness = 2;
strcpy(penText, colors[penColor]);
strcat(penText, widths[penThickness]);
printf("My pen is %s\n", penText); /* prints 'My pen is GreenThick' */
在调用 strcat()
之前,目标必须当前包含一个以空字符结尾的字符串,或者第一个字符必须用空字符初始化 (例如 penText[0] = '\0';
)。
以下是 strcat
的公共领域实现
#include <string.h>
/* strcat */
char *(strcat)(char *restrict s1, const char *restrict s2)
{
char *s = s1;
/* Move s so that it points to the end of s1. */
while (*s != '\0')
s++;
/* Copy the contents of s2 into the space at the end of s1. */
strcpy(s, s2);
return s1;
}
char *strchr(const char *s, int c);
strchr()
函数将定位指向 s
的字符串中第一个出现的 c
(转换为 char
)。终止空字节被视为字符串的一部分。如果未找到该字符,则函数返回找到的字符的位置,否则返回空指针。
此函数用于在字符串中查找特定字符。
在历史上,此函数曾被称为 index
。strchr
的名称虽然有些神秘,但符合命名的一般模式。
以下是 strchr
的公共领域实现
#include <string.h>
/* strchr */
char *(strchr)(const char *s, int c)
{
char ch = c;
/* Scan s for the character. When this loop is finished,
s will either point to the end of the string or the
character we were looking for. */
while (*s != '\0' && *s != ch)
s++;
return (*s == ch) ? (char *) s : NULL;
}
int strcmp(const char *s1, const char *s2);
字符串比较的基本形式是用 strcmp()
函数完成的。它接受两个字符串作为参数,如果第一个字符串在字典序上小于第二个字符串,则返回一个小于零的值,如果第一个字符串在字典序上大于第二个字符串,则返回一个大于零的值,如果两个字符串相等,则返回零。比较是通过逐个字符地比较字符的编码(ASCII)值来完成的。
如今,这种简单的字符串比较类型在对字符串列表进行排序时通常被认为不可接受。存在更先进的算法,可以生成字典排序的列表。它们还可以解决诸如 strcmp()
将字符串 "Alpha2" 视为大于 "Alpha12" 的问题。(在前面的示例中,"Alpha2" 与 "Alpha12" 比较结果大于,因为 '2' 在字符集中位于 '1' 之后)。也就是说,不要在任何商业或专业代码中单独使用此 strcmp()
进行通用字符串排序。
strcmp()
函数将把指向 s1
的字符串与指向 s2
的字符串进行比较。非零返回值的符号将由被比较字符串中第一个差异字节对的值的差值的符号决定(都解释为 unsigned char
类型)。完成时,strcmp()
将返回一个大于、等于或小于 0 的整数,如果指向 s1
的字符串分别大于、等于或小于指向 s2
的字符串。
由于除非正在比较同一数组中的指针,否则单独比较指针在实践中没有用处,因此此函数会按字典序比较两个指针指向的字符串。
此函数在比较中很有用,例如
if (strcmp(s, "whatever") == 0) /* do something */ ;
strcmp()
使用的排序顺序等效于机器的本机字符集。关于排序顺序的唯一保证是,从'0'到'9'的数字是按连续顺序排列的。
以下是 strcmp
的公共领域实现
#include <string.h>
/* strcmp */
int (strcmp)(const char *s1, const char *s2)
{
unsigned char uc1, uc2;
/* Move s1 and s2 to the first differing characters
in each string, or the ends of the strings if they
are identical. */
while (*s1 != '\0' && *s1 == *s2) {
s1++;
s2++;
}
/* Compare the characters as unsigned char and
return the difference. */
uc1 = (*(unsigned char *) s1);
uc2 = (*(unsigned char *) s2);
return ((uc1 < uc2) ? -1 : (uc1 > uc2));
}
char *strcpy(char *restrict s1, const char *restrict s2);
有些人建议始终使用 strncpy()
而不是 strcpy,以避免缓冲区溢出。
strcpy()
函数将把指向 s2
的 C 字符串(包括终止空字节)复制到指向 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;
/* Do the copying in a loop. */
while ((*dst++ = *src++) != '\0')
; /* The body of this loop is left empty. */
/* Return the destination string. */
return s1;
}
size_t strlen(const char *s);
strlen()
函数将计算指向 s
的字符串中的字节数,不包括终止空字节。它返回字符串中的字节数。没有值用于指示错误。
以下是 strlen
的公共领域实现
#include <string.h>
/* strlen */
size_t (strlen)(const char *s)
{
const char *p = s; /* pointer to character constant */
/* Loop over the data in s. */
while (*p != '\0')
p++;
return (size_t)(p - s);
}
注意如何将该行
const char *p = s
声明并初始化指向整数常量的指针 p
,即 p
不能更改它指向的值。
char *strncat(char *restrict s1, const char *restrict s2, size_t n);
strncat()
函数将从指向 s2
的数组的末尾追加不超过 n
个字节(空字节及其后的字节不会被追加)到指向 s1
的字符串的末尾。s2
的初始字节将覆盖 s1
末尾的空字节。始终将终止空字节追加到结果中。如果在重叠的对象之间进行复制,则行为未定义。函数返回 s1
。
以下是 strncat
的公共领域实现
#include <string.h>
/* strncat */
char *(strncat)(char *restrict s1, const char *restrict s2, size_t n)
{
char *s = s1;
/* Loop over the data in s1. */
while (*s != '\0')
s++;
/* s now points to s1's trailing null character, now copy
up to n bytes from s2 into s stopping if a null character
is encountered in s2.
It is not safe to use strncpy here since it copies EXACTLY n
characters, NULL padding if necessary. */
while (n != 0 && (*s = *s2++) != '\0') {
n--;
s++;
}
if (*s != '\0')
*s = '\0';
return s1;
}
int strncmp(const char *s1, const char *s2, size_t n);
strncmp()
函数将比较不超过 n
个字节(跟随空字节的字节不会被比较)从指向 s1
的数组到指向 s2
的数组。非零返回值的符号由被比较字符串中第一个差异字节对的值的差值的符号决定。请参阅 strcmp
以了解返回值的解释。
此函数在比较中很有用,与 strcmp
函数一样。
以下是 strncmp
的公共领域实现
#include <string.h>
/* strncmp */
int (strncmp)(const char *s1, const char *s2, size_t n)
{
unsigned char uc1, uc2;
/* Nothing to compare? Return zero. */
if (n == 0)
return 0;
/* Loop, comparing bytes. */
while (n-- > 0 && *s1 == *s2) {
/* If we've run out of bytes or hit a null, return zero
since we already know *s1 == *s2. */
if (n == 0 || *s1 == '\0')
return 0;
s1++;
s2++;
}
uc1 = (*(unsigned char *) s1);
uc2 = (*(unsigned char *) s2);
return ((uc1 < uc2) ? -1 : (uc1 > uc2));
}
char *strncpy(char *restrict s1, const char *restrict s2, size_t n);
strncpy()
函数将从指向 s2
的数组复制不超过 n
个字节(跟随空字节的字节不会被复制)到指向 s1
的数组。如果在重叠的对象之间进行复制,则行为未定义。如果指向 s2
的数组是一个短于 n
个字节的字符串,则空字节将被追加到指向 s1
的数组中的副本,直到总共写入 n
个字节。函数将返回 s1;没有返回值保留用于指示错误。
该函数可能不会返回以空字符结尾的字符串,这种情况发生在 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;
/* Copy bytes, one at a time. */
while (n > 0) {
n--;
if ((*dst++ = *src++) == '\0') {
/* If we get here, we found a null character at the end
of s2, so use memset to put null bytes at the end of
s1. */
memset(dst, '\0', n);
break;
}
}
return s1;
}
char *strrchr(const char *s, int c);
strrchr
函数类似于 strchr
函数,只是 strrchr
返回指向 s
中 c
的最后一个出现位置的指针,而不是第一个出现位置。
strrchr()
函数将定位指向 s
的字符串中 c
(转换为 char
)的最后一个出现位置。终止空字节被视为字符串的一部分。它的返回值类似于 strchr
的返回值。
在历史上,此函数曾被称为 rindex
。strrchr
的名称虽然有些神秘,但符合命名的一般模式。
以下是 strrchr
的公共领域实现
#include <string.h>
/* strrchr */
char *(strrchr)(const char *s, int c)
{
const char *last = NULL;
/* If the character we're looking for is the terminating null,
we just need to look for that character as there's only one
of them in the string. */
if (c == '\0')
return strchr(s, c);
/* Loop through, finding the last match before hitting NULL. */
while ((s = strchr(s, c)) != NULL) {
last = s;
s++;
}
return (char *) last;
}
不太常用的函数是
memchr
- 在内存中查找字节memcmp
- 比较内存中的字节memcpy
- 复制内存中的字节memmove
- 复制重叠区域的内存中的字节memset
- 设置内存中的字节strcoll
- 根据特定于区域设置的排序顺序比较字节strcspn
- 获取互补子字符串的长度strerror
- 获取错误消息strpbrk
- 在字符串中扫描字节strspn
- 获取子字符串的长度strstr
- 查找子字符串strtok
- 将字符串拆分为标记strxfrm
- 转换字符串
void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
memcpy()
函数将从指向 s2
的对象复制 n
个字节到指向 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;
/* Loop and copy. */
while (n-- != 0)
*dst++ = *src++;
return s1;
}
void *memmove(void *s1, const void *s2, size_t n);
memmove()
函数将从 s2
指向的对象中复制 n
个字节到 s1
指向的对象中。复制过程类似于将 s2
指向的对象的 n
个字节首先复制到一个不与 s1
和 s2
指向的对象重叠的 n
字节临时数组中,然后将临时数组中的 n
个字节复制到 s1
指向的对象中。该函数返回 s1
的值。
在不使用临时数组的情况下实现此功能的简单方法是检查会阻止升序复制的条件,如果找到,则执行降序复制。
以下是一个公共领域的 memmove
实现,尽管并非完全可移植。
#include <string.h>
/* memmove */
void *(memmove)(void *s1, const void *s2, size_t n)
{
/* note: these don't have to point to unsigned chars */
char *p1 = s1;
const char *p2 = s2;
/* test for overlap that prevents an ascending copy */
if (p2 < p1 && p1 < p2 + n) {
/* do a descending copy */
p2 += n;
p1 += n;
while (n-- != 0)
*--p1 = *--p2;
} else
while (n-- != 0)
*p1++ = *p2++;
return s1;
}
int memcmp(const void *s1, const void *s2, size_t n);
memcmp()
函数将比较 s1
指向的对象的第一个 n
个字节(每个字节都解释为 unsigned char
)与 s2
指向的对象的第一个 n
个字节。非零返回值的符号应由被比较对象中第一个不同的字节对的值(均解释为 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;
while (n-- != 0) {
if (*us1 != *us2)
return (*us1 < *us2) ? -1 : +1;
us1++;
us2++;
}
return 0;
}
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
函数应用于相同的两个原始字符串的结果。放置到 s1
指向的结果数组中的字符不超过 n
个,包括终止空字符。如果 n
为零,则允许 s1
为空指针。如果在重叠对象之间进行复制,则行为未定义。该函数返回转换后的字符串的长度。
这些函数很少使用且代码非平凡,因此本节没有代码。
void *memchr(const void *s, int c, size_t n);
memchr()
函数将在 s
指向的对象的初始 n
个字节(每个字节都解释为 unsigned char
)中找到 c
(转换为 unsigned char
)的第一次出现。如果未找到 c
,memchr
将返回空指针。
以下是一个公共领域的 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;
}
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
指向的字符串的字符组成。
所有这些函数都类似,只是测试和返回值不同。
以下分别是 strcspn
、strpbrk
和 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);
return sc1 - s1; /* terminating nulls match */
}
#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;
return NULL; /* terminating nulls match */
}
#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);
return sc1 - s1; /* terminating nulls don't match */
}
char *strstr(const char *haystack, const char *needle);
strstr()
函数将在 haystack
指向的字符串中找到 needle
指向的字符串中字节序列(不包括终止空字节)的第一次出现。该函数返回指向 haystack
中匹配字符串的指针,如果未找到匹配项则返回空指针。如果 needle
是空字符串,则该函数返回 haystack
。
以下是一个公共领域的 strstr
实现。
#include <string.h>
/* strstr */
char *(strstr)(const char *haystack, const char *needle)
{
size_t needlelen;
/* Check for the null needle case. */
if (*needle == '\0')
return (char *) haystack;
needlelen = strlen(needle);
for (; (haystack = strchr(haystack, *needle)) != NULL; haystack++)
if (memcmp(haystack, needle, needlelen) == 0)
return (char *) haystack;
return NULL;
}
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
视为由一个或多个字符从分隔符字符串 delimiters
中跨越而分隔的零个或多个文本标记序列。参数 lasts 指向用户提供的指针,该指针指向 strtok_r()
继续扫描相同字符串所需存储的信息。
在对 strtok_r()
的第一次调用中,s
指向空终止字符串,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 : *lasts;
sbegin += strspn(sbegin, delimiters);
if (*sbegin == '\0') {
*lasts = "";
return NULL;
}
send = sbegin + strcspn(sbegin, delimiters);
if (*send != '\0')
*send++ = '\0';
*lasts = send;
return sbegin;
}
/* strtok */
char *(strtok)(char *restrict s1, const char *restrict delimiters)
{
static char *ssave = "";
return strtok_r(s1, delimiters, &ssave);
}
这些函数不适合上述任何类别。
void *memset(void *s, int c, size_t n);
memset()
函数将 c
转换为 unsigned char
,然后将该字符存储到 s
指向的内存的前 n
个字节中。
以下是 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;
return s;
}
char *strerror(int errorcode);
此函数返回与参数相对应的特定于区域设置的错误消息。根据具体情况,此函数的实现可能非常简单,但作者不会这样做,因为它的实现方法各不相同。
Single Unix System 版本 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("Length = %d\n", length); // prints 'Length = 7'
length2 = strlen(gemstone);
turkey = malloc( length + length2 + 1);
if (turkey) {
strcpy( turkey, gemstone);
strcat( turkey, flower);
printf( "%s\n", turkey); // prints 'ruby begonia'
free( turkey );
}
请注意,为“turkey”分配的内存大小为要连接的字符串长度的总和加一。这是为了终止空字符,它不计入字符串的长度。
- 字符串函数使用大量的循环结构。是否有办法以可移植的方式解开这些循环?
- 现在库中可能缺少哪些函数?
- C Primer/C 字符串函数库
- C++ 编程/代码/IO/流/字符串
- 由于标准
string.h
库中的许多函数容易受到缓冲区溢出错误的影响,有些人建议避免使用string.h
库和“C 风格字符串”,而是使用动态字符串 API,例如 字符串库比较 中列出的 API。 - 有一个很小的 公共领域 concat() 函数,它将分配内存并在可移植的 C/C++ 代码中安全地连接任意数量的字符串