C 编程/string.h/函数参考
#include <string.h>
void *memset(void *s, int c, size_t n);
memset() 将 c 复制到 s 指向的对象的前 n 个字节中。
该函数返回指针 s。当发生错误时,没有定义的返回值。
在计算中,C 编程语言提供了一个名为 strcat 的库函数,允许将一个内存块附加到另一个内存块。这两个内存块都需要以 null 结尾。因为在 C 中,字符串不是一等公民数据类型,而是作为内存中的 ASCII 字节块实现的,strcat将有效地将一个字符串附加到另一个字符串,给定指向两个已分配内存块的指针。名称strcat是“字符串连接”的缩写。strcat可以在string.h头文件中找到。
例如
char str1[14] = "Hello,"; /* The array has enough space for 'Hello,' plus " world!" plus a null terminator */
strcat(str1, " world!");
puts(str1); /* prints "Hello, world!" to stdout followed by a newline */
以下是可能实现的strcat:
char *
strcat(char *dest, const char *src)
{
size_t i,j;
for (i = 0; dest[i] != '\0'; i++)
;
for (j = 0; src[j] != '\0'; j++)
dest[i+j] = src[j];
dest[i+j] = '\0';
return dest;
}
它也可以用其他字符串库函数来定义
char *
strcat(char *dest, const char *src)
{
strcpy(dest + strlen(dest), src);
return dest;
}
strcat可能是危险的,因为如果要附加的字符串太长,无法放入目标缓冲区,它将覆盖相邻的内存,从而引发未定义的行为。通常程序在这种情况下只会导致段错误,但熟练的攻击者可以使用这种缓冲区溢出攻击来侵入系统(参见计算机安全)。
为了防止缓冲区溢出,已经使用了多种替代strcat的方法。它们都接受一个额外的参数,该参数对目标缓冲区的长度进行编码,并且不会写入该缓冲区末尾。如果提供了错误的长度,它们都可能导致缓冲区溢出。
char* strncat(char* dst, const char* src, size_t n);
最常见的边界变体,strncat,只附加指定数量的字节,加上一个 NULL 字节。这允许每个连接的字符串使用不超过其在缓冲区中的“份额”,也许是用来制作表格的。它不适合更常见的需求,即获得适合缓冲区的连接字符串的前缀。为此,要传递的计数的正确值是bufferSize-strlen(buffer)-1。常见的错误是传递bufferSize, bufferSize-1和bufferSize-strlen(buffer),这些都会导致缓冲区溢出。
size_t strlcat(char* dst, const char* src, size_t size);
该strlcat函数由 OpenBSD 开发人员 Todd C. Miller 和 Theo de Raadt 创建,通常被认为是strncat的更安全、更有用的版本。它接受缓冲区的实际长度作为参数,并返回所需的字节数,允许调用者根据需要重新分配缓冲区。它已被移植到许多操作系统,但被 glibc 维护者明确拒绝,他们认为 C 程序员需要跟踪字符串长度,并且“使用此函数只会导致其他错误”。[1]
errno_t strcat_s(char* dst, rsize_t size, const char* src);
strcat_s
函数在 ISO/IEC TR 24731 中提出标准化。[2][3] 受 Microsoft C 运行时库支持。[4] 以及其他一些 C 库。如果源字符串不适合,它会返回非零值,并将缓冲区设置为空字符串(如果原始字符串未存储在其他位置或调用者忽略返回值,则这是一个灾难性的结果)。它还被一些库明确不支持,包括 GLibc 库。[5] Microsoft 编译器发出的警告消息,建议程序员将strcat和strncat更改为此函数,据一些人推测是微软试图将开发者锁定在其平台上。[6][7]
- strcat(3) 手册页 通过 OpenBSD
std::strcat
的 C++ 参考- [1]
C 和 C++ 的函数名称 strchr()
语法
include <string.h>
char *strchr(const char *s, int c);
描述
strchr() 函数在 s 指向的字符串中查找 c 的第一个出现,转换为 char。终止 null 字符被认为是字符串的一部分。
参数
s 指向要搜索的字符串。
c 是要在字符串 s 中搜索的字符。
返回值
strchr() 函数返回指向 s 内找到的字符 c 的第一个出现的指针。如果字符串中没有出现字符 c,strchr() 返回一个空指针。
在 POSIX 和 C 编程语言中,strcmp
是 C 标准库中的一个函数(在 string.h
中声明),用于比较两个 C 字符串。
根据 ISO/IEC 9899:1999,7.21.4.2 的原型
int strcmp(const char *s1, const char *s2);
当字符串相等时,strcmp
返回 0;当 s1
小于 s2
时,返回负整数;当 s1
大于 s2
时,返回正整数,根据字典序。
strcmp
的一个变体名为 strncmp
,它只比较字符串到一定偏移量。
另一个变体 strcasecmp
符合 POSIX.1-2001,工作方式类似于 strcmp
,但区分大小写。一些系统反而用名为 stricmp
或 strcmpi
的函数提供此功能。为了区分大小写地比较两个字符串的子集,各种系统可能会提供 strncasecmp
、strnicmp
或 strncmpi
。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char **argv)
{
int v;
if (argc < 3)
{
fprintf (stderr, "Compares two strings\nUsage: %s string1 string2\n",argv[0]);
return EXIT_FAILURE;
}
v = strcmp (argv[1], argv[2]);
if (v < 0)
printf ("'%s' is less than '%s'.\n", argv[1], argv[2]);
else if (v == 0)
printf ("'%s' equals '%s'.\n", argv[1], argv[2]);
else if (v > 0)
printf ("'%s' is greater than '%s'.\n", argv[1], argv[2]);
return 0;
}
上面的代码是一个工作示例,它打印第一个参数是否小于、等于或大于第二个参数。
可能的实现是(P.J. Plauger,The Standard C Library,1992)
int strcmp (const char * s1, const char * s2)
{
for(; *s1 == *s2; ++s1, ++s2)
if(*s1 == 0)
return 0;
return *(unsigned char *)s1 < *(unsigned char *)s2 ? -1 : 1;
}
但是,大多数现实世界的实现将具有各种优化技巧来减少函数的执行时间。你会注意到,strcmp 不仅返回 -1、0 和 +1,还会返回其他负值或正值,这是由于优化掉了由 ?:
运算符引入的分支。
return *(const unsigned char *)s1 - *(const unsigned char *)s2;
C 编程语言提供了一个名为 strcpy 的库函数,在 string.h 头文件中定义,它允许将以 null 结尾的内存块从一个位置复制到另一个位置。由于 C 中的字符串不是一等数据类型,而是作为内存中的连续字节块来实现,strcpy将有效地复制给定指向两个已分配内存块的指针的字符串。
函数的原型是:[8]
char *strcpy(char *destination, const char *source);
参数顺序模仿赋值:目标“=”源。返回值是 目标
。
例如
char *str1 = "abcdefghijklmnop";
char *str2 = malloc(100); /* must be large enough to hold the string! */
strcpy(str2, str1); /* str2 is now "abcdefghijklmnop" */
str2[0] = 'A'; /* str2 is now "Abcdefghijklmnop" */
/* str1 is still "abcdefghijklmnop" */
在第二行,内存被分配来保存字符串的副本,然后字符串从一个内存块复制到另一个内存块,然后该副本的第一个字母被修改。
虽然简单的赋值str2 = str1似乎可以做同样的事情,它只复制了str1的内存地址到str2str1和到中,但不是实际的字符串。两者到都将引用相同的内存块,以前由
该strcpy指向的分配块将丢失。对 str2[0] 的赋值也会修改 str1,或者会导致访问冲突(因为现代编译器通常将字符串常量放在只读内存中)。strcpy函数通过遍历字符串的各个字符并将它们逐个复制来执行复制。的显式实现是
char *strcpy(char *dest, const char *src)
{
unsigned i;
for (i=0; src[i] != '\0'; ++i)
dest[i] = src[i];
//Ensure trailing null byte is copied
dest[i]= '\0';
return dest;
}
一个常见的紧凑实现是
char *strcpy(char *dest, const char *src)
{
char *save = dest;
while(*dest++ = *src++);
return save;
}
C 库提供的现代版本通常一次复制多个字节,依靠位数学来检测较大的字在写入之前是否包含空字节。通常,调用会编译成专门用于执行strcpy.
strcpy将适用于 Unicode 字符串的所有常见字节编码,包括 UTF-8。只要空字节不被其使用,就无需真正知道编码。
如果 Unicode 以大于一个字节的单位编码,例如 UTF-16,则需要不同的函数,因为空字节将出现在更大的代码单元的一部分中。C99 定义了函数wcscpy(),它将复制wchar_t大小的对象,并在遇到第一个值为零的对象时停止。这不像看起来那么有用,因为不同的计算机平台在如何设置wchar_t的大小(有些使用 16 位,有些使用 32 位)方面存在分歧。
strcpy可能很危险,因为如果要复制的字符串太长而无法放入目标缓冲区,它将覆盖相邻的内存,导致未定义的行为。通常,程序在这种情况下只会导致分段错误,但熟练的攻击者可以使用缓冲区溢出来入侵系统。为了防止缓冲区溢出,已经使用了几种替代方案strcpy。它们都接受一个额外的参数,该参数是目标缓冲区的长度,并且不会写入该缓冲区末尾。如果提供了不正确的长度,它们仍然会导致缓冲区溢出。
char* strncpy(char* dst, const char* src, size_t size);
strncpy写入了给定的字节数,如果字符串太长,则只复制字符串的开头,或者在副本的末尾添加零来填充缓冲区。它被引入 C 库是为了处理目录条目等结构中的固定长度名称字段。尽管它的名字是strcpy,但它不是的边界版本;它不保证结果是以 null 结尾的字符串。函数的名称具有误导性,因为strncat和snprintf 是的边界版本,分别是strcat和sprintf.
假设结果是以 null 结尾的字符串会导致两个问题。如果源字符串太长,则结果不是以 null 结尾的,这使得缓冲区末尾之后的数据看起来像是字符串的一部分。如果源字符串比缓冲区短得多,则将浪费大量时间将剩余的缓冲区填充为 null 字节。
标准 C 库中一个始终追加一个 null 字节的替代方法是使用 strncat,并将一个最初为空的字符串作为目标。
size_t strlcpy(char* dst, const char* src, size_t size);
该strlcpy函数由 OpenBSD 开发人员 Todd C. Miller 和 Theo de Raadt 创建,通常被认为是strncpy的更安全版本。它始终添加一个 null 字节,并返回所需的字节数,允许调用者重新分配缓冲区(如果可能)。它已被移植到许多操作系统,但最值得注意的是被 glibc 维护者 Ulrich Drepper 拒绝,他建议 C 程序员需要跟踪字符串长度,并且“使用此函数只会导致其他错误”。[1]
errno_t strcpy_s(char* dst, rsize_t size, const char* src);
strcpy_s
函数在 ISO/IEC TR 24731 中被提议用于标准化。[9][10] 它受 Microsoft C 运行时库[11] 和其他一些 C 库的支持。如果源字符串不适合,它将返回非零值,并将缓冲区设置为空字符串(而不是前缀!)。它也明确不受一些库的支持,包括 GNU C 库。[12] 一些人推测,Microsoft 编译器发出的建议程序员将strcpy和strncpy更改为该函数的消息是 Microsoft 试图将开发人员锁定在其平台上。[13][14]
- C++ 对
std::strcpy
的引用 - : 复制字符串 – OpenBSD 库函数手册
strcspn 是来自 C 标准库(头文件 string.h)的函数。
它在字符串中搜索特定的一组字符。
strcspn() 函数计算字符串 1 的初始段的长度,该段不包含字符串 2 中的任何字符。
返回值
[edit | edit source]该函数返回字符串 1 中第一个与字符串 2 中的任何字符匹配的字符的索引。
语法
[edit | edit source]#include <string.h>
size_t strcspn( const char *str1, const char *str2 );
示例
[edit | edit source]#include <stdio.h>
#include <string.h>
int main(){
char s[20] = "wikireader007", t[11] = "0123456789";
printf("The first decimal digit of s is at position: %d.\n", '''strcspn'''(s, t));
return 0;
}
输出:
s 的第一个十进制数字位于位置:10
外部链接
[edit | edit source]strerror
[edit | edit source]字符串错误函数 strerror 是一个 C/C++ 函数,它将错误代码(通常存储在全局变量 errno 中)转换为人类可读的错误消息。
历史
[edit | edit source]strerror 函数在 IEEE Std 1003.1(也称为 POSIX 1)中定义。
可重入性
[edit | edit source]strerror 函数不可重入。有关该函数的可重入版本,请参见 strerror r。
用法
[edit | edit source]包含
[edit | edit source]#include <string.h>
声明
[edit | edit source]char* strerror(int errnum);
语义
[edit | edit source]该函数生成并报告一个 C 样式字符串,其中包含从与 errnum 传递的错误代码派生的错误消息。
参考
[edit | edit source]- strerror by OpenGroup
外部链接
[edit | edit source]strlen
[edit | edit source]在 C 标准库中,strlen 是一个字符串函数,它确定 C 字符串的长度。
示例用法
[edit | edit source]#include <stdio.h>
#include <string.h>
int main()
{
char *string = "Hello World";
printf("%lu\n", (unsigned long)strlen(string));
return 0;
}
此程序将打印值 11,它是字符串 "Hello World" 的长度。字符字符串存储在称为char的数据类型的数组中。字符串的结尾通过搜索数组中的第一个空字符来找到。
重要的是要注意,此长度 *不* 包含 C 字符串的结束字符所需的尾随空字节的数组条目。因此,如果您需要复制 C 字符串,则需要分配 strlen() + 1 的空间。
实施
[edit | edit source]FreeBSD 6.2 实现strlen如下所示:[15]
size_t strlen(const char * str)
{
const char *s;
for (s = str; *s; ++s) {}
return(s - str);
}
可以在 C 中编写更快的版本,这些版本检查完整的机器字而不是逐字节地检查。Hacker's Delight 给出了一个算法,该算法利用按位运算来检测这些字节中的任何一个是否为空 ('\0')。当前的 FreeBSD 实现就是这样做的。 [16]
现代 C 编译器通常提供strlen的快速内联版本,这些版本使用汇编编写,使用按位运算技术或某些 CISC 处理器提供的特殊指令。此外,strlen引用的字符串常量的长度通常优化为常数整数。
外部链接
[edit | edit source]- Linux 库函数 手册 : 计算字符串的长度 –
std::strlen
的 C++ 参考
strrchr
[edit | edit source]strrchr 是 string.h 中的函数。[17] 它主要用于从末尾开始搜索字符串中字符的最后一次出现。它返回指向字符串中字符最后一次出现的指针。结束空字符被认为是 C 字符串的一部分。因此,它也可以被定位以检索指向字符串末尾的指针。
语法
[edit | edit source]在 C 中,此函数被声明为
char *strrchr ( const char *, int );
str 是一个 C 字符串。character 是要定位的字符。它作为其 int 提升传递,但它在内部被转换回 char。
返回值
[edit | edit source]指向 str 中 character 最后一次出现的指针。如果未找到该值,该函数将返回一个 空指针。
示例
[edit | edit source]#include <stdio.h>
#include <string.h>
int main(void)
{
const char *str = "This is a sample string";
char *pch = strrchr(str, 's');
printf("Last occurrence of 's' found at %d\n", pch - str + 1);
return 0;
}
输出:'s' 的最后一次出现位于 18。
另请参阅
[edit | edit source]外部链接
[edit | edit source]strspn
[edit | edit source]strspn() 函数用于找出子字符串的长度或由一个字符串指向的字符串(例如 s1)的最大初始段的长度,该初始段包含来自另一个由另一个字符串(例如 s2)指向的字符串的所有字符,而 strscpn() 用于发现包含不在拒绝列表中的所有元素的初始段的长度。
size_t strspn(const char *s, const char *accept);
size_t strcspn(const char *s, const char *reject);
s1 - 指向要搜索的以空字符结尾的字符串。
s2 - 指向以空字符结尾的字符集。
strstr是 C 标准库字符串函数,定义在string.h. strstr()具有以下函数签名:char * strstr(const char *haystack, const char *needle);它返回指向第一个索引处的字符的指针,该索引处needle在haystack中,如果不存在,则返回 NULL。[18]
该strcasestr()是一个与strstr()非常相似的函数,它忽略了needle和haystack. strcasestr()是一个非标准函数,而strstr()符合 C89 和 C99。[18]
#include <stdio.h>
#include <string.h>
int main(void)
{
/* Define a pointer of type char, a string and the substring to be found*/
char *cptr;
char str[] = "Wikipedia, be bold";
char substr[] = "edia, b";
/* Find memory address where substr "edia, b" is found in str */
cptr = strstr(str, substr);
/* Print out the character at this memory address, i.e. 'e' */
printf("%c\n", *cptr);
/* Print out "edia, be bold" */
printf("%s\n", cptr);
return 0;
}
cptr现在是指向第六个字母(e)的指针,位于 "wikipedia" 中。
strtok 是 C 库函数之一。strtok() 函数的语法如下:语法
#include <string.h>
char *strtok( char *str1, const char *str2 );
描述:strtok() 函数返回 str1 中下一个“标记”的指针,其中 str2 包含确定标记的分隔符。如果找不到标记,则 strtok() 返回 NULL。为了将字符串转换为标记,第一次调用 strtok() 应使 str1 指向要标记化的字符串。所有此后的调用都应使 str1 为 NULL。
strxfrm
是 C 标准库字符串函数,在 string.h 中声明。它根据当前区域设置转换字符串。
此函数的原型为
size_t strxfrm(char *str1 , const char *str2 , size_t num);
是接收 num 个字符的转换字符串的字符串。如果 num 等于零,则 str1 仅包含空字符。
是要转换的字符串。
是要复制到 str1 中的最大字符数。
strxfrm() 函数根据当前区域设置转换 str2。为此,使用定义在 locale.h 中的 LC_COLLATE 类别。转换后,转换后的字符串的前 num 个字符被复制到 str1 中。strxfrm() 函数执行转换,以使对两个字符串的 strcmp 结果与对两个原始字符串的 strcoll 结果相同。
strxfrm() 函数返回转换后的字符串的长度,不包括终止空字符。
#include <stdio.h>
#include <string.h>
int main(void)
{
char str2[] = "Hello World";
char str1[];
printf("The length of str2 = %d\n",strxfrm(str1, str2, 4));
printf("The content of str1 = %s\n", str1[]);
printf("The content of str2 = %s\n", str2[]);
return 0;
}
str2 的长度 = 11
str1 的内容 = Hell
str2 的内容 = Hello World
- Linux 库函数 手册 –
std::strxfrm
的 C++ 参考
- ↑ a b libc-alpha 邮件列表,选自 2000 年 8 月 8 日的主题:53,60,61
- ↑ ISO/IEC. ISO/IEC WDTR 24731 安全 C 库函数规范. 国际标准化组织. Retrieved 2008-04-23.
- ↑ Plakosh, Daniel. "strcpy_s() 和 strcat_s()". Pearson Education, Inc. 检索于 2006-08-12.
- ↑ 微软. "CRT 中的安全增强功能". MSDN. 检索于 2008-09-16.
- ↑ "Re: 实施“C 库扩展”(ISO/IEC WG14 N1172)".
- ↑ Danny Kalev. "他们又在搞什么鬼". InformIT.
- ↑ "安全增强型 CRT,比标准库更安全?".
- ↑ ISO/IEC 9899:1999 规范, 第 326 页,第 7.21.2.3 节
- ↑ ISO/IEC. ISO/IEC WDTR 24731 安全 C 库函数规范. 国际标准化组织. 检索于 2008-04-23.
- ↑ Plakosh, Daniel. "strcpy_s() 和 strcat_s()". Pearson Education, Inc. 检索于 2006-08-12.
- ↑ 微软. "CRT 中的安全增强功能". MSDN. 检索于 2008-09-16.
- ↑ "Re: 实施“C 库扩展”(ISO/IEC WG14 N1172)".
- ↑ Danny Kalev. "他们又在搞什么鬼". InformIT.
- ↑ "安全增强型 CRT,比标准库更安全?".
- ↑ "strlen.c 修订版 1.4". FreeBSD. 2002-03-21. 检索于 2009-03-04.
- ↑ "/stable/10/lib/libc/string/strlen.c 的内容". FreeBSD. 2013-10-10.
- ↑ ISO/IEC 9899:1999 规范 (PDF). 第 343 页,第 7.12.4.3 节.
- ↑ a b strcasestr(3)