c语言字符函数和字符串函数

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

strlen()函数

strlen()函数使用
strlen()返回值为size_t (typedef  unsigned int) ,参数为一个char*的指针,即为一个地址。然后strlen函数从这个地址开始一个字节一个字节的向后访问,直到遇见\0才停止,然后返回前面访问的字符数。

#include<stdint.h>
#include<string>
int main()
{
	char arr[10] = { 'a','b','c','d','e','f' };
	//当给数组设置长度后,并且初始化时没有占满数组,则后面的数组元素会自动补为\0
	//但当没有设置数组长度时,数组后面就不会自动补\0;
	
	if (strlen("abc") - strlen("qwerty") > 0)
	//strlen()的返回值为无符号整型,所以3-6=-3,但是比较时会将-3按照无符号整数解析
	//所以会一直大于0
	//故strlen()的返回值不要相减后和0比较大小,要是比较的话就强制类型转换为int
	//或者直接将两个strlen()返回值比较大小
	{
		printf(">\n");
	}
	else
	{
		printf("<=\n");
	}

	return 0;
}
模拟实现strlen()函数
计数器方法
//计数器方法
#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* str)
{
	assert(str);  //断言,判断传进来的str是不是NULL,如果是就中断程序
	int count = 0;
	while (*str != '\0')
	{
		count++;
		str++;
	}
	return count;
}
int main()
{
	char str[] = "abcdef";
	int res = my_strlen(str);
	printf("%d\n", res);
	printf("%d\n", my_strlen(str));

	return 0;
}
递归方法
//递归的方法
#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* str)
{
	assert(str);  //断言,判断传进来的str是不是NULL,如果是就中断程序
	if (*str == '\0')
	{
		return 0;
	}
	else
	{
		return 1 + my_strlen(str + 1);  //不能写成str++,那样会先把str传入函数,然后str才++
	}
}
int main()
{
	char str[] = "abcdef";
	int res = my_strlen(str);
	printf("%d\n", res);
	printf("%d\n", my_strlen(str));

	return 0;
}
指针-指针
//指针-指针
#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* str)
{
	assert(str);  //断言,判断传进来的str是不是NULL,如果是就中断程序
	char* p = str;
	while (*p != '\0')
	{
		p++;
	}
	return p-str;
}
int main()
{
	char str[] = "abcdef";
	int res = my_strlen(str);
	printf("%d\n", res);
	printf("%d\n", my_strlen(str));

	return 0;
}

strcpy()函数

strcpy()函数的使用
strcpy()函数返回一个char*类型的指针,即返回一个地址,该地址就是目标字符串的首地址。
第一个参数为char*类型的指针, 即目标字符串的首地址。
第二个参数为char*类型的指针,即为源字符串的首地址。
strcpy()拷贝时会将源字符串的\0也拷贝进去。

//strcpy()函数
#include<stdio.h>
#include<string.h>
int main()
{
	//char arr1[4] = "x";  //当目标数组的长度小于源字符串长度时,会发生越界访问,
	//但是strcpy()函数还是会将源字符串里面的内容都拷贝到目标数组中。
	//char* arr1 = "qwersdjf"; //arr1指向的是常量字符串,常量是不可修改的

	char arr1[20] = "XXXXXXXXXXXX";  
	//char arr2[] = "abcdef";
	char arr2[10] = { 'a','b','c' };  //不全部初始化,后面的会补上\0
	strcpy(arr1, arr2);

	printf("%s\n", arr1);  //abcdef\0XXXXX
	return 0;
}
模拟实现strcpy()函数
#include<stdio.h>
#include<assert.h>
//strcpy函数返回的是目标空间的起始地址
//strcpy函数的返回类型的设置是为了实现链式访问
char* my_strcpy(char* dest, const char* src)
{
	assert(dest && src);
	char* start = dest;
	//while (*src != '\0')
	//{
	//	*dest = *src;
	//	dest++;
	//	src++;
	//}
	//*dest = *src; //最后的\0也拷贝过去
	
	//简便写法
	while (*dest++ = *src++);
	return start;
}
int main()
{
	/*char arr1[20] = "abcdefdskjfk";
	char arr2[] = "xyz";*/
	char arr1[20] = { 0 };
	char* arr2 = "abcdef";
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);

	return 0;
}

strcat()函数

