C语言字符串函数,字符函数,内存函数使用及模拟实现

目录
  • 求字符串长度
    • strlen
  • 长度不受限制的字符串函数
    • strcpy
    • strcat
    • strcmp
  • 长度受限制的字符串函数
    • strncpy
    • strncat
    • strncmp
  • 字符串查找函数
    • strstr
    • strtok
    • strerror
  • 字符函数
    • 字符分类函数
    • 字符转换函数
  • 内存操作函数
    • memcpy
    • memmove
    • memcmp
    • memset

求字符串长度

strlen

函数功能

字符串长度,求一个字符串中字符的个数(不包含’\0’)。

函数参数:

size_t strlen( const char *string );
# size_t 是函数的返回类型
# char* string 是函数参数

函数使用:

#include <stdio.h>
#include <string.h>  //strlen对应头文件
int main()
{
	char arr[] = "abcdef";
	int len = strlen(arr);
	printf("%d\n", len);
	return 0;
}

模拟实现(初阶):

#include <stdio.h>
#include <assert.h>  //assert对应头文件

size_t my_strlen(const char* str)
{
	assert(str != NULL);   //检查str是否为空指针
	int count = 0;
	while (*str != '\0')
	{
		str++;
		count++;
	}
	return count;
}

int main()
{
	char arr[] = "abcdef";
	int len = my_strlen(arr);
	printf("%d\n", len);
	return 0;
}

模拟实现(进阶):

#include <stdio.h>
#include <assert.h>  //assert对应头文件
size_t my_strlen(const char* str)   //const用于保护源字符串不被修改
{
	assert(str != NULL);
	char* head = str;      //记录字符串开头的地址
	while (*str++);        //找到字符串结束的地址
	return str - head - 1; //指针-指针得到元素个数,-1减去\0
}
int main()
{
	char arr[] = "abcdef";
	int len = my_strlen(arr);
	printf("%d\n", len);
	return 0;
}

注意事项:

  • 字符串以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含’\0’)。
  • 函数参数指向的字符串必须要以 ‘\0’ 结束,否则得到的就是随机值(strlen会一直往后找,直到遇到’\0’才结束)。(常考)
  • 注意函数的返回值为size_t,是无符号的。(易错:可能出现算术转换)

长度不受限制的字符串函数

strcpy

函数功能:

字符串拷贝,把一个字符串里面的内容拷贝到另一个字符串中去(包括’\0’)。

函数参数;

char* strcpy(char * destination, const char * source );
# char* 是函数的返回值,返回的是目标空间的起始地址
# source 是要拷贝的字符串
# destination 是目标空间

函数使用:

#include <stdio.h>
#include <string.h>  //strcpy对应头文件
int main()
{
	char arr1[] = "abcdef";
	char arr2[10] = "";
	strcpy(arr2, arr1);
	printf("%s\n", arr2);
	return 0;
}

模拟实现(初阶):

#include <stdio.h>
#include <assert.h>  //assert对应头文件

char* my_strcpy(char* dest, const char* src)  //const用于保护源字符串
{
	assert(dest && src);  //保证传递过来的不是空串
	char* ret = dest;  //记录目标空间的起始地址
	while (*src != '\0')
	{
		*dest = *src;
		dest++;
		src++;
	}
	*dest = *src;  //将末尾的'\0'赋给dest
	return ret;
}

int main()
{
	char arr1[] = "abcdef";
	char arr2[10] = "";
	my_strcpy(arr2, arr1);
	printf("%s\n", arr2);
	return 0;
}

模拟实现(进阶):

#include <stdio.h>
#include <assert.h>  //assert对应头文件

char* my_strcpy(char* dest, const char* src)  //const用于保护源字符串
{
	assert(dest && src);  //保证传递过来的不是空串
	char* ret = dest;  //记录目标空间的起始地址
	while (*dest++ = *src++);  //连同末尾的'\0'一起赋给了dest
	return ret;
}

int main()
{
	char arr1[] = "abcdef";
	char arr2[10] = "";
	my_strcpy(arr2, arr1);
	printf("%s\n", arr2);
	return 0;
}

注意事项:

  • 源字符串必须以 ‘\0’ 结束。
  • 会将源字符串中的 ‘\0’ 拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可变。

strcat

函数功能:

字符串追加,在一个字符串的末尾追加另外一个字符串(包括’\0’)。

函数参数:

char * strcat ( char * destination, const char * source );
# char* 是函数的返回值,返回的是目标空间的起始地址
# source 是要追加的字符串
# destination 是目标空间

