C语言学习笔记——字符、字符串、内存操作函数章节

学习小结

c语言字符、字符串、内存操作函数的学习笔记汇总

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<string.h>
//字符操作函数和字符串操作函数以及内存操作函数
//长度不受限制的字符串函数
//strcpy 字符串拷贝
//strcat 字符串追加
//strcmp 字符串比较

//长度受限制的字符串函数
//strncpy 字符串拷贝(有字数限制)
//strncat 字符串追加(有字数限制)
//strncmp 字符串比较(有字数限制)

//strlen:求字符串长度  strlen返回值是一个无符号的整形
//碰到\0停止,注意不包括\0
//int main()
//{
//	//int len1 = strlen("abcdef");//6
//	char arr[] = { 'a','b','c','d','e','f' };
//	int len2 = strlen(arr);//随机值,因为这段字符数组中没有\0
//	printf("%d\n", len2); 
//	return 0;
//}

//自定义实现strlen函数
//1、计数器的方法
//2、递归
//3、指针减指针的方法
//#include<assert.h>
//int my_strlen(const char* str)
//{
//	int count = 0;
//	assert(str != NULL);//断言函数 保证指针的有效性
//	while (*str != '\0')
//	{
//		count++;
//		str++;
//	}
//	return count;
//}
//int main()
//{
//	char arr[] = "abcdef";
//	int len = my_strlen(arr);
//	printf("%d\n", len); 
//	return 0;
//}
//递归的方式实现strlen
//int my_strlen(char* arr)
//{
//	if (*arr != '\0')
//	{
//		return my_strlen(arr + 1) + 1;
//	}
//	else
//	{
//		return 0;
//	}
//}
//int main()
//{
//	char arr[] = "abcdef";
//	int len = my_strlen(arr);
//	printf("%d\n", len);
//	return 0;
//}

//strcpy:字符串拷贝
//#include<string.h>
//int main()
//{
//	char arr1[] = "abcdef";
//	char arr2[] = "bit";
//	strcpy(arr1, arr2);
//	printf("%s\n", arr1);//bit
//	return 0;
//}
//自定义strcpy函数
//#include<assert.h>
//void my_strcpy(char* dest, const char* src)
//{
//	assert(dest != NULL && src != NULL);//保证指针的有效性
//
//	while (*src != '\0')
//	{
//		*dest++ = *src++;
//	}
//	*dest = *src;
//}
//int main()
//{
//	char arr1[] = "abcdef";
//	char arr2[] = "bit";
//	my_strcpy(arr1, arr2);
//	printf("%s\n", arr1);//bit
//	return 0;
//}

//strcat:字符串追加函数(拼接)
//strcat() 函数把 strSource 所指向的字符串追加到 strDestination 所指向的字符串的结尾
//所以必须要保证 strDestination 有足够的内存空间来容纳两个字符串,否则会导致溢出错误
//注意:strDestination 末尾的\0会被覆盖,strSource 末尾的\0会一起被复制过去,最终的字符串只有一个\0
#include<string.h>
//int main()
//{
//	char arr1[20] = "hello\0xxxxxxxx";
//	char arr2[] = "world";
//	strcat(arr1, arr2);
//	printf("%s\n", arr1);
//	return 0;
//}
//自定义strcat
//#include<assert.h>
//char* my_strcat(char* dest, const char* src)
//{
//	char* ret = dest;
//	assert(dest != NULL && src != NULL);//保证指针的有效性
//	//1、找到目的字符串\0的位置
//	while (*dest != '\0')
//	{
//		dest++;
//	}
//	//2、找到之后在后面开始追加
//	while (*dest++ = *src++)
//	{
//		;
//	}
//	return ret;
//}
//int main()
//{
//	char arr1[20] = "hello";
//	char arr2[] = "world";
//	my_strcat(arr1, arr2);
//	printf("%s\n", arr1);
//	return 0;
//}

//strcmp:字符串比较函数 比的是ascll码值
//第一个字符串大于第二个字符串,则返回大于0的数字
//第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
//int main()
//{
//	char* p1 = "abcdef";
//	char* p2 = "asqwer";
//	if (strcmp(p1, p2) > 0)
//		printf("第一个大于第二个\n");
//	else if (strcmp(p1, p2) < 0)
//		printf("第一个小于第二个\n");
//	else
//		printf("等于\n");
//	return 0;
//}
//自定义实现strcmp函数
//#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;//小于
//}
//int main()
//{
//	char* p1 = "abc";
//	char* p2 = "abqwe";
//	int ret=my_strcmp(p1, p2);
//	printf("%d", ret);
//	return 0;
//}