strcat()函数使用
strcat()为追加字符串函数。即在一个字符串末尾追加另一个字符串。
strcat()的返回值为一个char*类型的指针,即为目标字符串的首元素地址。
strcat()的第一个参数为目标字符串的首元素地址。
strcat()的第二个参数为源字符串的首元素地址。 
strcat()函数会将源字符串追加到目标字符串后面,并且会将目标字符串的\0字符给覆盖,但是也会将源字符串的\0跟着追加过去。
strcat()函数中的源字符串必须以'\0'结束。
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。
字符串不可以使用该函数实现自己给自己追加,如果自己给自己追加会发生越界访问。

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[20] = "hello\0XXXXXX";  

	//arr2追加到arr1后面,会先找到\0,然后从\0开始追加(会将\0直接覆盖),并且会将arr2的\0也追加过去
	//所以这就要求源字符串arr2必须以\0结尾.
	char arr2[] = " world";  
	strcat(arr1, arr2);
    //printf("%s\n", arr1);
    printf("%s\n",strcat(arr1,arr2));
	
	//实验strcat()函数实现字符串自己给自己追加
	char arr3[] = "bit";
	strcat(arr3, arr3);
	printf("%s\n", arr3); //会将arr3中bit\0中的\0给覆盖,然后一直循环追加bitbitbit,直到遇见内存中的\0才停止

	return 0;
}
模拟实现strcat()函数
#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);
	char* start = dest;
	while (*dest != '\0')
	{
		dest++;
	}
	//while (*src != '\0')
	//{
	//	*dest = *src;
	//	dest++;
	//	src++;
	//}
	//*dest = *src; //将源字符串中最后的\0也追加过去

	//简便写法
	while (*dest++ = *src++);

	return start;
}
int main()
{
	char arr1[20] = "hello\0XXXXXXX";
	char arr2[] = " world";
	my_strcat(arr1, arr2);

	//printf("%s\n", arr1);
	printf("%s\n", my_strcat(arr1, arr2));  //链式访问
	return 0;
}

strcmp()函数

strcmp()函数使用
strcmp()函数的返回值为int,当返回的值大于0,代表第一个字符串大于第二个字符串;当小于0,代表第一个字符串小于第二个字符串;当等于0,代表两个字符串大小相等。strcmp()比较字符串不是比较长度,而是从字符串首个字符开始,逐一比较,如果有一个字符不同,则字符ACSCII码大的字符所在的字符串就大于另一个字符串。当比较到\0时两个字符串还都相同就说明两个字符串的大小相等。 VS中的strcmp()函数规定了第一个字符串大于第二个字符串返回1,第一个字符串小于第二个字符串返回-1,两个字符串相等返回0.但其他编译器返回值可能有所不同。
第一个参数为第一个要比较的字符串的首字符地址。
第二个参数为第二个要比较的字符串的首字符地址。

//strcmp
#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abc";
	char arr2[] = "abc";
	int ret = strcmp(arr1, arr2);
	//strcmp函数比较的不是字符串的长度,而是比较字符串中对应位置上的字符的大小
	//如果相同,就比较下一对,直到不同或者都遇到\0
	if (ret > 0)
	{
		printf(">\n");
	}
	else if (ret == 0)
	{
		printf("==\n");
	}
	else
	{
		printf("<\n");
	}
	printf("%d\n", ret);

	return 0;
}
模拟实现strcmp()函数
#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
		while (*str1 == *str2)
		{
			if (*str1 == '\0')
			{
				return 0;  //相等
			}
			str1++;
			str2++;
		}
		/*if (*str1 > *str2)
		{
			return 1;
		}
		else
		{
			return -1;
		}*/

		//或者写成这样
		return *str1 - *str2;
}
int main()
{
	char arr1[] = "abr";
	char arr2[] = "abc";
	int ret = my_strcmp(arr1, arr2);
	if (ret > 0)
	{
		printf(">\n");
	}
	else if (ret == 0)
	{
		printf("==");
	}
	else
	{
		printf("<\n");
	}

	return 0;
}

长度受限制的字符串函数

strncpy()函数

strncpy()函数使用

strncpy()函数的返回值和参数都和strcpy()函数的类型,不过strncpy多了一个参数,该参数为一个size_t类型的无符号整型,该参数可以定义,要从源字符串中拷贝到目标字符串的字符个数count。

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

