C语言再学习25——常用字符串函数归纳

前言:

为了方便查看博客,特意申请了一个公众号,附上二维码,有兴趣的朋友可以关注,和我一起讨论学习,一起享受技术,一起成长。

在这里插入图片描述


1. memcpy

内存复制函数。

1.1 头文件

#include <string.h>

1.2 描述

void *memcpy(void *str1, const void *str2, size_t n) ;

从存储区 str2 复制 n 个字符到存储区 str1。

1.3 参数

str1: 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针;

str2: 指向要复制的数据源,类型强制转换为 void* 指针;

n: 要被复制的字节数。

1.4 返回值

该函数返回一个指向目标存储区 str1 的指针。

1.5 注意

(1)复制的内容不同。strcpy 只能复制字符串,而 memcpy 可以复制任意内容,例如字符数组、整型、结构体、类等;

(2)复制的方法不同。strcpy 不需要指定长度,它遇到被复制字符的串结束符 “\0” 才结束,所以容易溢出。memcpy 则是根据其第 3 个参数决定复制的长度;

(3)用途不同。通常在复制字符串时用 strcpy,而需要复制其他类型数据时则一般用 memcpy。

(4)str1指针要分配足够的空间,也即大于等于 n 字节的空间。如果没有分配空间,会出现断错误,造成空间溢出;

(5)str1 和 str2 所指的内存空间不能重叠(如果发生了重叠,使用 memmove() 会更加安全);

(6)memcpy 是按照字节进行拷贝。多字节数据的拷贝如下:

测试:

void memcpy_test(void)
{
	char src_buf[5] = {1, 2, 3, 4, 5};
	char dst_buf[10] = {0};
	int test_buf1[5] = {99, 8522, 987, 3467, 11027};
	int test_buf2[5] = {0};
	
	memcpy(dst_buf, src_buf, sizeof(src_buf));
	for (int i = 0; i < sizeof(src_buf); i++)
	{
		printf("dst_buf: %d \r\n", dst_buf[i]);
	}
	
	memcpy(test_buf2, test_buf1, sizeof(test_buf1));	//sizeof(test_buf1) = 20字节
	for (int i = 0; i < 5; i++)
	{
		printf("test_buf2: %d \r\n", test_buf2[i]);
	}
}

结果输出:

在这里插入图片描述

1.6 原型实现

void *Memcpy(void *dest, const void *src, unsigned int count)
{
	char *pdest = (char *)dest;
	char *psrc = (char *)src;

	if (pdest == NULL || psrc == NULL)
	{
		return NULL;
	}

	if (pdest == psrc)
	{
		return;
	}

	if (pdest > psrc)
	{
		while (count--)
		{
			*(pdest + count) = *(psrc + count);
		}
	}
	else
	{
		while (count--)
		{
			*pdest++ = *psrc++;
		}
	}
	return pdest;
}

2. memset

将某一块内存中的内容全部设置为指定的值,它是对较大的结构体或数组进行清零操作的一种快捷方法。

2.1 头文件

#include <string.h>

2.2 描述

void *memset(void *str, int c, size_t n) ;

复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。

2.3 参数

str: 指向要填充的内存块

c: 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式;

n: 要被设置为该值的字节数。

2.4 返回值

该函数返回一个指向存储区 str 的指针。

2.5 注意

(1)memset 函数按字节对内存块进行初始化,所以不能用它将 int 数组初始化为 0 和 -1 之外的其他值(除非该值高字节和低字节相同);

(2)memset(void *str, int c, size_t n) 中 c 实际范围应该在 0——255,因为该函数只能取 c 的后八位赋值给你所输入的范围的每个字节。无论 c 多大只有后八位二进制有效,而后八位二进制的范围在(0~255)。而对字符数组操作时则取后八位赋值给字符数组,其八位值作为 ASCII 码。

测试:

void memset_test(void)
{
	char test_buf1[5];
	int test_buf2[5];
	
	memset(test_buf1, 1, sizeof(test_buf1));
	memset(test_buf2, 1, sizeof(test_buf2));
	for (int i = 0; i < sizeof(test_buf1); i++)
	{
		printf("tset_buf1 is %x \r\n", test_buf1[i]);
	}
	for (int i = 0; i < 5; i++)
	{
		printf("tset_buf2 is %x \r\n", test_buf2[i]);
	}
}