//strncay 字符串拷贝(有字数限制)
//基本格式
//char* strncpy(char* destinin, char* source, int maxlen);
//int main()
//{
//	char arr1[10] = "abcef";
//	char arr2[] = "hello bit";
//	strncpy(arr1, arr2, 4);
//	printf("%s", arr1);
//	return 0;
//}
//自定义实现strncpy函数
//char* my_strncpy(char* str1, char* str2, int num)
//{
//	int i = 0;
//	char* tmp = str1;
//	for ( i = 0; i < num; i++)
//	{
//		*str1++ = *str2++;
//	}
//	return (tmp);
//}
//int main()
//{
//	char arr1[10] = "abcef";
//	char arr2[] = "hello bit";
//	my_strncpy(arr1, arr2, 4);
//	printf("%s", arr1);
//	return 0;
//}

//strncat 字符串追加(有字数限制)在字符串中第一个\0处开始追加n个字符
//格式
//char* strncat(char* dest, const char* src, size_t n);
//int main()
//{
//	char arr1[30] = "hello\0xxxxxxx";
//	char arr2[] = "world";
//	strncat(arr1, arr2, 3);
//	printf("%s\n", arr1); //hellowor
//	return 0;
//}
//自定义实现strncat函数
//char* my_strncat(char* str1, char* str2, int num)
//{
//	char* tmp = str1;
//	//找到str1中\0的位置
//	while (*str1 != '\0')
//	{
//		str1++;
//	}
//	for (int i = 0; i < num; i++)
//	{
//		*str1++ = *str2++;
//	}
//	//在str1结尾处放一个\0
//	*str1 = '\0';
//	return tmp;
//}
//int main()
//{
//	char arr1[30] = "hello\0xxxxxxx";
//	char arr2[] = "world";
//	my_strncat(arr1, arr2, 4);
//	printf("%s\n", arr1); //hellowor
//	return 0;
//}

//strncmp 字符串比较(有字数限制)
//格式
//int strncmp(const char* str1, const char* str2, size_t n)
//int main()
//{
//	const char arr1[] = "abcdef";
//	const char arr2[] = "abcqwer";
//	int len = strncmp(arr1, arr2, 2);
//	printf("%d\n", len);
//	return 0;
//}
//size_t在vs编译器中表示无符号整形的简写(unsigned int)
//#include<assert.h>
//int my_strncmp(char* str1, char* str2, int num)
//{
//	assert(str1 != NULL && str2 != NULL);
//	while (*str1 == *str2)
//	{
//		if (num == 0)
//			return 0;
//		str1++;
//		str2++;
//		num--;
//	}
//
//	return (*str1 - *str2);
//}
//int main()
//{
//	const char arr1[] = "abcdef";
//	const char arr2[] = "abcqwer";
//	int len = my_strncmp(arr1, arr2, 4);
//	printf("%d\n", len);
//	return 0;
//}

//strstr作用是返回字符串中首次出现子串的地址 (查找字符串)
//注意:找不到时会返回一个空指针
//格式
//char *strstr(const char *haystack, const char *needle)
//int main()
//{
//	char* p1 = "abcdef123";
//	char* p2 = "def";
//	char* ret = strstr(p1, p2);
//	if (ret == NULL)
//		printf("字串不存在");
//	else
//		printf("存在,是:%s\n", ret);
//	return 0;
//}
//自定义实现strstr函数
//#include<assert.h>
//char* my_strstr(const char* p1, const char* p2)
//{
//	assert(p1 != NULL && p2 != NULL);
//	char* s1 = (char*)p1;
//	char* s2 = (char*)p2;
//	char* cur = (char*)p1;
//	//空字符串返回p1的地址
//	if (*p2 == '\0')
//	{
//		return (char*)p1;
//	}
//	while (*cur)
//	{
//		s1 = cur;
//		s2 = (char*)p2;
//		while ((*s1 != '\0') && (*s2 != '\0') && (*s1 == *s2))
//		{
//			s1++;
//			s2++;
//		}
//		if (*s2 == '\0')
//		{
//			return (cur);//找到字串
//		}
//		cur++;
//	}
//	//找完整个串没找到返回NULL
//	return NULL;
//}
//int main()
//{
//	char* p1 = "abcdef123";
//	char* p2 = "";
//	char* ret = my_strstr(p1, p2);
//	if (ret == NULL)
//		printf("字串不存在");
//	else
//		printf("存在,是:%s\n", ret);
//	return 0;
//}
//注意:kmp算法