//strncpy
#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "qwerdfjk";
	strncpy(arr1, arr2, 3);  //只会拷贝arr2字符串的前三个字符替换arr1的前三个字符
	printf("%s\n", arr1);  //qwedef

	char arr3[] = "abcdef";
	char arr4[] = "qwe";
	strncpy(arr3, arr4, 5); //如果源字符串的长度不够,则拷贝完源字符串后会在后面补\0
	printf("%s\n", arr3);
	return 0;
}
 模拟实现strncpy()函数
//strncpy()
char* my_strncpy(char* dest, const char* src, size_t count)
{
	assert(dest && src);
	char* head = dest;
	while (count != 0)
	{
		*dest = *src;
		dest++;
		if (*src != '\0')
		{
			src++;
		}
		--count;
	}
	return head;
}
int main()
{
	char arr1[20] = "abcdXXXXXX";
	char arr2[5] = "efgh";

	//strncpy(arr1, arr2, 6);
	//printf("%s\n", strncpy(arr1, arr2, 6));
	
	my_strncpy(arr1, arr2, 2);
	printf("%s\n", arr1);
	printf("%s\n", my_strncpy(arr1, arr2, 2));

	return 0;
}

strncat()函数

strncat()函数使用
strncat()函数和strcat()函数的返回值和参数类似,只不过strncat()多了一个参数,该参数用来定义从源字符串中向目标字符串中追加的字符个数count。 
strncat中的源字符串追加到目标字符串后面count个字符后,还会在后面补一个\0。当源字符串的长度不够count时,会把源字符串都追加到目标字符串后面,然后只在后面补一个\0,没有追加count个字符也没关系。

strncat可以实现自己给自己追加。

//strncat
#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[20] = "abcdeXXXX";
	char arr2[] = "qwerdks";
	strncat(arr1, arr2, 5);
	printf("%s\n", arr1);  //abcdeXXXXqwerd

	char arr3[20] = "abcde\0XXXXXXXX";
	char arr4[] = "qwerrtuta";
	//strncat会寻找目标字符串的\0,然后将从\0开始追加(会将\0覆盖掉)
	//并且会在追加的源字符串后面补上\0
	strncat(arr3, arr4, 5);  //abcdeqwerr
	printf("%s\n", arr3);

	char arr5[20] = "abcde\0XXXXXXXX";
	char arr6[] = "qwe";
	//当源字符串arr6的长度不够5时,会先将arr6追加到arr5后,然后只会补一个\0
	strncat(arr5, arr6, 8);
	printf("%s\n", arr5);

	return 0;
}
 模拟实现strncat()函数
//strncat()
char* my_strncat(char* dest, const char* src, size_t count)
{
	assert(dest && src);
	char* head = dest;
	while (*dest != '\0')
	{
		dest++;
	}
	while (count != 0)
	{
		*dest = *src;
		if (*src == '\0')
		{
			break;
		}
		dest++;
		src++;
		count--;
	}
	*dest = '\0';
}

int main()
{
	char arr1[20] = "abcdXXXX";
	char arr2[5] = "efgh";
	//strncat(arr1, arr2, 8);
	//my_strncat(arr1, arr2, 4);
	my_strncat(arr1, arr1, 4);

	printf("%s\n", arr1);
	return 0;
}

strncmp()函数

strncmp()函数使用
strncmp()的返回值和参数与strcmp()函数的类似,只不过strncmp()函数多了一个比较字符数量的参数count,即比较两个字符串的前count个字符。


//strncmp
#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcdq";
	int ret1 = strncmp(arr1, arr2, 4);  //只会比arr1和arr2的前四个字符
	printf("%d\n", ret1);

	char arr3[] = "abcdef";
	char arr4[] = "ab";
	int ret2 = strncmp(arr3, arr4, 4);  //如果有一个字符串的长度不够,也正常比较,如果前面的字符都相等,那么最后就是'\0'和字符比较
	printf("%d\n", ret2);

	char arr5[] = "abcdef";
	char arr6[] = "abc";
	if (arr5 < arr6)   //比较的是arr1和arr2的地址
	{ 
		printf("hh\n");
	}
	if ("abc" < "abcdef")  //比较的是常量字符"abc" 和 "abcdef"的地址
	{
		printf("hh\n"); 
	}

	return 0;
}
模拟实现strncmp()函数
//strncmp()
int my_strncmp(const char* str1, const char* str2, size_t count)
{
	assert(str1 && str2);
	while ((*str1 == *str2) && (count != 0))
	{
		if (*str1 == '\0')
		{
			return 0;
		}
		str1++;
		str2++;
		count--;
	}
	/*if (*str1 > *str2)
	{
		return 1;
	}
	else
	{
		return -1;
	}*/
	return *str1 - *str2;
}
int main()
{
	char arr1[20] = "abcdXXXXX";
	char arr2[5] = "abcd";
	//printf("%d\n", strncmp(arr1, arr2, 5));
	
	printf("%d\n", my_strncmp(arr1, arr2, 3));

	return 0;
}