结果输出:

在这里插入图片描述

2.6 原型实现


void *MyMemset(void *dest, int n, unsigned int len)
{
	if (dest == NULL)
		return NULL;
	char *pdest = (char *)dest;
	while (len--)
	{
		*pdest++ = n;
	}

	return dest;
}

3. memcmp

把存储区 str1 和存储区 str2 的前 n 个字节进行比较,按字节比较

3.1 头文件

#include <string.h>

3.2 描述

int memcmp(const void *str1, const void *str2, size_t n) ;

存储区 str1 和存储区 str2 的前 n 个字节进行比较。

3.3 参数

str1: 指向内存块的指针;

str2: 指向内存块的指针;

n: 要被比较的字节数。

3.4 返回值

如果返回值 < 0,则表示 str1 小于 str2;

如果返回值 > 0,则表示 str2 小于 str1;

如果返回值 = 0,则表示 str1 等于 str2。

3.5 注意

(1)该函数是按字节比较的,比较 str1 和 str2 的第一个字节的 ascII 码值。

测试:

void memcmp_test(void)
{
	char str1[] = "abcd";
	char str2[] = "abcd";
	int ret = 0;

	ret = My_Memcmp(str1, str2, 4);
	printf("ret val is %d \r\n", ret);

	memcpy(str1, "abce", 4);
	ret = My_Memcmp(str1, str2, 4);
	printf("ret val is %d \r\n", ret);

	memcpy(str1, "abcc", 4);
	ret = My_Memcmp(str1, str2, 4);
	printf("ret val is %d \r\n", ret);
}

结果输出:

在这里插入图片描述

3.6 原型实现

int My_Memcmp(void *str1, void *str2, int count)
{
	char *ptr1 = (char *)str1;
	char *ptr2 = (char *)str2;

	if (!count)
	{
		return 0;
	}

	while (count--)
	{
		if (*ptr1 == *ptr2)
		{
			ptr1 = ptr1 + 1;
			ptr2 = ptr2 + 1;
		}
		else
		{
			return *ptr1 - *ptr2;
		}
	}
	return *ptr1 - *ptr2;
}

4. strlen

strlen 所作的是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符 ‘\0’ 为止,然后返回字符计数器值(长度不包含 '\0 ')。

4.1 头文件

#include <string.h>

4.2 描述

size_t strlen(const char *str) ;

计算字符串 str 的长度,直到空结束字符,但不包括空结束字符。

4.3 参数

str: 要计算长度的字符串。

4.4 返回值

该函数返回字符串的长度。

4.5 注意

(1)注意 strlen 和 sizeof 的区别。

测试:

void strlen_test(void)
{
	char *ptr = "asdfghjl";
	
	printf("strlen length is %d \r\n", strlen(ptr));
}

结果输出:

在这里插入图片描述
输出字符串长度不包括 ‘\0’。

4.6 原型实现

unsigned int My_Strlen(const char *str)
{
	int str_len = 0;

	while (*str++ != '\0')
	{
		str_len++;
	}
	return str_len;
}

5. strcpy

strcpy 把含有 ‘\0’ 结束符的字符串复制到另一个地址空间,返回值的类型为 char*。

5.1 头文件

#include <string.h>

5.2 描述

char *strcpy(char *dest, const char *src);

把 src 所指向的字符串复制到 dest。

5.3 参数

dest: 指向用于存储复制内容的目标数组。;

src: 要复制的字符串。

5.4 返回值

该函数返回一个指向最终的目标字符串 dest 的指针。

5.5 注意

(1)若目标数组 dest 不够大,而源字符串的长度又太长,可能会造成缓冲溢出的情况;

(2)src 和 dest 所指内存区域不可以重叠。

测试:

void strcpy_test(void)
{
	char test_buf1[6] = "ABCDE";
	char test_buf2[100] = {0};
	
	strcpy(test_buf2, test_buf1);
	printf("strcpy test %s \r\n", test_buf2);
}

5.6 原型实现

