学习小结
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以.来切割
// //zpw@bitedu.tech
// //zpw bitedu tech
// char arr[] = "zpw@bitedu.tech";
// 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环境下编译