strstr()函数

strstr()函数使用
strstr()函数为查找子字符串函数,该函数的返回值为char*类型的指针,即为查找到的子字符串在目标字符串中第一次出现的位置的地址,如果目标字符串中没有该子字符串,则会返回NULL。
第一个参数为目标字符串的首字符地址。
第二个参数为要查找的子字符串的首字符地址。 

//strstr
#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abcdeqabcdefafs";
	char arr2[] = "cdef";

	//strstr()函数会将arr2字符串在arr1字符串中首次出现的位置的地址返回
	//如果在arr1中没有找到arr2,就会返回NULL
	char* ret = strstr(arr1, arr2);
	if (NULL == ret)
	{
		printf("找不到字符串\n");
	}
	else
	{
		printf("%s\n", ret);
	}

	return 0;
}
模拟实现strstr()函数
#include<stdio.h>
#include<assert.h>
char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	//因为形参str1和str2都用const修饰,所以为了保持一致,下面的s1、s2、cur也需要用const修饰
	const char* s1 = str1;
	const char* s2 = str2;
	const char* cur = str1;  //回溯指针,用来使s1回到起始位置。
	while (*cur != '\0')  
	{
		s1 = cur;  //将s1回溯到下一个字符
		s2 = str2; //将s2回溯到字符串首字符
		while (*s1 == *s2 && *s1!='\0' && *s2!='\0')  //如果s1和s2指向的字符一直,就继续向后寻找,直到遇见*s1和*s2不想等,或者有一个字符串结束.
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')  //如果结束是因为s2字符串已经结束,则说明查找成功
		{
			//因为该函数要返回char*的指针,而cur是const修饰的,所以强制类型转换一下,使返回的cur为char*类型的指针
			return (char*)cur; //返回arr1中该字符串的首地址
		}
		cur++;  //如果没有*cur字符为首字符没有查到,则使cur向后移一位,以后面的字符为首字符开始查找
	}

	return NULL;  //如果cur指向\0时还没有查到,说明arr1中没有arr2字符串。则返回NULL
}
int main()
{
	char arr1[] = "abbsabcafa";
	char arr2[] = "bbc";
	char* ret = my_strstr(arr1, arr2);
	if (ret == NULL)
	{
		printf("没有找到\n");
	}
	else
	{
		printf("%s\n", ret);
	}

	return 0;
}

strtok()函数

strtok()函数使用
strtok()函数为分割字符串函数,该函数的返回值为分割后字符串的首字符地址。
第一个参数指定一个字符串,它包含了0个或者多个由strDelimit字符串中一个或者多个分隔符分割的标记。
第二个参数strDelimit是个字符串,定义了用作分隔符的字符集合。
strtok函数找到strToken字符串中的下一个标记,并将其用\0结尾,返回一个指向这个被截断字符串的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
strtok函数的第一个参数不为NULL,函数将找到strToken中第一个标记,strtok函数将保持它在字符串中的位置。
strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
如果字符串中不存在更多的标记,则返回NULL指针。

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "dongruo@qq.com!!";
	char buf[30] = { 0 };
	char buf2[30] = { 0 };
	strcpy(buf, arr);   //strtok函数会改变传进去的字符串,所以在使用时一般传入临时拷贝的内容,并且该字符串需要是可修改的。
	strcpy(buf2, arr);
	const char* sep = "@.";  //该字符串为分隔符集合字符串,就是要按照这个字符串里面的字符来分割buf字符串



	printf("%s\n", strtok(buf, sep));  //只找第一个标记,第一次使用需要第一个参数需要传入被分割字符串,strtok找到后,
	//会将该字符串中第一个出现的分隔符设为\0,并且会保存分隔符后面的地址,并且将这个包含\0的字符串返回。
	
	//当第二次使用strtok函数时,第一个参数可以传NULL,然后就会从上一次保存的地址开始向后查找分隔符,找到后会将分隔符设为\0,
	//然后接着保存分隔符后面的地址,并且将处理好的包含\0的字符串返回。
	printf("%s\n", strtok(NULL, sep));  //是从保存好的位置开始继续往后找
	printf("%s\n", strtok(NULL, sep));  //是从保存好的位置开始继续往后找

	//使用循环打印分割好的字符,因为使用时不知道目标字符串里面含有多少个分隔符
	char* str = NULL;
	//先在初始化时调用第一次strtok,并且第一参数传入目标字符串,
	//然后判断strtok的返回值str,如果strtok函数找到了就返回被分割字符串的首地址,如果没找到就返回NULL/
	//然后接下来的调用strtok第一个参数就传入NULL,以便向后查找并且分割目标字符串。
	for (str = strtok(buf2, sep); str != NULL; str = strtok(NULL, sep))
	{
		printf("%s\n", str);
	}
	return 0;
}