//strtok函数:字符串分割
//格式
//char* strtok(char* s, const char* delim);
//分解字符串 str 为一组字符串,delim 为分隔符
//注意:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容
//int main()
//{
//	//点分时进制的表示方式 ip地址的表示方式
//	//192.168.31.121
//	//192 168 31 121 -strtok以.来切割
//	//[email protected]
//	//zpw bitedu tech
//	char arr[] = "[email protected]";
//	char* p = "@.";
//	char buf[1024] = { 0 };
//	//基本用法
//	//strtok(arr, p);
//
//	strcpy(buf, arr);//拷贝 相当于是对arr的副本进行修改
//	//切割buf中的字符串
//	//原理
//	//char* ret = strtok(buf, p);
//	//printf("%s\n", ret);//zpw
//
//	//ret = strtok(NULL, p);
//	//printf("%s\n", ret);//bitedu
//
//	//ret = strtok(NULL, p);
//	//printf("%s\n", ret);//tech
//	char* ret = NULL;
//	for (ret = strtok(arr, p); ret != NULL; ret = strtok(NULL, p))
//	{
//		printf("%s\n", ret);
//	}
//
//
//	return 0;
//}

//strerror寻找错误码(返回错误码,所对应的信息)
//当C语言的库函数在执行过程中,发生了错误,就会把对应的错误码,赋值到errno中
//格式
//char *strerror(int errnum)
//int main()
//{
//	char* str = strerror(0);
//	printf("%s\n", str); //No error
//	return 0;
//}
//int main()
//{
//	char* str = strerror(1);
//	printf("%s\n", str); // Operation not permitted不允许操作
//	return 0;
//}
//int main()
//{
//	char* str = strerror(2);
//	printf("%s\n", str); //No such file or directory 没有这个文件或者文件夹
//	return 0;
//}
//错误码(每一个错误码对应一个错误信息)
//0- No error没错误
//1- Operation not permitted不允许操作
//2- No such file or directory 没有这个文件或者文件夹
//#include <errno.h>
//int main()
//{
//	//errno是一个全局的错误码的变量
//	//当c语言的库函数在执行的过程中发生了错误,就会把对应的错误码,赋值到errno中
//	//char* str = strerror(errno);
//	//printf("%s\n", str);
//
//	//打开文件
//	// 格式
//	// FILE *fp = fopen("demo.txt", "r");
//	//fopen() 会获取文件信息,包括文件名、文件状态、当前读写位置等,并将这些信息保存到一个 FILE 类型的结构体变量中,然后将该变量的地址返回
//	FILE* pf = fopen("test.txt", "r");
//	//FILE 是 <stdio.h> 头文件中的一个结构体,它专门用来保存文件信息
//	//打开文件出错时,fopen() 将返回一个空指针,也就是 NULL
//	if (pf == NULL)
//	{
//		printf("%s\n", strerror(errno));//打开失败,并输出失败的原因
//	}
//	else
//	{
//		printf("open file success\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	任何可打印字符,包括图像字符和空白字符
//#include<ctype.h>
//int main()
//{
//	//char ch = 'w';
//	//int ret = islower(ch);//这个函数是判断ch是否为小写字符 如果是小写字母返回非0值,如果不是小写字母返回0
//	//printf("%d\n", ret);//2 - 小写
//
//	char ch = '1';
//	int ret = isdigit(ch);//这个函数是判断ch是否为数字字符 如果是返回非0值,如果不是返回0
//	printf("%d\n", ret);//4 - 数字
//	return 0;
//}

//字符转换
//tolower() 函数把给定的字母转换为小写字母
//toupper() 函数用来将小写字母转换为大写字母
//#include<ctype.h>
//int main()
//{
//	char ch = tolower('Q');//大写转小写
//	//char ch = toupper('q');//小写转大写
//	//putchar(ch);//打印字符
//	int i = 0;
//	char arr[] = "I Am A Studyent";
//	//全部改为小写字母
//	while (arr[i] != '\0')
//	{
//		if (isupper(arr[i]))//如果是大写进入if
//		{
//			arr[i] = tolower(arr[i]);
//		}
//		i++;
//	}
//	printf("%s\n", arr);
//	return 0;
//}

//内存函数
//memcpy 内存拷贝函数
//void* memcpy(void* str1, const void* str2, size_t n)
//从存储区 str2 复制 n 个字节到存储区 str1
//函数原型
//void *memcpy(void* dest, const void* src, size_t n);

