以下大部分内容粘自菜鸟教程,因为每次遇到字符串操作都处于一种既熟悉又陌生的状态,所以在这里记录一下,方便以后查找。
str_function.h
#include <iostream>
//#include <string>
using namespace std;
#pragma warning(disable:4996)
//# pragma warning 只对当前文件有效(对于.h,对包含它的cpp也是有效的),
//而不是对整个工程的所有文件有效。 当该文件编译结束,设置也就失去作用。
void test_for_memset();
void test_for_memcpy();
void test_for_memcmp();
void test_for_strcpy();
//void test_for_strcat();
void test_for_strcmp();
void test_for_strlen();
void test_for_strchr();
void test_for_strstr();
void test_for_strtok();
void test_for_strrchr();
void test_for_sprintf();
void test_for_snprintf();
void test_for_sscanf();
void* my_memcpy(void* str1, const void* str2, size_t n);
memset
【声明】
void *memset(void *str, int c, size_t n)
【参数】
str -- 指向要填充的内存块。
c -- 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。
n -- 要被设置为该值的字符数。
【描述】
复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。
【返回值】
该值返回一个指向存储区 str 的指针。
void test_for_memset()
{
printf("==========test_for_memset==========\n");
char ch[10];
memset(ch, '*', 8);
cout << ch << endl;
}
memcpy
【声明】
void *memcpy(void *str1, const void *str2, size_t n)
【参数】
str1 -- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
str2 -- 指向要复制的数据源,类型强制转换为 void* 指针。
n -- 要被复制的字节数。
【描述】
从存储区 str2 复制 n 个字节到存储区 str1
【返回值】
该函数返回一个指向目标存储区 str1 的指针。
void test_for_memcpy()
{
printf("==========test_for_memcpy==========\n");
const char ch_src[] = "abcdefg";
char ch_dest[10];
memcpy(ch_dest, ch_src, strlen(ch_src) + 1);//注意strlen(ch_src) + 1才能将ch_src的结尾字符'\0'也拷贝过去,或者采用下面的做法:
//char ch_dest[10]{};
//memcpy(ch_dest, ch_src, strlen(ch_src));
cout << ch_dest << endl;
}
memcmp
【声明】
int memcmp(const void *str1, const void *str2, size_t n)
【参数】
str1 -- 指向内存块的指针。
str2 -- 指向内存块的指针。
n -- 要被比较的字节数。
【描述】
把存储区 str1 和存储区 str2 的前 n 个字节进行比较
【返回值】
如果返回值 < 0,则表示 str1 小于 str2。
如果返回值 > 0,则表示 str1 大于 str2。
如果返回值 = 0,则表示 str1 等于 str2。
void test_for_memcmp()
{
printf("==========test_for_memcmp==========\n");
char str1[10] = "abcde";
char str2[10] = "abcddf";
int ret = memcmp(str1, str2, 5);
if (ret == 0) {
cout << "str1 = str2" << endl;
}
else if (ret < 0) {
cout << "str1 < str2" << endl;
}
else if (ret > 0) {
cout << "str1 > str2" << endl;
}
}
strcpy
【声明】
char *strcpy(char *destin, char *source);
【参数】
dest -- 指向用于存储复制内容的目标数组。
src -- 要复制的字符串。
【描述】
将source指向的字符串拷贝给destin,会覆盖之前的内容,source包含'\0'
【返回值】
该函数返回一个指向最终的目标字符串 dest 的指针。
void test_for_strcpy()
{
printf("==========test_for_strcpy==========\n");
char src[10] = "adbdffd";
char dest[10] = "ccc";
strcpy(dest, src);
cout << dest << endl;
}
strncpy
【声明】
char *strncpy(char *dest, const char *src, size_t n)
【参数】
dest -- 指向用于存储复制内容的目标数组。
src -- 要复制的字符串。
n -- 要从源中复制的字符数。
【描述】
把 src 所指向的字符串复制到 dest,最多复制 n 个字符。当 src 的长度小于 n 时,dest 的剩余部分将用空字节填充。
【返回值】
该函数返回最终复制的字符串。
strcat
【声明】
char *strcat(char *dest, const char *src)
【参数】
dest -- 指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串。
src -- 指向要追加的字符串,该字符串不会覆盖目标字符串。
【描述】
把 src 所指向的字符串追加到 dest 所指向的字符串的结尾
【返回值】
该函数返回一个指向最终的目标字符串 dest 的指针。
void test_for_strcat() {
printf("==========test_for_strcat==========\n");
char* dest_str = new char[9] {};
char *src_str = (char*)malloc(sizeof(char) * 6);
//char* src_str = dest_str + 4;
if (src_str != NULL) {
memset(src_str, 0, sizeof(char) * 6);
}
strcat(dest_str, "abcde");
if (src_str != NULL) {
strcat(src_str, "BBBBB");
strcat(dest_str, src_str);
}
cout << dest_str << endl;
if (src_str != NULL) {
free(src_str);
src_str = NULL;
}
if (dest_str != NULL) {
delete[] dest_str;
dest_str = NULL;
}
}
strncat
【声明】
char *strncat(char *dest, const char *src, size_t n)
【参数】
dest -- 指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串,包括额外的空字符。
src -- 要追加的字符串。
n -- 要追加的最大字符数。
【描述】
把 src 所指向的字符串追加到 dest 所指向的字符串的结尾,直到 n 字符长度为止。
【返回值】
该函数返回一个指向最终的目标字符串 dest 的指针。
strcmp
【声明】
int strcmp(const char *str1, const char *str2)
【参数】
str1 -- 要进行比较的第一个字符串。
str2 -- 要进行比较的第二个字符串。
【描述】
把 str1 所指向的字符串和 str2 所指向的字符串进行比较
【返回值】
如果返回值小于 0,则表示 str1 小于 str2。
如果返回值大于 0,则表示 str1 大于 str2。
如果返回值等于 0,则表示 str1 等于 str2。
void test_for_strcmp()
{
printf("==========test_for_strcmp==========\n");
char src[10] = "adbdffd";
char dest[10] = "ccc";
int ret = strcmp(src, dest);
if (ret == 0) {
cout << "src = dest" << endl;
}
else if (ret < 0) {
cout << "src < dest" << endl;
}
else if (ret > 0) {
cout << "src > dest" << endl;
}
}
strncmp
【声明】
int strncmp(const char *str1, const char *str2, size_t n)
【参数】
str1 -- 要进行比较的第一个字符串。
str2 -- 要进行比较的第二个字符串。
n -- 要比较的最大字符数。
【描述】
把 str1 和 str2 进行比较,最多比较前 n 个字节
【返回值】
如果返回值 < 0,则表示 str1 小于 str2。
如果返回值 > 0,则表示 str1 大于 str2。
如果返回值 = 0,则表示 str1 等于 str2。
strlen
【声明】
size_t strlen(const char *str)
【参数】
str -- 要计算长度的字符串。
【描述】
计算字符串 str 的长度,直到空结束字符,但不包括空结束字符。
【返回值】
该函数返回字符串的长度。
void test_for_strlen()
{
printf("==========test_for_strlen==========\n");
char src[10] = "adbdffd";
cout << strlen(src) << endl;
}
strchr
【声明】
char *strchr(const char *str, int c)
【参数】
str -- 要查找的字符串。
c -- 要查找的字符。
【描述】
查找字符串中的一个字符,并返回该字符在字符串中第一次出现的位置
【返回值】
如果在字符串 str 中找到字符 c,则函数返回指向该字符的指针,如果未找到该字符则返回 NULL。
void test_for_strchr()
{
printf("==========test_for_strchr==========\n");
char src[10] = "adbdffd";
char* p_ch = strchr(src, 'f');
printf("%p, %p", src, p_ch);
}
strrchr
【声明】
char *strrchr(const char *str, int c)
【参数】
str -- C 字符串。
c -- 要搜索的字符。以 int 形式传递,但是最终会转换回 char 形式。
【描述】
参数 str 所指向的字符串中搜索最后一次出现字符 c(一个无符号字符)的位置
【返回值】
该函数返回 str 中最后一次出现字符 c 的位置。如果未找到该值,则函数返回一个空指针。
void test_for_strrchr()
{
printf("==========test_for_strrchr==========\n");
char src[20] = "aaa-bbbbb-cccccc";
char* p_ch = strrchr(src, '-');
printf("%d, %d, %s", (int)src, (int)p_ch, p_ch);
}
strstr
【声明】
char *strstr(const char *haystack, const char *needle)
【参数】
haystack -- 要被检索的 C 字符串。
needle -- 在 haystack 字符串内要搜索的小字符串。
【描述】
在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 '\0'
【返回值】
该函数返回在 haystack 中第一次出现 needle 字符串的位置,如果未找到则返回 null。
void test_for_strstr()
{
printf("==========test_for_strstr==========\n");
char src[10] = "adbdffd";
char dest[10] = "ccc";
char* p_ch = strstr(src, dest);
printf("%p, %p", src, p_ch);
}
strtok
【声明】
char *strtok(char *str, const char *delim)
【参数】
str -- 要被分解成一组小字符串的字符串。
delim -- 包含分隔符的 C 字符串。
【描述】
分解字符串 str 为一组字符串,delim 为分隔符。
【返回值】
该函数返回被分解的第一个子字符串,如果没有可检索的字符串,则返回一个空指针。
void test_for_strtok()
{
printf("==========test_for_strtok==========\n");
char src[20] = "aaa-bbbbb-cccccc";
const char s[2] = "-";
char* tok;
tok = strtok(src, s);
while (tok != NULL) {
printf("%s\n", tok);
tok = strtok(NULL, s);
};
printf("\n");
for (int i = 0; i < 20; i++) {
//对原字符串的改动是切分符原位置均更改为 '\0',所以内容都还在
printf("%c", src[i]);
}
}
sprintf
【声明】
int sprintf(char *str, const char *format, ...)
【参数】
str -- 这是指向一个字符数组的指针,该数组存储了 C 字符串。
format -- 这是字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags][width][.precision][length]specifier
附加参数 -- 根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。
【描述】
发送格式化输出到 str 所指向的字符串
【返回值】
如果成功,则返回写入的字符总数,不包括字符串末尾的空字符。如果失败,则返回一个负数。
void test_for_sprintf()
{
char dest[128] = "";
char str[10] = "aaa";
int a = 10;
float b = 2110.333334;
int length = 0;
length = sprintf(dest, "a = %d, b = %5.3f", a, b);
printf("length = %d, dest = \"%s\"", length, dest);
length = sprintf(dest, "%s=aaa", str);
printf("length = %d, dest = \"%s\"", length, dest);
}
snprintf
【声明】
int snprintf ( char * str, size_t size, const char * format, ... )
【参数】
str -- 目标字符串,用于存储格式化后的字符串的字符数组的指针。
size -- 字符数组的大小。
format -- 格式化字符串。
... -- 可变参数,可变数量的参数根据 format 中的格式化指令进行格式化。
【描述】
snprintf() 是一个 C 语言标准库函数,用于格式化输出字符串,并将结果写入到指定的缓冲区,与 sprintf() 不同的是,snprintf() 会限制输出的字符数,避免缓冲区溢出。如果格式化后的字符串长度超过了 size-1,则 snprintf() 只会写入 size-1 个字符,并在字符串的末尾添加一个空字符(\0)以表示字符串的结束
【返回值】
输出到 str 缓冲区中的字符数,不包括字符串结尾的空字符 \0。如果返回值大于等于缓冲区的大小,则表明输出的结果被截断了
void test_for_snprintf()
{
char dest[128] = "";
int a = 10;
float b = 2110.333334;
int length = 0;
length = snprintf(dest, 10, "a = %d, b = %5.3f", a, b);
printf("length = %d, dest = \"%s\"", length, dest);
}
sscanf
【声明】
int sscanf(const char *str, const char *format, ...)
【参数】
str -- 这是 C 字符串,是函数检索数据的源。
format -- 这是 C 字符串,包含了以下各项中的一个或多个:空格字符、非空格字符 和 format 说明符。
format 说明符形式为 [=%[*][width][modifiers]type=],具体讲解如下:
参数
描述
*
这是一个可选的星号,表示数据是从流 stream 中读取的,但是可以被忽视,即它不存储在对应的参数中。
width
这指定了在当前读取操作中读取的最大字符数。
modifiers
为对应的附加参数所指向的数据指定一个不同于整型(针对 d、i 和 n)、无符号整型(针对 o、u 和 x)或浮点型(针对 e、f 和 g)的大小: h :短整型(针对 d、i 和 n),或无符号短整型(针对 o、u 和 x) l :长整型(针对 d、i 和 n),或无符号长整型(针对 o、u 和 x),或双精度型(针对 e、f 和 g) L :长双精度型(针对 e、f 和 g)
type
一个字符,指定了要被读取的数据类型以及数据读取方式。具体参见下一个表格。
sscanf 类型说明符:
类型
合格的输入
参数的类型
c
单个字符:读取下一个字符。如果指定了一个不为 1 的宽度 width,函数会读取 width 个字符,并通过参数传递,把它们存储在数组中连续位置。在末尾不会追加空字符。
char *
d
十进制整数:数字前面的 + 或 - 号是可选的。
int *
e,E,f,g,G
浮点数:包含了一个小数点、一个可选的前置符号 + 或 -、一个可选的后置字符 e 或 E,以及一个十进制数字。两个有效的实例 -732.103 和 7.12e4
float *
o
八进制整数。
int *
s
字符串。这将读取连续字符,直到遇到一个空格字符(空格字符可以是空白、换行和制表符)。
char *
u
无符号的十进制整数。
unsigned int *
x,X
十六进制整数。
int *
附加参数 -- 这个函数接受一系列的指针作为附加参数,每一个指针都指向一个对象,对象类型由 format 字符串中相应的 % 标签指定,参数与 % 标签的顺序相同。
针对检索数据的 format 字符串中的每个 format 说明符,应指定一个附加参数。如果您想要把 sscanf 操作的结果存储在一个普通的变量中,您应该在标识符前放置引用运算符(&),例如:
int n;
sscanf (str,"%d",&n);【描述】
从字符串读取格式化输入
【返回值】
如果成功,该函数返回成功匹配和赋值的个数。如果到达文件末尾或发生读错误,则返回 EOF。
void test_for_sscanf()
{
char src[128] = "a_str 10";//"a_str=10"这种匹配不出来,不确定是什么原因
int a = 0;
char a_str[10]{};
int match_num = 0;
match_num = sscanf(src, "%s %d", a_str, &a);//"%s=%d"
printf("a_str = %s, a = %d, match_num = %d", a_str, a, match_num);
}
memcpy的底层实现
void* my_memcpy(void* pdestStr, const void* psrcStr, size_t n)
{
char* pdest;
char* psrc;
if (pdestStr == NULL || psrcStr == NULL) {
return NULL;
}
if ((psrcStr < pdestStr) && (char*)psrcStr + n > (char*)pdestStr) {
//出现地址重叠,从后向前拷贝
pdest = (char*)pdestStr + n - 1;
psrc = (char*)psrcStr + n - 1;
while (n--) {
*pdest-- = *psrc--;
}
}
else {
pdest = (char*)pdestStr;
psrc = (char*)psrcStr;
while (n--) {
*pdest++ = *psrc++;
}
}
return pdest;
}