C\C++字符串操作&memcpy函数的底层实现

        以下大部分内容粘自菜鸟教程,因为每次遇到字符串操作都处于一种既熟悉又陌生的状态,所以在这里记录一下,方便以后查找。

 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",&amp;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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值