char *My_Strcpy(char *dest, const char *src)
{
	char *tmp = (char *)dest;
	
	if ((dest == NULL) || (src == NULL))
	{
		return 0;
	}
	
	while (*src != '\0')
	{
		*tmp++ = *src++;
	}
	*tmp = '\0';
	
	return tmp;
}

6. strcmp

比较两个字符串并根据比较结果返回整数。基本形式为 strcmp(str1, str2),若 str1 = str2,则返回零;若 str1 < str2,则返回负数;若 str1 > str2,则返回正数。

6.1 头文件

#include <string.h>

6.2 描述

int strcmp(const char *str1, const char *str2);

把 str1 所指向的字符串和 str2 所指向的字符串进行比较。

6.3 参数

str1: 要进行比较的第一个字符串;

str2: 要进行比较的第二个字符串。

6.4 返回值

如果返回值小于 0,则表示 str1 小于 str2;

如果返回值大于 0,则表示 str1 大于 str2;

如果返回值等于 0,则表示 str1 等于 str2。

6.5 注意

(1)两个字符串自左向右逐个字符相比(按 ASCII 值大小相比较),直到出现不同的字符或遇 ‘\0’ 为止;

(2)只能比较字符串,即可用于比较两个字符串常量或比较数组,不能比较数字等其他形式的参数。

测试:

void strcmp_test(void)
{
	int ret = 0;
//	char test_buf1[6] = "ABCBE";
//	char test_buf2[3] = "AB";
	char test_buf1[6] = {1, 2, 3, 4, 5, 6};
	char test_buf2[6] = {1, 2, 3, 7, 5, 6};
	
	ret = My_Strcmp(test_buf1, test_buf2);
	printf("ret val is %d \r\n", ret);
}

6.6 原型实现

int My_Strcmp(const char *str1, const char *str2)
{
	if (str1 == NULL || str2 == NULL)
	{
		return NULL;
	}
	
	while (*str1 == *str2)
	{
		str1++;
		str2++;
		
		if (*str1 == '\0' || *str2 == '\0')
		{
			break;
		}
	}
	
	return *str1 - *str2;
}

7. sprintf

字符串格式化命令。函数声明为 int sprintf(char *string, char *format [,argument,…]);,主要功能是把格式化的数据写入某个字符串中,即发送格式化输出到 string 所指向的字符串。

7.1 头文件

#include <stdio.h>

7.2 描述

int sprintf(char *str, const char *format, ...);

发送格式化输出到 str 所指向的字符串。

7.3 参数

str: 指向一个字符数组的指针,该数组存储了 C 字符串;

format : 字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags] [width] [.precision] [length]specifier,具体介绍如下:

flags(标识):

在这里插入图片描述

width(宽度):

在这里插入图片描述

.precision(精度):

在这里插入图片描述

length(长度):

在这里插入图片描述

specifier(说明符):

在这里插入图片描述

附加参数 – 根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。

7.4 返回值

如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。

7.5 注意

(1)格式化数字字符串 sprintf 最常见的应用之一是把整数打印到字符串中;

(2)sprintf 的返回值是字符数组中字符的个数,即字符串的长度,不用在调用 strlen(str) 求字符串的长度;

测试:

void sprintf_test(void)
{
	char buf[100] = {0};
	double data = 3.141593;
	uint16_t len = 0;
	uint8_t test_buff[5] = {55, 22, 66, 77, 99};
	
	len = sprintf((char *)buf, "%f", data);
	printf("----------------------------------------------------------------- \r\n");
	printf("buf is %s \r\n", buf);
	printf("sprintf return len is %d \r\n", len);
	
	len = 0;
	
	for (uint16_t i = 0; i < sizeof(test_buff); i++)
	{
		len += sprintf((char *)buf + i * 2, "%d", test_buff[i]);	//数组数据转换为字符串
	}
	printf("test_buff val is %s \r\n", buf);
	printf("sprintf return len is %d \r\n", len);
	printf("----------------------------------------------------------------- \r\n");
}

结果输出:
在这里插入图片描述


参考:

  1. C 库函数
  2. Cplusplus.com
  3. memcpy
  4. (C语言)memcpy函数原型的实现
  5. C函数库中的memcmp实现
  6. strlen (C/C++语言函数)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章