函数使用:

#include <stdio.h>
#include <string.h>  //strcat对应头文件
int main()
{
	char arr1[] = "world!";
	char arr2[20] = "hello ";
	strcat(arr2, arr1);
	printf("%s\n", arr2);
	return 0;
}

模拟实现(初阶):

#include <stdio.h>
#include <assert.h>

//字符串追加可以分为两部分:1、找到目标字符串的末尾 2、字符串拷贝
char* my_strcat(char* dest, const char* src)  //const用于保护源字符串
{
	assert(dest && src);  //保证传递过来的不是空串
	char* ret = dest;  //记录目标空间的起始地址
	while (*dest != '\0')  //找到目标空间的末尾
	{
		dest++;
	}
	while (*src != '\0')
	{
		*dest = *src;
		dest++;
		src++;
	}
	*dest = *src;  //将末尾的'\0'赋给dest
	return ret;
}

int main()
{
	char arr1[] = "world!";
	char arr2[20] = "hello ";
	my_strcat(arr2, arr1);
	printf("%s\n", arr2);
	return 0;
}

模拟实现(进阶):

#include <stdio.h>
#include <assert.h>

//字符串追加可以分为两部分:1、找到目标字符串的末尾 2、字符串拷贝
char* my_strcat(char* dest, const char* src)  //const用于保护源字符串
{
	assert(dest && src);  //保证传递过来的不是空串
	char* ret = dest;  //记录目标空间的起始地址

	while (*dest++ != '\0');   //找到目标空间的末尾
	dest--;  //抵消最后一次自增的副作用
	while (*dest++ = *src++);  //字符串拷贝

	return ret;
}

int main()
{
	char arr1[] = "world!";
	char arr2[20] = "hello ";
	my_strcat(arr2, arr1);
	printf("%s\n", arr2);
	return 0;
}

注意事项:

  • 源字符串必须以 ‘\0’ 结束。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改。
  • strcat 函数不能自己给自己追加。(追加会覆盖掉末尾的’\0’,导致死循环)

strcmp

函数功能:

字符串比较,以字节为单位比较两个字符串的大小

函数参数:

int strcmp ( const char * str1, const char * str2 );
# int 函数返回值
# char* str1  char* str2 用于比较的两个字符串

函数返回值:

>0 : str1 大于 str2;
=0 : str1 等于 str2;
<0 : str1 小于 str2

函数使用:

#include <stdio.h>
#include <string.h>  //strcmp对应头文件
int main()
{
	char str1[] = "abcdef";
	char str2[] = "abq";
	int ret = strcmp(str1, str2);
	printf("%d\n", ret);
	return 0;
}

模拟实现:

#include <stdio.h>
#include <assert.h>  //assert对应头文件

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2 && *str1 != '\0' && *str2 != '\0')  //找到字符串中不相等字符的位置
	{
		str1++;
		str2++;
	}
	if (*str1 != '\0' && *str2 != '\0')   //如果此位置不是字符串末尾,则不相等,返回差值
		return *str1 - *str2;
	return 0;  //若前面没返回,说明相等,返回0
}

int main()
{
	char str1[] = "abcdef";
	char str2[] = "abq";
	int ret = my_strcmp(str1, str2);
	printf("%d\n", ret);
	return 0;
}

注意事项:

  • 对每一对字符进行比较,直到遇到不相等的字符或者遇到’\0’。
  • 比较的是每一对字符的ASCII值。

长度受限制的字符串函数

由于strcpy、strcat、strcmp等字符串函数存在安全隐患(目标空间小于源空间等问题),C语言还提供了另外几种相对安全的字符串函数,即strncpy、strncat、strncmp,这些字符串函数相比于原字符串函数多了一个参数,用于指定操作的字节数。(注意:strncpy、strncat、strncmp函数只是相对安全,并不是绝对安全,多一个参数只是起到一个提醒作用)

strncpy

函数功能:

字符串拷贝,把一个字符串中num个字节的内容拷贝到另一个字符串中去。

函数参数:

char * strncpy ( char * destination, const char * source, size_t num );
# char* 是函数的返回值,返回的是目标空间的起始地址
# source 是要拷贝的字符串
# destination 是目标空间
# num 是要拷贝的字节数

函数使用:

#include <stdio.h>
#include <string.h>  //strncpy对应的头文件
int main()
{
	char arr1[] = "abcdef";
	char arr2[10] = "";
	strncpy(arr2, arr1, sizeof(arr1) / sizeof(arr1[0]) * 1);
	//sizeof(arr)/sizeof(arr[0]) 求得数组元素个数,*1 乘以每个元素的大小,得到整个数组的字节数
	printf("%s\n", arr2);
	return 0;
}