strerror()函数

strerror()函数使用
strerror()函数的返回值是一个char*的指针,即返回的是错误信息。
该函数的参数为int型,就是传入一个错误码,然后strerror()函数根据这个错误码返回对应的错误信息。


#include<stdio.h>
#include<errno.h>
#include<limits.h>
#include<string.h>
#include<stdio.h>
int main()
{
	//每个错误都对应一个错误码。当程序运行时遇到错误后,就会将错误码变量errno的值改为对应的错误码
	//然后调用strerror函数并且传入错误码,就会打印对应的错误信息。
	//errno为一个全局变量
	int* p = (int*)malloc(LLONG_MAX);  //向堆区申请内存
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));  //Not enough space
		printf("%d\n", errno);  //12 ,所以可知Not enough space错误的错误码为12
		perror("Malloc");  //perror函数会直接将错误的信息打印出来,并且会将传入的字符串后面加上:然后将错误信息打印在后面。
		return 1;
	}
	printf("nn");
	return 0;
}

字符操作函数

字符分类函数

字符分类函数使用
这些函数用来判断字符是否符合条件,如果符合条件就返回真,不符合就返回假。

使用这些函数需要引用头文件,即 #include<ctype.h>

 字符转换
可以将里面的字母转换为大写或者小写,如果已经是大写或小写就不会再转换了。
//字符判断函数
#include<stdio.h>
#include<string.h>
#include<ctype.h>
int main()
{
	if (isdigit('2'))
	{
		printf("是数字\n");
		printf("%d\n", isdigit('2'));  //如果符合条件就返回真,即返回非0数字
		printf("%d\n", isdigit('a'));  //如果不符合条件就返回假,即返回0

	}

	printf("%c\n", toupper('a'));  //A
	printf("%c\n", toupper('A'));  //如果已经是大写,就不做任何操作  A
	printf("%c\n", tolower('B'));  //b

	return 0;
}

 内存操作函数

memcpy()函数

memcpy()函数使用
memcpy()函数的返回值为一个void*类型的指针,即为目标数组的地址。
memcpy()函数的第一个参数和第二个参数都设置为void*型,是为了使该函数可以拷贝任意类型的数组。第一个参数为目标数组地址,第二个参数为源数组的地址。
第三个参数为size_t类型的无符号整数,定义了从源地址向后拷贝多少字节的数据到目标地址。
函数memcpy从src位置开始向后复制count个字节的数据到dest的内存位置。
这个函数在遇到'\0'的时候并不会停下来,只有在复制够count个字节后才会停下。
如果src和dest中有任何的重叠,复制的结果都是错的。

#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[5] = { 0 };
	memcpy(arr2, arr1, 20);  //将arr1的前二十个字节的数据拷贝到arr2中
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr2[i]);
	}

	return 0;
}
模拟实现memcpy()函数
#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* src,size_t count)
{
	assert(dest && src);
	void* start = dest;
	while (count)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
		count--;
	}
	return start;
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[5] = { 0 };
	my_memcpy(arr2, arr1, 20);
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr2[i]);
	}
	printf("\n");
	my_memcpy(arr1 + 2, arr1, 20);  //当拷贝的数据在内存中重叠时,就会发生错误,因为原来的数据被修改的数据覆盖了。
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

memmove()函数

memmove()函数使用
memmove()函数memcpy()函数的差别就是memmove函数处理的源内存和目标内存块是可以重叠的。所以如果源空间和目标空间出现重叠,就得使用memmove函数处理。

