字符函数与字符串函数 和C语言内存函数<string.h>
目录
字符分类函数
字符转换函数
基础函数使用
strlen 使用和模拟与实现
strcpy 使用和模拟与实现
strcat 使用和模拟与实现
strcmp 使用和模拟与实现
进阶函数使用
strncpy 函数的使用
strncat 函数的使用
strncmp 函数的使用
strstr 使用和模拟实现
strtok 函数使用
strerror 函数使用
perror 函数使用
C语言内存函数
memcpy 使用和模拟实现
memmove 使用和模拟实现
memset 函数的使用
memcmp 函数的使用
字符分类函数
C语言中有一系列的函数是专门做字符分类的,也就是一个字符是属于什么类型的字符的。这些函数的使用都需要包含一个头文件是ctype .h
这写函数其实都比较类似,就只介绍一个
int islower ( int c );当识别到数值为a~z的小字母,就会返回非0 数值,如果不是就返回0数值。
字符转换函数
C语言提供了2个字符转换函数:
int tolower ( int c ); //将参数传进去的大写字母转小写 int toupper ( int c ); //将参数传进去的小写字母转大写函数使用
#include <stdio .h> #include <ctype .h> int main () { int i = 0; char str [] = "Test String.\n"; char c; while (str[i]) { c = str [i]; if (islower(c)) c = toupper(c); putchar(c); i++; } return 0; }但其实这中其实可以通过加减32来通过改变字符英文字母大小就可以,这个函数也只是作为一个了解即可。
<string.h>介绍
string.h 的库函数里面有strcpy、strcat、strcmp、strncpy、strncat、strncmp、strstr、strtok、strerror、memcmp等等的函数,那我们来一 一介绍。
基础<string.h>函数使用
strlen 使用和模拟与实现
strlen 的介绍
strlen 是用来计算字符串的首地址到达‘\0’位置之间又多少个字符的函数
补充:准确来说strlen 不是string.h 函数里面的没有string.h 的库函数也可以使用。
size_t strlen(char* str)放回类型:size_t (非负数的整形类型)
传参: char* (字符指针)
模拟实现:
strlen_my 函数来实现代码:
方法1:
利用循环来实习strlen的代码实现:
原理:通过循环计算当代码执行到‘\0’的时候就停止计算。
size_t strlen_my1(char* str) { size_t i = 0; for (i = 0; *(str + i) != '\0'; i++); return i; }方法2:
利用递归的方式来实现代码:
原理:通过执行代码如果不是‘\0’就进行1+strlen(str+1),如果遇到‘\0'就停止计算,返回值为0。
size_t strlen_my2(char* str) { if (*str) { return 1 + strlen_my2(str + 1); } return 0; }strcpy 使用和模拟与实现
strcpy 的介绍
strcpy 是一个cpy 有关的函数,通过cpy 就是拷贝的功能,可以将一个数组的内容考培到了一个数组里面。
char* strcpy(char* str1,char const* str2)返回值:char* 返回str1 的首元素地址
传参:
char* 第一个值是载体,要被同化对象。
char const * 第二个就是内容,从const *可以从不能对*str2不能修改内容就可以看出。
模拟实现
strcpy_my 函数来实现strcpy 函数代码实现
原理:
传参不能为空地址;
循环来实现代码,遇到‘\0’循环也可以直接结束;
在代码最开始的标记好首元素地址,循环执行完也也有直接返回地址。
char* my_strcpy(char* str1, char const* str2) { char* tmp = str1; assert(str1 != NULL); assert(str2 != NULL); while (*str1++ = *str2++); return tmp; }strcat 使用和模拟与实现
strcat 的介绍
strcat 的函数与strcpy 类似也是跟拷贝有关,但是它与strcpy拷贝不同,strcat 是在str1的字符串最后‘\0‘位置进行拷贝
char * strcat ( char * destination , const char * source );返回值:char* destination的最开始位置
传参:
destination:指针,指向目的地空间
source:指针,指向源头数据、
模拟实现:
my_strcat 实现代码:
原理就还是与strcpy 保持一致,就在拷贝之前先进行移位操作。
char* my_strcat(char* str1, char const* str2) { char* tmp = str1; assert(str1 != NULL); assert(str2 != NULL); while (*str1) str1++; while (*str1++ = *str2++); return tmp; }strcmp 使用和模拟与实现
strcmp 的介绍
strcmp 是用来比较的函数,比较标准是通过ASCII 的数值大小来比较的。
int strcmp ( const char * str1 , const char * str2 );返回值:
标准规定:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
模拟实现:
my_strcmp来实现代码:
原理:
int my_strcmp(const char* str1, const char* str2) { while (*str1 == *str2) { if (*str1 == '\0') return 0; str1++; str2++; } if (*str1 > *str2) return 1; else return -1; }进阶<string.h>函数使用
strncpy 函数的使用
strncpy 的介绍
strncpy 函数与strcpy 函数功能类似,多了一个传参值
char * strncpy ( char * destination , const char * source , size_t num );函数的多了一个可以可控制拷贝多少的控制:size_t num
当如果str
参数:
destination:指针,指向目的地空间
source:指针,指向源头数据
num:从source指向的字符串中最多拷贝的字符个数
返回值:
strncpy函数返回的目标空间的起始地址
函数的使用:
#include <stdio.h> #include <string.h> int main() { char str1[20] = "hello world."; char str2[20] = "world"; strncpy(str1, str2,5); printf("%s", str1); return 0; }以为world 要我去拷贝数量应该输入的6,而输入的是5 少拷贝了一个‘\0’的字符
strncat 函数的使用
strncat 的介绍
同理strncat 函数与strcat 函数也是多一个可控制的拷贝数量
int strncmp ( const char * str1 , const char * str2 , size_t num );功能:字符串比较;比较str1和str2指向的两个字符串的内容,最多比较num字符。
参数:
str1:指针,指向一个比较的字符串
str2:指针,指向另外一个比较的字符串
num:最多比较的字符个数
函数的使用
int main() { char str1[20] = "hello"; char str2[20] = " world.\0 I love me"; strncat(str1, str2,10); printf("%s", str1); return 0; }可以看到如果拷贝对象值中间有一个‘\0’,那么只拷‘\0’的位置就停止就不会在往后拷贝了。
strncmp 函数的使用
strncmp 的介绍
同理:strncmp也是多一个比较数量
int strncmp ( const char * str1 , const char * str2 , size_t num );参数:
str1:指针,指向一个比较的字符串
str2:指针,指向另外一个比较的字符串
num:最多比较的字符个数
返回值:
•标准规定:
◦第一个字符串大于第二个字符串,则返回大于0的数字
◦第一个字符串等于第二个字符串,则返回0
◦第一个字符串小于第二个字符串,则返回小于0的数字
函数使用
int main() { char str1[20] = "abcdef"; char str2[20] = "abcde"; int i=strncmp(str1, str2,5); printf("%d", i); return 0; }原理解释:
以为比较的长度只有5,那么比较str1 和str2 的长度5的内容一致,那么就直接返回0。
strstr 使用和模拟实现
strstr 的介绍
strstr 的功能是查找str2指向的字符串在str1指向的字符串中第一次出现的位置。
简而言之:就是找东西的函数
参数:
str1:指针,指向了被查找的字符串
str2:指针,指向了要查找的字符串
返回值:
•如果str 1指向的字符串中存在str2指向的字符串,那么返回第一次出现位置的指针
•如果str 1指向的字符串中不存在str2指向的字符串,那么返回NULL
函数的使用
int main() { char str1[20] = "hello world abcde"; char str2[20] = "abcde"; int* p=strstr(str1, str2); if (p) printf("%p", p); return 0; }模拟实现
my_strstr 函数实现
char* my_strstr(char const* str1, char const* str2) { assert(str1 != NULL); assert(str2 != NULL); const char* const ret = str2;//标记好str2 的初始位置 char* tmp = str1; int input = 0;//设置查找标记 while (*str1) { tmp = str1;//标记好初始位置 str2 = ret; while (*str1++ == *str2++) { if (!*str2)//所有的数值查找到‘\0’,就标记好查找结束 { input = 1;//标记查找到的证明 break; } } if (input) return tmp;//返回标记1位置 tmp++; str1 = tmp; } return NULL; } int main() { char str1[20] = "hello world abcde "; char str2[20] = "world"; int* p=my_strstr(str1, str2); if (p) printf("%p", p); return 0; }strtok 函数使用
strtok 的介绍
strtok 的函数的功能是分割字符串的功能
char *strtok(char *str , const char *delim);参数
1.str:首次调用时传入待分割的字符串;后续调用传入NULL,表示继续分割同一个字符串。
2.delim:包含所有可能分隔符的字符串(每个字符均视为独立的分隔符)。
返回值
•成功时返回指向当前子字符串的指针。
•没有更多子字符串时返回NULL。
使用步骤
1.首次调用:传入待分割字符串和分隔符。
2.后续调用:传入NULL和相同的分隔符,继续分割。
3.结束条件:当返回NULL时,表示分割完成。
注意strtok 具有一定的破坏性,会把原先的数组改的面目全非,为了防止代码对于原先字符串的破坏,要进行一个拷贝操作strcpy 。
函数的运用
展示1:
int main() { char str1[20] = "2026 5 10 21 28"; char str2[] = " "; char cpy[30] = {0}; strcpy(cpy, str1); for (char* str = strtok(cpy, str2); str != NULL; str = strtok(NULL, str2)) { printf("%s\n", str); } return 0; }展示2:
int main() { char str1[50] = "https://hello.world.com/";//分割内容 char str2[] = ":./";//分割标准 char cpy[30] = {0}; strcpy(cpy, str1); for (char* str = strtok(cpy, str2); str != NULL; str = strtok(NULL, str2)) { printf("%s\n", str); } return 0; }strerror 函数使用
strerror的介绍
strerror 函数就像名字一样,error 是跟报错有关的代码
char* strerror ( int errnum );传参:
int 对应的数值输出对应的报错
for (int i = 0; i <= 10; i++) { printf("%s\n", strerror(errno)); }//0 : No error 无错误
//1 : Operation not permitted 操作不被允许
//2 : No such file or directory 没有该文件或目录
//3 : No such process 没有给进度
//4 : Interrupted function call 函数调用中断
//5 : Input / output error 输入/输出错误
//6 : No such device or address 没有该设备或地址
//7 : Arg list too long 参数列数表过长
//8 : Exec format error 可执行格式错误
//9 : Bad file descriptor 错误的文件描述符
//10 : No child processes 没有子进度
怎么多的数值,我们也不可能一个一个去记住,所有就有<errno.h>这个库函数,来辅助程序员,当代码发生对应的错误的时候就会把对应代码报错信息,就会存进errno这个数值里面。
函数使用
#include <stdio.h> #include <errno.h> #include <stdlib.h> int main() { int* arr = (int*)malloc(sizeof(int) * INT_MAX); if (arr == NULL) { printf("error:%s\n", strerror(errno)); return 1; } return 0; }这里也报错输出了:内存空间不足的报错信息。
那有点人还是说,太麻烦了,那么有没有更加方便的函数呢?当然还有一个更加方便的函数。
perror 函数使用
他就是strerror 和errno 的结合体,可以不需要<string.h>和<errno.h>库函数就可以使用,没有任何限制就可以直接使用。
所以这个函数就是程序员最常用的报错代码之一了。
int main() { int* arr = (int*)malloc(sizeof(int) * INT_MAX); if (arr == NULL) { perror("error"); return 1; } return 0; }其实就等价于刚才这段代码
printf("error:%s\n", strerror(errno));注意perror 会自动多加有一个" : "(冒号)在里面。
C语言内存函数 <string.h>
memcpy 使用和模拟实现
memcpy 的介绍
memcpy 的函数其实还是与cpy 拷贝有关,类似于strncpy的功能,但是这个函数的传参第三个值的意义就有所不同了。
void * memcpy (void * destination , const void * source , size_t num );功能:
•memcpy是完成内存块拷贝的,不关注内存中存放的数据是啥
•函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。
•如果source和destination有任何的重叠,复制的结果都是未定义的。◦(内存重叠的情况使用memmove就行)
参数:
destination:指针,指向目标空间,拷贝的数据存放在这里
source:指针,指向源空间,要拷贝的数据从这里来
num:要拷贝的数据占据的字节数
返回值:
拷贝完成后,返回目标空间的起始地址
函数使用
展示1:
int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,0 }; int arr2[10] = { 0,9,8,7,6,5,4,3,2,1 }; memcpy(arr2, arr1, 24); for (int i = 0; i < 10; i++) { printf("%d ", arr2[i]); } return 0; }可看到arr2 对前面6个整形int 类型进性修改数值,而且刚好他的修改数值24,是6*4=24个字节的大小,那么其实修改数量的就是字节位置修改数值。
模拟实现
void* my_memcpy(void* str1, void const* str2, size_t size) { void* tmp = str1; assert(str1); assert(str2); while (size--) { *(char*)str1 = *(char*)str2; str1 = (char*)str1 + 1; str2 = (char*)str2 + 1; } return tmp; } int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,0 }; int arr2[10] = { 0 }; my_memcpy(arr2, arr1, 24); for (int i = 0; i < 10; i++) { printf("%d ", arr2[i]); } return 0; }memmove 使用和模拟实现
memmove 的介绍
memmove 函数其实就是strncat 的翻版,但是以为无需考虑'\0'的问题,就其实功能还是与memcpy 一致 ,他们本质区别在于memmove可以处理内存地址重叠问题,但你如果真的去使用的话两个都是可以处理这类问题,但还是记住一些memmove 可以处理重叠问题就可以。
void * memmove ( void * destination, const void * source, size_t num );函数使用
展示1:
#include <stdlib.h> int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,0 }; memmove(arr1+2, arr1, 24); for (int i = 0; i < 10; i++) { printf("%d ", arr1[i]); } return 0; }展示2:
int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,0 }; memmove(arr1, arr1+2, 24); for (int i = 0; i < 10; i++) { printf("%d ", arr1[i]); } return 0; }模拟实现
my_memmove 代码展示:
void* my_memmove(void* str1, void const* str2, size_t size) { void* tmp = str1; assert(str1); assert(str2); if (str1 < str2) { //从前往后走 while (size--) { *(char*)str1 = *(char*)str2; str1 = (char*)str1 + 1; str2 = (char*)str2 + 1; } } else if(str1 > str2) { //从后往前走 int size_my = size; while (--size) { str1 = (char*)str1 + 1; str2 = (char*)str2 + 1; } size = size_my; while (size--) { *(char*)str1 = *(char*)str2; str1 = (char*)str1 - 1; str2 = (char*)str2 - 1; } } else { return tmp; } return tmp; } int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,0 }; my_memmove(arr1+2, arr1, 24); for (int i = 0; i < 10; i++) { printf("%d ", arr1[i]); } return 0; }为什么需要花费大费周章的去搞是从前往后走还是从后往前走的情况呢?
以为如果不去细分的话就发生数据混乱的情况。
宏观模拟实现:
当str2在绿色位置的时候就是不会发生内存地址重叠的情况,该情况无论是从头往前走还是从尾后往走都不会发生冲的情况,所以str2在红色区域的时候,就是需要从后往前走的情况,而黄色区域的是需要从前往后走的情况。
从前往后走:
从后往前走:
memset 函数的使用
memset 的介绍
void * memset (void * ptr , int value , size_t num );功能:
•memset函数是用来设置内存块的内容的,将内存中指定长度的空间设置为特定的内容。
•memset的使用需要包含
参数:
ptr:指针,指向要设置的内存空间,也就是存放了要设置的内存空间的起始地址。
value:要设置的值,函数将会把value值转换成unsigned char的数据进行设置的。也就是以字节为单位来设置内存块的。
num:要设置的内存长度,单位是字节。
返回值:返回的是要设置的内存空间的起始地址。
函数使用
int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,0 }; memset(arr1, 0x12, 4); //12121212 for (int i = 0; i < 10; i++) { printf("%d ", arr1[i]); } return 0; }可以看出该函数是针对的是一个字节为的进行一个一个的修改内容,四个字节每一个字节位置都附上十六进制的0x12 ,0x12121212 的对应的十进制数量就是3 0317 4162。
memcmp 函数的使用
memcmp 的介绍
memcmp 就是cmp针对一个字节位的比较,功能还是与其他的cmp 都是一样的。
int memcmp ( const void * ptr1 , const void * ptr2 , size_t num );功能:
比较指定的两块内存块的内容,比较从ptr 1和ptr2指针指向的位置开始,向后的num个字节
memcmp的使用需要包含
参数:
ptr1:指针,指向一块待比较的内存块
ptr2:指针,指向另外一块待比较的内存块
num:指定的比较长度,单位是字节
函数使用
int main() { int arr1[10] = { 1,2,3,4,5 }; int arr2[10] = { 1,2,3,4,4 }; printf("%d", memcmp(arr1, arr2, 16)); return 0; }int main() { int arr1[10] = { 1,2,3,4,5 }; int arr2[10] = { 1,2,3,4,4 }; printf("%d", memcmp(arr1, arr2, 20)); return 0; }当然string.h 的介绍也不仅如此,做一个简单的介绍,我的介绍结束感谢观看。
悠仁さん