模拟实现:

//模拟实现strncpy
#include <stdio.h>
#include <assert.h>
char* my_strncpy(char* dest, const char* src, size_t num)
{
	assert(dest && src);
	char* ret = dest;  //记录目标空间的起始地址
	while (num--)
	{
		*dest = *src;
		if (*dest == '\0')  //如果*dest为0,说明将src的结束字符赋给了dest,这种情况下源字符串的长度小于num
		{
			while (num--)
			{
				//如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。(与库函数的实现方式保持一致)
				*dest++ = 0;
			}
			break;
		}
        dest++;
        src++;
	}
	*dest = '\0';  //在dest的末尾补上结束字符
	return ret;
}

int main()
{
	char arr1[] = "abc";
	char arr2[10];
	my_strncpy(arr2, arr1, 4);
	printf("%s\n", arr2);
	return 0;
}

注意事项:

  • 拷贝num个字符从源字符串到目标空间。
  • 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

strncat

函数功能:

字符串追加,将一个字符串中num个字节的内容追加到另一个字符串的末尾,并在最后面加上’\0’。

函数参数:

char * strncat ( char * destination, const char * source, size_t num );
# char* 是函数的返回值,返回的是目标空间的起始地址
# source 是要追加的字符串
# destination 是目标空间
# num 是要追加的字节数

函数使用:

#include <stdio.h>
#include <string.h>  //strncat对应的头文件
int main()
{
	char arr1[] = "world!";
	char arr2[20] = "hello ";
	strncat(arr2, arr1, sizeof(arr1) / sizeof(arr1[0]) * 1);
	//sizeof(arr)/sizeof(arr[0]) 求得数组元素个数,*1 乘以每个元素的大小,得到整个数组的字节数
	printf("%s\n", arr2);
	return 0;
}

模拟实现:

#include <stdio.h>
#include <assert.h>
char* my_strncat(char* dest, const char* src, size_t num)
{
	assert(dest && src);
	char* ret = dest;  //记录目标空间的起始地址

	//找到dest末尾
	while (*dest != '\0')
	{
		dest++;
	}

	//strncpy
	while (num--)
	{
		*dest = *src;
		if (*dest == '\0')  //如果*dest为0,说明将src的结束字符赋给了dest,这种情况下源字符串的长度小于num
		{
			//如果源字字符串的长度小于num,则只复制到终止空字符的内容。(与库函数的实现方式保持一致)
			return ret; //直接返回
		}
		dest++;
		src++;
	}
	*dest = '\0';  //如果循环正常结束,则在dest的末尾补上结束字符
	return ret;
}

int main()
{
	char arr1[20] = "abcdef";
	char arr2[] = "ABCDEF";
	my_strncat(arr1, arr2, 5);
	printf("%s\n", arr1);
	return 0;
}

注意事项:

  • 将源字符串中num个字节的内容追加到目标字符串的末尾,并在最后添加’\0’。
  • 如果源中字符串的长度小于num,则只复制到终止空字符的内容

strncmp

函数功能:

字符串比较,比较两个字符串中前num个字节的大小。

函数参数:

int strncmp ( const char * str1, const char * str2, size_t num );
# int 函数返回值
# char* str1  char* str2 用于比较的两个字符串
# num 要比较的字节数

函数返回值:

>0 : str1 大于 str2;
=0 : str1 等于 str2;
<0 : str1 小于 str2

函数使用:

#include <stdio.h>
#include <string.h>  //strncmp对应的头文件
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcq";
	int len = strncmp(arr2, arr1, 3);
	printf("%d\n", len);
	return 0;
}

注意事项:

  • 对前num对字节中的每一对字符进行比较,直到遇到不相等的字符。
  • 比较的是每一对字符的ASCII值。

字符串查找函数

strstr

函数功能:

查找子串,查找一个字符串中是否包含子串。

函数参数:

char * strstr ( const char *str1, const char * str2);
# char* 函数返回值,返回字符串中子串的起始地址,若找不到,则返回NULL;
# char* str1 要搜索的字符串;
# char* str2 子串

函数使用:

#include <stdio.h>
#include <string.h>  //strstr对应头文件
int main()
{
	char arr1[] = "abbbcdef";
	char arr2[] = "bcd";
	char* ret = strstr(arr1, arr2);
	printf("%s\n", ret);
	return 0;
}

模拟实现(重要):