//#include<string.h>
//int main()
//{
//	int arr1[] = { 1,2,3,4,5 };
//	int arr2[5] = { 0 };
//	strcpy(arr2, arr1);//strcpy字符串拷贝,遇到斜杠0会停止拷贝
//	return 0;
//}
//#include<string.h>
//typedef struct S
//{
//	char name[20];
//	int age;
//}Stu;
//int main()
//{
//	//int arr1[] = { 1,2,3,4,5 };
//	//int arr2[5] = { 0 };
//	//memcpy(arr2, arr1, 5 * sizeof(arr1[0]));
//	
//	Stu arr3[] = { {"张三",20},{"李四",21} };
//	Stu arr4[5] = { 0 };
//	memcpy(arr4, arr3, sizeof(arr3));
//	return 0;
//}
//自定义实现memcpy函数
//#include<string.h>
//#include<assert.h>
//typedef struct S
//{
//	char name[20];
//	int age;
//}Stu;
typedef unsigned __int64 size_t;说明size_t是 unsigned int的重命名
//void* my_memcpy(void* dest, const void* src, size_t num)
//{
//	void* ret = dest;
//	assert(dest && src);
//	//因为void*指针不能进行解引用操作,以及急++ --等,所以强制类型转换
//	//以字节为单位,进行操作
//	while (num--)
//	{
//		*((char*)dest) = *((char*)src);
//		++((char*)dest);
//		++((char*)src);
//	}
//	return ret;
//}
int main()
{
	//int arr1[] = { 1,2,3,4,5 };
	//int arr2[5] = { 0 };
	//memcpy(arr2, arr1, 5 * sizeof(arr1[0]));

	Stu arr3[] = { {"张三",20},{"李四",21} };
	Stu arr4[5] = { 0 };
	my_memcpy(arr4, arr3, sizeof(arr3));
	return 0;
}
//int main()
//{
//	int i;
//	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
//	//memcpy(arr + 2, arr, 20);
//	//for (i = 0; i < 10; i++)
//	//{
//	//	printf("%d ", arr[i]); //1 2 1 2 3 4 5 8 9 10
//	//}
//	my_memcpy(arr + 2, arr, 20);
//	for (i = 0; i < 10; i++)
//	{
//		printf("%d ", arr[i]); //1 2 1 2 1 2 1 8 9 10 memcpty不能用于拷贝重叠数据
//	}
//	//return 0;
//}

//memmove用于拷贝字节,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,但复制后源内容会被更改。
//但是当目标区域与源区域没有重叠则和memcpy函数功能相同
//格式
//void *memmove(void *str1, const void *str2, size_t n)
//memmove函数
//c语言标准规定
//memcpy只要处理不重叠的内存拷贝就可以
//memmove用于处理重叠内存的拷贝(既可以处理重叠,也可以处理不重叠)
//int main()
//{
//	int i;
//	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
//	memmove(arr + 2, arr, 20);//处理内存重叠情况
//	for (i = 0; i < 10; i++)
//	{
//		printf("%d ", arr[i]); //1 2 1 2 3 4 5 8 9 10
//	}
//}

//注意:c语言标准说memcpy函数可以拷贝不重叠的就可以了
//当下发现vs2022环境下memcpy函数可以处理重叠拷贝

自定义实现memmove函数
//第一种写法
//void* my_memmove(void* dest, void* src, size_t count)
//{
//	if (dest < src)//从前向后拷贝
//	{
//		void* ret = dest;
//		while (count--)
//		{
//			*((char*)dest) = *((char*)src);
//			++(char*)dest;
//			++(char*)src;
//		}
//		return ret;
//	}
//	else//从后向前拷贝
//	{
//		void* ret = dest;
//		while (count--)
//		{
//			*((char*)dest + count) = *((char*)src + count);
//		}
//		return ret;
//	}
//}
//第二种
//void* my_memmove(void* dest, void* src, size_t count)
//{
//	if (dest < src || dest>(char*)src + count)//从前向后拷贝
//	{
//		;//....
//	}
//	else//从后向前拷贝
//	{
//		;//.....
//	}
//}
//int main()
//{
//	int i;
//	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
//	my_memmove(arr + 2, arr, 20);//处理内存重叠情况
//	for (i = 0; i < 10; i++)
//	{
//		printf("%d ", arr[i]); //1 2 1 2 3 4 5 8 9 10
//	}
//}

//memcmp函数
//功能是把存储区 str1 和存储区 str2 的前 n 个字节进行比较。该函数是按字节比较的
//int memcmp(const void* str1, const void* str2, size_t n)
//int main()
//{
//	//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 
//	//01 00 00 00 02 00 00 00 05 00 00 00 04 00 00 
//	int arr1[] = { 1,2,3,4,5 };
//	int arr2[] = { 1,2,5,4,3 };
//	int ret = memcmp(arr1, arr2, 9);
//	printf("%d\n", ret);
//	return 0;
//}

//memset函数 - 内存设置(单位是字节,对字节进行操作)
// void *memset(void *str, int c, size_t n)
//memset是计算机中C/C++语言初始化函数。作用是将某一块内存中的内容全部设置为指定的值,这个函数通常为新申请的内存做初始化工作
//int main()
//{
//	char arr[10] = "";
//	memset(arr, '#', 10);
//	return 0;
//}

以上代码均在vs2022环境下编译

猜你喜欢

转载自blog.csdn.net/qq_72935001/article/details/126336282