//memmove()
#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr1 + 2, arr1, 20); //可以实现重叠内存的拷贝
	int i = 0;
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}
模拟实现memmove()函数
my_memmove()函数解决目标内存与源内存重叠情况的办法,即通过判断来决定是从前向后拷贝还是从后向前拷贝。

#include<stdio.h>
#include<assert.h>
void* my_memmove(void* dest, const void* src, size_t count)
{
	assert(dest && src);
	void* start = dest; //用来记录要返回的地址
	if (dest < src)  //当dest<src时,从前向后拷贝
	{
		while (count)
		{
			//因为形参定义类型为void*,是为了使任何数据类型的地址都可以使用此函数拷贝,
			//而在实现时,都强制类型转换为char*类型,这样才能按字节拷贝数据
			*(char*)dest = *(char*)src; 
			dest = (char*)dest + 1;
			src = (char*)src + 1;
			count--;
		}
	}
	else  //剩下的情况从后向前拷贝
	{
		while (count)
		{
			//即从目标空间的最后开始拷贝。
			//(char*)dest + count刚好指向了目标空间后的第一个地址,所以要-1才指向目标空间最后一字节的地址。
			*((char*)dest + count - 1) = *((char*)src + count - 1);
			count--;
		}
	}

	return start;  //将拷贝好的空间地址返回
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr1 + 2, arr1,20);  //可以实现重叠内存的拷贝
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr1[i]);  //1 2 1 2 3 4 5 8 9 10
	}
	return 0;
}
memcpy()函数和memmove()函数比较
虽然模拟实现的my_memcpy函数不能处理内存空间重叠的情况,但是在编译器的完善中,编译器实现的mymcpy()函数已经也可以处理内存空间重叠的情况了,所以编译器将memcpy()函数的功能完善的和memmove()函数的功能基本一致了。

memcmp()函数

memcmp()函数使用
memcmp()函数的返回值为int型,即和strcmp()函数的返回值代表的意义相同。
memcmp()函数比strcmp()函数多了一个size_t类型的参数,该参数定义了两个字符串要比较的字符的个数count。即比较从buf1和buf2指针开始的count个字节。 

//memcmp
#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 1,2,3,4,0x11223305 };
	int ret = memcmp(arr1, arr2, 17);
	printf("%d\n", ret); //  0

	ret = memcmp(arr1, arr2, 18);
	printf("%d\n", ret);  //  -1


	return 0;
}

 模拟实现memcmp()函数

//memcmp()
int my_memcmp(const void* buf1, const void* buf2, size_t count)
{
	assert(buf1 && buf2);
	void* str1 = buf1;
	void* str2 = buf2;

	while ((*((char*)str1) == *((char*)str2))&&(count!=0))
	{
		str1 = (char*)str1 + 1;
		str2 = (char*)str2 + 1;
		--count;
	}
	if (count == 0)
	{
		return 0;
	}
	if (*((char*)str1) > *((char*)str2))
	{
		return 1;
	}
	else
	{
		return -1;
	}
}
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 1,2,3,4,0x11223305 };
	int ret = memcmp(arr1, arr2, 17);
	printf("%d\n", ret); //  0

	ret = memcmp(arr1, arr2, 18);
	printf("%d\n", ret);  //  -1

	return 0;
}

memset()函数

memset()函数使用

memset()函数的返回值为void*类型的指针,即为处理过的数据的地址。

第一个参数为void*类型的指针,所以任何类型的数据都可以调用memset()函数来实现按字节设置数据。

第二个参数为int型,即为要设置的数据为什么。

第三个参数为size_t类型,即为要改变的字节数。

//memset()
#include<stdio.h>
#include<string.h>
int main()
{
	int arr[] = { 0x11111111,0x22222222,3,4,5 };
	memset(arr, 6, 20);  //memset是以字节为单位来初始化内存单元的
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%p\n", arr[i]);  // 
	}
	return 0;
}

模拟实现memset()函数
//memset()
void* my_memset(void* dest, int c, size_t count)
{
	assert(dest);
	void* start = dest;
	while (count)
	{
		*((char*)dest) = (char)c;
		dest = (char*)dest + 1;
		--count;
	}

	return dest;
}
int main()
{
	int arr1[] = { 0x11111111,0x22222222,3,4,5 };
	//memset(arr1, '\0', 4);
	my_memset(arr1, 6, 20);

	int sz = sizeof(arr1) / sizeof(arr1[0]);
	for (int i = 0; i < sz; i++)
	{
		printf("%p ", arr1[i]);
	}
	printf("\n");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值