#include <stdio.h>
#include <assert.h>
char* my_strstr(const char* str1, const char* str2)
{
    assert(str1 && str2);
	//如果中途匹配失败需要回到str2的起始地址,所以用其他变量标识str2,保证str2的首地址不会丢失
	const char* p1 = str1;
	const char* p2 = str2;
	const char* mark = str1;  //用来标记每次第一个字符成功匹配的位置
	while (*mark != '\0')
	{
		p1 = mark;  //从mark处开始往后匹配
		p2 = str2;  //每次匹配后p2回到str2开头
		while (*p1 == *p2 && *p1 != '\0' && *p2 != '\0')  //一直往后匹配,直到遇到不相等的字符
		{
			p1++;
			p2++;
		}
		if (*p2 == '\0')  //如果不相等处p2为'\0'(子串全部匹配成功),则返回Mark处地址
			return (char*)mark;
		mark++;  //否则,说明这一次匹配失败,从mark后面一个字节处开始重新匹配
	}
	return NULL;  //字符串找完都没有子串就返回空指针
}

int main()
{
	char arr1[] = "abbbcdef";
	char arr2[] = "bcdq";
	char* ret = my_strstr(arr1, arr2);
	printf("%s\n", ret);
	return 0;

注意事项:

  • 被查找的字符串和子串都不能是空串,且都以’\0’结尾。
  • 如果查找成功,返回字符串中子串所在位置的首地址,如果查找失败,则返回NULL。

注:我们上面模拟实现的查找子串的函数效率比较低,如果要追求高效率,则需要使用KMP算法,有关KMP算法的相关知识,我会在后面的文章中进行介绍。

strtok

函数功能:

字符串分割,把一个字符串按照分割标志分割为几个字符串。

函数参数:

char * strtok ( char * str, const char * sep );
# char* 函数返回值,strtok函数会找到str中的下一个标记,并将其用'\0'结尾,返回一个指向这个标记的指针;
# char* str 指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记;
# char* sep 一个字符串,定义了用作分隔符的字符集合;

函数使用:

#include <stdio.h>
#include <string.h>
int main()
{
	char* sep = "@.";
	char email[] = "1684277750@qq.com";
	char tmp[20] = "";
	//由于strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都会临时拷贝一份,操作拷贝的数据
	strcpy(tmp, email);
	printf("%s\n", strtok(tmp, sep));  //第一次第一个参数传递被切割字符串的首地址
	printf("%s\n", strtok(NULL, sep));   //第二次及以后第一个参数传递空指针(strtok会记住上一次切割的位置)
	printf("%s\n", strtok(NULL, sep));
	return 0;
}

这里我们知道目标字符串会被分隔符切割为三个字符串,所以这里我们调用了三次strtok函数,但是当我们不知道目标字符串的内容时,这种方法显然就不能用了;那么我们该如何正确的使用strtok函数呢?

我们知道,strtok函数第一次调用时需要传递目标字符串的地址,其余调用都只需要传递NULL即可,那么我们可以利用这个特点结合for循环的特性来正确调用strtok函数。

#include <stdio.h>
#include <string.h>
int main()
{
	char* sep = "@.";
	char email[] = "1684277750@qq.com";
	char tmp[20] = "";
	//由于strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都会临时拷贝一份,操作拷贝的数据
	strcpy(tmp, email);
	char* ret = NULL;  //用来保存strtok函数的返回值
	for (ret = strtok(tmp, sep);   //初始化部分:第一次传递tmp的地址
		ret != NULL;               //判断部分:只要strtok的返回值ret不为空,说明继续分割
		ret = strtok(NULL, sep))   //调整部分:第二次及以上传递NULL
	{
		printf("%s\n", ret);  //ret不为空,说明字符串没被分割完,则打印
	}
	return 0;
}

注意事项:

  • sep参数是个字符串,定义了用作分隔符的字符集合;
  • 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标 记;
  • strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注: 由于strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都会临时拷贝一份,操作拷贝的数据 )
  • strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置;
  • strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记;
  • 如果字符串中不存在更多的标记,则返回 NULL 指针;

strerror

函数功能:

C语言有一系列的库函数,当这些库函数调用失败时,会返回相应的错误码,而strerror函数的作用就是获取错误码对应的错误信息的首地址,让使用者知道程序发生错误的原因。

函数参数:

char * strerror ( int errnum );
# char* 函数返回值,返回错误码对应的错误信息的字符串的地址;
# int errnum 错误码

函数使用:

#include <stdio.h>
#include <string.h>  //strerror的头文件
int main()
{
	printf("%s\n", strerror(0));
	printf("%s\n", strerror(1));
	printf("%s\n", strerror(2));
	printf("%s\n", strerror(3));
	printf("%s\n", strerror(4));
	printf("%s\n", strerror(5));
	return 0;
}

这里有一个问题,C语言中那么多的错误信息,那么我们需要记住每一个错误信息对应的错误码吗?其实,C语言中设置了一个全局的用于存放错误码的变量errno,只要调用C语言库函数发生错误,那么errno就会记录相应的错误码,所以strerror函数和errno一般都是配合使用的。

#include <stdio.h>
#include <string.h>  //strerror对应头文件
#include <errno.h>   //errno对应头文件
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	else
	{
		printf("文件打开成功!\n");
	}
	return 0;
}

字符函数

字符分类函数

函数 如果他的参数符合下列条件就返回真
iscntrl 任何控制字符
isspace 空白字符:空格‘ ’,换页‘\f’,换行’\n’,回车‘\r’,制表符’\t’或者垂直制表符’\v’
isdigit 十进制数字 0~9
isxdigit 十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F
islower 小写字母a~z
isupper 大写字母A~Z
isalpha 字母a~z或A~Z
isalnum 字母或者数字,a~z,A~Z,0~9
ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph 任何图形字符
isprint 任何可打印字符,包括图形字符和空白字符

字符转换函数

函数 返回值
tolower 返回对应小写字母的ASCII值
toupper 返回对应大写字母的ASCII值

内存操作函数

前面我们学习的strcpy、strcat、strcmp、strncpy、strncat、strncmp等函数都是字符串函数,只能对字符串进行相关操作,如果要对其他数据类型,如整形、字符、结构体等进行类似操作的话,就需要学习内存操作函数,常见的内存操作函数有memcpy、memmove、memcmp、memset

memcpy

函数功能:

内存拷贝,将一块内存中num个字节的内容拷贝到另一块内存中,常用来处理不重叠内存数据的拷贝。

函数参数:

void * memcpy ( void * destination, const void * source, size_t num );
# void* 函数返回值,返回dest内存空间的地址;
# void* destination 目标内存空间地址;
# void* source 源空间地址;
# size_t num 要拷贝的字节数;

函数使用:

#include <stdio.h>
#include <string.h>   //memcpy对应头文件
int main()
{
	int arr1[] = { 1,2,3,4,5,6 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr1, 6 * sizeof(int));
	for (int i = 0; i < 6; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

模拟实现:

#include <stdio.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;  //保存目标空间的地址
	while (num--)   //以字节为单位进行拷贝
	{
		*(char*)dest = *(char*)src;  //强转为char*类型后赋值
        //这里不要写成(char*)dest++,在某些编译器下会报错,因为强制类型转是一种临时效果
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6 };
	int arr2[10] = { 0 };
	my_memcpy(arr2, arr1, 6 * sizeof(int));
	for (int i = 0; i < 6; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

注意事项(重要):

在C语言标准中,memcpy只负责处理内存不重叠的数据,内存重叠的数据的拷贝是memmove函数负责实现的,即下面这种情况在C语言标准中memcpy函数是不能实现的:

memcpy(arr1 + 2, arr1, 4 * sizeof(int));

从上面我们memcpy的模拟实现中也可以看出,memcpy是从前向后拷贝的,这就导致在拷贝重叠内存数据时会发生数据覆盖(即arr1[2]中的数据在前面赋值中被改为1,导致将arr[2]中的数据赋给arr[4]时不是4,而是1),但是在VS下的memcpy函数是具备拷贝重叠数据的能力的,也就是说,VS下的memcpy函数同时实现了memmove函数的功能,但是其他编译器下的memcpy函数是否也具备memmove函数功能是未知的,所以我们在处理重叠内存数据拷贝的时候尽量还是使用memmove函数,以免发生错误。

memmove

函数功能:

内存移动,将一块内存数据中的内容移动覆盖至另一块内存数据,常用来处理重叠内存数据的拷贝。

函数参数:

# memmove 函数的参数和 memcpy 函数完全相同
void * memmove ( void* destination, const void * source, size_t num );

函数使用:

#include <stdio.h>
#include <string.h>  //memmove对应头文件
int main()
{
	int arr1[] = { 1,2,3,4,5,6 ,7,8 };
	int arr2[10] = { 0 };
	memmove(arr1 + 2, arr1, 4 * sizeof(int));
	for (int i = 0; i < 8; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

模拟实现(重要):

思路分析:

在memcpy中我们提到在拷贝重叠内存的数据时会发生内存覆盖的情况,其实这种覆盖分为两种情况:

(1):dest的地址大于src的地址

如图,如果这时我们从前往后移动的话,那么4就会覆盖掉6,从而导致将6赋给8变成4赋给8,所以我们应该从后往前移。

(2):dest的地址小于src的地址

如果这时我们从后往前移动的话,那么7就会覆盖掉5,导致将5赋给2的时候变成7赋给2,所以这里我们应该从前往后移动。

代码实现:

#include <stdio.h>
#include <assert.h>
void* my_memmove(void* dest, void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;  //保存目标空间的地址
	if (dest < src)
	{
		//前 -> 后 等价于memcpy
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		//后 -> 前
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return ret;
}

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9 };
	my_memmove(arr + 1, arr + 3, 4 * sizeof(int));
	for (int i = 0; i < 9; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

memcmp

函数功能:

内存比较,比较两块内存中前num个字节的大小。

函数参数:

int memcmp ( const void * ptr1, const void * ptr2, size_t num );
# int 函数返回值;
# void* ptr1 void* ptr2 要比较的两块内存;
# size_t num 要比较的字节数;

函数返回值:

>0 : ptr1 大于 ptr2;
=0 : ptr1 等于 ptr2;
<0 : ptr1 小于 ptr2;··

函数使用:

#include <stdio.h>
#include <string.h>  //memcmp对应头文件
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 1,2,3 };
	int ret = memcmp(arr1, arr2, 3 * sizeof(int));
	printf("%d\n", ret);
	return 0;
}

模拟实现:

#include <stdio.h>
#include <assert.h>

int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
	assert(ptr2 && ptr2);
	size_t count = 0;  //用来标记相等的字节数
	while (*(char*)ptr1 == *(char*)ptr2 && count < num)  //一直循环,直到找到不相等的字节数据
	{
		count++;  //进入一次循环表示有一对字节相等,count++
		ptr1 = (char*)ptr1 + 1;
		ptr2 = (char*)ptr2 + 1;
	}
	if (count < num)  //如果count小于num,说明两块内存的前num个字节中有不相等的数据
		return *(char*)ptr1 - *(char*)ptr2;  //直接返回数据的差值
	else
		return 0;  //count等于num,说明相等
}
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 1,2,3 };
	int ret = my_memcmp(arr1, arr2, 3 * sizeof(int));
	printf("%d\n", ret);
	return 0;
}

memset

函数功能:

内存设置,把一块内存中num个字节的内容设置为指定的数据。

函数参数:

void *memset( void *dest, int c, size_t count );
# void* 函数返回值,返回目标空间的地址;
# int c 函数参数,指定你想要初始化的数据;
# size_t count 函数参数,指定初始化的字节数

函数使用:

#include <stdio.h>
#include <string.h>  //memset对应头文件
int main()
{
	char str[] = "hello world";
	memset(str, 'x', 5);
	printf("%s\n", str);
	return 0;
}

模拟实现:

#include <stdio.h>
#include <assert.h>

void* my_memset(void* dest, int c, size_t num)
{
	assert(dest != NULL);
	void* ret = dest;  //记录目标空间的地址
	while (num--)  //循环将num个字节的内容初始化为指定值
	{
		*(char*)dest = c;
		dest = (char*)dest + 1;
	}
	return ret;
}

int main()
{
	char str[] = "hello world";
	my_memset(str, 'x', 5);
	printf("%s\n", str);
	return 0;
}

到此这篇关于C语言字符串函数,字符函数,内存函数使用及模拟实现的文章就介绍到这了,更多相关C语言字符串内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 一波C语言字符数组实用技巧集锦

    字符数组倒序 #include <stdio.h> void daoxu(char str[]){ int i; char temp; for(i = 0; i < strlen(str) / 2 ; i ++){ temp = str[i]; str[i] = str[strlen(str) - i-1]; str[strlen(str) - i-1] = temp; } } 单词计数    int wordCount(char str[]){ int i; int count = 0

  • C语言字符串函数模拟实现流程介绍

    目录 一.strlen 1.使用计数器 2.使用函数递归 3.使用指针-指针 二.strcpy 三.strcat 四.strcmp 该文章将简易模拟实现strlen.strcpy.strcat.strcmp.strstr.那么让我们废话少说,直接开始吧. 一.strlen strlen-Get string length.即获取字符串长度.函数参数为 const char* str,函数返回类型为 size_t.如下图所示: strlen函数的读取结束标志为’\0’,因此,若字符串中没有’\0’

  • 浅析C语言中的数组及字符数组

    我们来编写一个程序,以统计各个数字.空白符(包括空格符.制表符及换行符)以及所有其它字符出现的次数.这个程序的实用意义并不大,但我们可以通过该程序讨论 C 语言多方面的问题. 所有的输入字符可以分成 12 类,因此可以用一个数组存放各个数字出现的次数,这样比使用 10 个独立的变量更方便.下面是该程序的一种版本: #include <stdio.h> /* count digits, white space, others */ main() { int c, i, nwhite, nothe

  • C语言之从字符数组中删除特定的字符

    从字符数组中删除特定的字符,即输入要删除的指定字符,利用for循环找到非指定字符,将非指定字符输出即可.以下为具体的实现方法: #include<stdio.h> int main() { char str[100],c; int j,k; printf("please input a string:"); gets(str); printf("\nEnter a character:"); c=getchar(); for(j=k=0;str[j]!=

  • c语言字符数组与字符串的使用详解

    1.字符数组的定义与初始化字符数组的初始化,最容易理解的方式就是逐个字符赋给数组中各元素.char str[10]={ 'I',' ','a','m',' ','h','a','p','p','y'};即把10个字符分别赋给str[0]到str[9]10个元素如果花括号中提供的字符个数大于数组长度,则按语法错误处理:若小于数组长度,则只将这些字符数组中前面那些元素,其余的元素自动定为空字符(即 '\0' ). 2.字符数组与字符串在c语言中,将字符串作为字符数组来处理.(c++中不是)在实际应用

  • C语言字符串与字符数组面试题中最易错考点详解

    目录 一.'\0'对字符串与字符数组的重要性 二.strlen与sizeof有什么区别 三.含转义字符求字符串长度 本文介绍字符串与字符数组中最易错的3个考点.若以后遇到其他相关的易错点,会持续补充更新. 一.'\0'对字符串与字符数组的重要性 #include<stdio.h> #include<string.h> //下面代码,打印结果是什么? int main(){ char arr1[] = "abc"; char arr2[] = { 'a', 'b'

  • C语言中的字符串数据在C中的存储方式

    目录 内存中的五大区域 字符串数据在C语言中有两种存储方式 几个比较容易混的点 统计字符串中某一个字符出现的次数 使用字符指针数组来存储多个字符串数据 内存中的五大区域 栈:是专门用来存储局部变量的,所有的局部变量都是声明在栈区域中 堆:允许程序员手动的从堆申请指定字节数的空间来使用 BSS段:是用来存储未初始化的全局变量和静态变量,声明一个全局变量,如果我们没有初始化,在程序运行最开始的时候,这个全局变量是没有初始化的,存储在BSS段[程序运行后系统就自动的初始化为0,并把初始化后的全局变量存

  • C语言中关于计算字符串长度的几种方式

    目录 计算字符串长度的几种方式 自定义函数 使用string头文件中的strlen()函数 使用sizeof()操作符 计算字符串长度,使用sizeof和strlen的坑 使用strlen计算 使用sizeof计算 计算字符串长度的几种方式 C语言计算字符串长度,可以手动计算也可以使用库函数或者sizeof()操作符. 自定义函数求长度 使用strlen()函数 使用sizeof()操作符 自定义函数 int cont_str(char *s) {     int i = 0;        

  • C语言超全面讲解字符串函数

    目录 1.gets函数 2.puts函数 3.strcat函数 4.strcpy函数(strncpy函数) 5.strcmp函数(strncmp函数) 6.strlen函数 7.strlwr函数 8.strupr函数 9.strstr函数 注意:在使用字符串处理函数时,一定要使用#include <string.h>开头 1.gets函数 其形式为:gets(字符数组)——输入字符串的函数 作用是从终端输入一个字符串到字符数组,并且得到一个函数值. 2.puts函数 其形式为:puts(字符数

  • C语言深入详解四大内存函数的使用

    目录 1.memcpy 2.memmove 3.memcmp 4.memset 1.memcpy 与字符串函数 strcpy 类似,也是进行拷贝.但是需要注意的是,strcpy 是针对字符串进行拷贝,而 memcpy 是针对内存进行拷贝. 如何理解呢?strcpy 进行拷贝的时候,只能一个字节一个字节的拷贝,但要实现 整型.浮点型等数据类型拷贝的时候,就不得不用到 memcpy 了. 我们观察 strcpy 的函数声明: char * strcpy ( char * destination, c

  • GO语言字符串处理Strings包的函数使用示例讲解

    目录 常用的字符串处理函数 (1) Contains (2) Join (3) Index (4) Repeat (5) Replace (6) Split (7) Trim (8) Fields 字符串转换 (1) Format (2) Parse (3) Append 常用的字符串处理函数 (1) Contains func Contains(s, substr string) bool 功能:字符串s中是否包含substr,返回bool值 演示如下: //查找一个字符串在另一个字符串中是否

  • 一篇文章带你了解C语言的一些重要字符串与内存函数

    目录 一.字符串函数 1. 求字符串长度的strlen 2.比较字符串大小的strcmp 3.复制字符串的strcpy 4.追加字符串的strcat 5.查找字符串函数的strstr 二.内存函数 1.复制 memcpy,memmove 2.比较 memcmp 总结 一.字符串函数 1. 求字符串长度的strlen size_t strlen ( const char * str ); 字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '

  • c语言重要的字符串与内存函数

    目录 一.字符串函数 1. 求字符串长度的strlen 2.比较字符串大小的strcmp 3.复制字符串的strcpy 4.追加字符串的strcat 5.查找字符串函数的strstr 二.内存函数 1.复制 memcpy,memmove 2.比较 memcmp 一.字符串函数 1. 求字符串长度的strlen size_t strlen ( const char * str ); 字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0'

  • C语言中利用封装好的函数实现英文字母的大小写转换

    在C语言中,利用tolower和toupper两个函数实现英文字母的大小写之间的转换 范例1:将s字符串内的小写字母转换成大写字母 #include <ctype.h> int main() { char s[] = "aBcDeFgH"; int i; printf("before toupper() : %s\n", s); for(i = 0; i < sizeof(s); i++) s[i] = toupper(s[i]); printf(

  • C语言字符串函数,字符函数,内存函数使用及模拟实现

    目录 求字符串长度 strlen 长度不受限制的字符串函数 strcpy strcat strcmp 长度受限制的字符串函数 strncpy strncat strncmp 字符串查找函数 strstr strtok strerror 字符函数 字符分类函数 字符转换函数 内存操作函数 memcpy memmove memcmp memset 求字符串长度 strlen 函数功能 字符串长度,求一个字符串中字符的个数(不包含’\0’). 函数参数: size_t strlen( const ch

  • C语言字符函数、内存函数功能及实现代码

    C语言字符函数.内存函数 功能及实现 strlen函数(求字符串长度)注意点模拟实现 strcpy函数(字符串拷贝函数)注意点模拟实现 strcat函数(字符串衔接函数)注意点模拟实现 strcmp函数注意点模拟实现 strstr函数模拟实现 strtok函数使用 strerror函数使用 memcpy函数注意点模拟实现 memmove函数注意点模拟实现 memset函数注意点 strlen函数(求字符串长度) 统计字符串长度直到\0为止 注意点 1.属于<string.h>库 2.参数为字符

  • C语言进阶教程之字符串&内存函数

    目录 前言: 一.求字符串长度 strlen strlen函数的模拟实现 二.长度不受限制的字符串函数 strcpy strcpy函数的模拟实现 strcat strcat函数的模拟实现 strcmp strcmp函数的模拟实现 三.长度受限制的字符串函数 strncpy strncpy函数的模拟实现 strncat strncat函数的模拟实现 strncmp strncmp函数的模拟实现 四.字符串查找 strstr strstr函数的模拟实现 strtok strtok函数的模拟实现 五.

  • C语言详解如何应用模拟字符串和内存函数

    目录 1.strlen 求字符串长度 使用案例: 1.计数法 2.不创建临时变量计数器-递归 3.指针-指针的方式 2.长度不受限制的字符串函数 1.strcpy 使用案例: 模拟实现: 2.strcat 使用案例: 模拟实现: 3.strcmp-比较字符串首字母的大小 使用案例: 模拟实现: 3.长度受限制的字符串函数  1.strncpy 使用案例: 2.strncat  使用案例: 3.strncmp 使用案例: 4.strstr-找子串  使用案例: 模拟实现: 5.strtok 用法:

  • C语言字符串函数与内存函数精讲

    目录 strlen strcpy strcat strcmp strncpy strncat strncmp strstr strtok strerror tolower\toupper memcpy memmove memcmp memset strlen 获取字符串长度. strlen - size_t strlen( const char *string ); 1.字符串以’\0’作为结束标志,strlen函数返回的是在字符串中’\0’前面出现的字符个数(不包含’\0’). 2.参数指向的

随机推荐