- 前言
- 一.字符串函数
- 1.strlen
- 1.1分析
- 1.2模拟实现strlen
- 2.strcpy
- 2.1分析
- 2.2模拟实现strcpy
- 3.strcat
- 3.1分析
- 3.2模拟实现strcat
- 4.strcmp
- 4.1分析
- 4.2模拟实现strcmp
- 5.strncpy
- 5.1分析
- 5.2模拟实现strncpy
- 6.strncat
- 6.1分析
- 6.2模拟实现strncat
- 7.strncmp
- 7.1分析
- 7.2模拟实现strncmp
- 8.strstr
- 8.1分析
- 8.2模拟实现strstr
- 9.strtok
- 9.1分析
- 9.2使用实例
- 10.strerror
- 10.1分析
- 10.2使用实例
- 二.字符操作函数
- 1.字符分类函数
- 2.字符转换函数
- 三.内存操作函数
- 1.memcpy
- 1.1分析
- 1.2模拟实现memcpy
- 2.memmove
- 2.1分析
- 2.2模拟实现memmove
- 3.memcmp
- 3.1分析
- 3.2模拟实现memcmp
- 4.memset
- 4.1分析
- 4.2模拟实现memset
- 结语
C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中。字符串常量适用于那些对它不做修改的字符串函数。
一.字符串函数 1.strlen 1.1分析功能:求字符串长度
参数:str——所求字符串的地址
size_t strlen(const char* str)
返回值:字符串的长度
注意事项:
1.字符串已经 ' ’作为结束标志,strlen函数返回的是在字符串中 ' ’前面出现的字符个数(不包含 ‘ ’)
2.参数指向的字符串必须要以 ' ’结束
3.注意函数的返回值为size_t,是无符号(unsigned int)的( 易错 )
例如:
注:strlen(str2) - strlen(str1)恒大于0,因为strlen返回值是无符号整形
1.2模拟实现strlen#include2.strcpy 2.1分析#include //循环(计数器方式) size_t my_strlen1(const char* str) { assert(str); int count = 0; while(*str!=' ') { str++; count++; } return count; } //指针-指针 size_t my_strlen2(const char* str) { assert(str); char* left = str; while(*str) { str++; } char* right = str; return left - right; } //递归(不能创建临时变量) size_t my_strlen3(const char* str) { assert(str); if(*str==' ') return 0; else return 1 + my_strlen3(str + 1); } int main() { char arr[] = "abcdef"; size_t len = my_strlen1(arr); printf("%un",len); return 0; }
功能:字符串拷贝
参数:
dest(destination)——目标字符数组的地址
src(source)——源字符串的的地址
size_t strcpy(char* dest, const char* src)
返回值:目标字符数组(目标空间)的地址(dest)
注意事项:
1.源字符串必须以 ' ’结束
2.会将源字符串中的 ' ’拷贝到目标空间(如下图)
3.目标空间必须足够大,以确保能存放源字符串
4.目标空间必须可变(不一定)
2.2模拟实现strcpy#include3.strcat 3.1分析#include char* my_strcpy(char* dest, const char* src) { assert(dest&&src); char* ret = dest; while(*dest++ = *src++) { ; } // while(*dest++ = *src++);while的循环体是; return ret; } int main() { char arr1[]="abcdef"; char arr2[20]={ 0 }; char* ret = my_strcpy(arr2, arr1); printf("%sn",ret); return 0; }
功能:字符串追加
参数:
dest(destination)——目标字符数组的地址
src(source)——源字符串的的地址
char* strcat(char* dest, const char* src)
返回值:目标字符数组(目标空间)的地址(dest)
注意事项:
1.源字符串必须以 ' ’结束
2.目标空间必须有足够的大,能容纳下源字符串的内容
3.目标空间必须可修改
4.会将源字符串中的’ ’追加到目标空间中
5.字符串能自己给自己追加,会将字符串中的’ ’覆盖掉,结果是未知的,可能会出现死循环等问题!
3.2模拟实现strcat#include4.strcmp 4.1分析#include char* my_strcat(char* dest, const char* src) { assert(dest!=NULL); assert(src!=NULL); char* ret = dest; //找到目标空间的末尾 while(*dest != ' ') { dest++; } //覆盖' ',将原数组的元素赋给目标空间 while(*dest++=*src++) { ; } return ret; } int main() { char arr1[20]="abcde"; char arr2[]="fghij"; my_strcat(arr1, arr2); printf("%sn",arr1); return 0; }
功能:字符串比较
参数:str1,str2——要比较的两个字符串(数组)的地址
char* strcmp(const char* str1, const char* str2)
返回值:
注意事项:
1.比较两个字符串是否相等,例如arr1,arr2, 不可以arr1==arr2直接比较,arr1,arr2是数组名,数组名是数组首元素的的地址,地址无法比较,需要使用strcmp函数比较
2.两个字符串比较,先是俩个字符串的首个字符进行大小的比较,如果相同,再向后进行下一对的比较,和两个字符串的长度无关
4.2模拟实现strcmp#include5.strncpy 5.1分析#include int my_strcmp(const char* str1, const char* str2) { { assert(str1 != NULL); assert(str2 != NULL); if(*str1==*str2 && *str2 == ' ') return 0; str1++; str2++; } if(*str1 > *str2) return 1; else return -1; //return (*str1 - *str2); } int main() { char arr1[20]="abcde"; char arr2[20]="abc"; int ret = my_strcmp(arr1, arr2); if (ret > 0) { printf(">n"); } else if (ret < 0) { printf(" printf("=="); } return 0; }
功能:字符串拷贝,长度受限制
参数:
dest(destination)——目标字符数组的地址
src(source)——源字符串的的地址
num——拷贝字符串的个数
char* strncpy(char* dest, const char* src, size_t num)
返回值:目标字符数组(目标空间)的地址(dest)
注意事项:
1.和strcpy不同的是,可以限制拷贝字符串的个数,拷贝num个字符从源字符串到目标空间
2.如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加’ ’,直到num个’ ’
5.2模拟实现strncpy#include6.strncat 6.1分析#include char* my_strncpy(char* dest, const char* src, size_t num) { assert(dest&&src); char* ret = dest; while(num && (*dest++ = *src++)!=' ') { num--; } if(num) { while(num--) { *dest++=' '; } } return ret; } int main() { char arr1[]="abcdef"; char arr2[]="bit"; char* ret = my_strcpy(arr2, arr1, 5); printf("%sn",ret); return 0; }
功能:字符串追加,有长度限制
参数:
dest(destination)——目标字符串(数组)的地址
src(source)——源字符串的地址
num——追加字符串的个数
char* strncat(char* dest, const char* src, size_t num);
返回值:目标字符串(数组)的地址(dest)
注意事项:
1.追加到目标空间的字符串结尾会添加 ’ '用来结尾
2.如果源字符串的长度小于num,追加到 ’ ’ 便会停止追加
3.不可以自己给自己追加(可能会造成死循环)
6.2模拟实现strncat#include7.strncmp 7.1分析#include char* my_strncat(char* dest, const char* src, size_t num) { assert(dest&&src); char* ret = dest; while(*dest!=' ') { dest++; } while(num--) { while((dest++=*src++)==' ') { return ret; } *dest=' '; } return ret; } int main() { char arr1[20]="abcdef"; char arr2[]="ghi"; my_strncat(arr1, arr2, 5); printf("%sn",arr1); return 0; }
功能:字符串比较,限制长度
参数:
src1,src2——要比较的两个字符串
num——比较的两个字符串(数组)的地址
int strncmp(const char* str1, const char* str2)
返回值:
- 第一个子字符串大于第二个子字符串,则返回大于0的数字
- 第一个子字符串等于第二个子字符串,则返回0
- 第一个子字符串小于第二个子字符串,则返回小于0的数字
注意事项:
比较到出现字符串中两个字符不同或者num个字符全部比较完毕
7.2模拟实现strncmp#include#include int my_strncmp(const char* str1, const char* str2, size_t num) { assert(str1&&str2); while(num--) { if(*str1==*str2&&*str1!=' ') { *str1++; *str2++; } else { return (*str1-*str2); } } } int main() { arr1[] = "abcdef"; arr2[] = "abcdg"; int ret = my_strncmp(arr1, arr2, 5); if(ret>0) { printf(">n"); } else if(ret==0) { printf("==n"); } else { printf(" 8.strstr 8.1分析 功能:查找子字符串
参数:
src1——被查找的字符串的地址
str2——要查找的字符串的地址
char* strstr(const char* str1, const char* str2)返回值:存在返回子字符串所在的地址,不存在则返回空指针
注意事项:
8.2模拟实现strstr#include9.strtok 9.1分析#include char* my_strstr(const char* str1, const char* str2) { assert(str1&&str2); const char* s1 = str1; const char* s2 = str2; const char* s1 = p; while(*p) { s1 = p; s2 = str2; while(*s1==*s2&&s1!=' '&&s2!=' ') { s1++; s2++; } if(*s2==' ') { return p; } p++; } return NULL; } int main() { char email[] = "wei@nulixuexi.com"; char substr[] = "nulixuexi"; char* ret = my_strstr(email,substr); if(ret == NULL) { printf("字串不存在n"); } else { printf("%sn",ret); } return 0; } 功能:切割字符串
参数:
str——被字符串的地址
sep——分隔符(标记)所组成字符串的地址
char* strtok(char* str, const char* sep)返回值:找到分割符,返回指向这个分隔符开头的地址;没找到返回空指针
注意事项:
1.sep参数是个字符串,定义了用作分隔符的字符集合
2.第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记
3.strtok函数找到str中的下一个标记,并将其用 结尾,返回一个指向这个标记的指针
(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改)
4.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置
5.strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记
6.如果字符串中不存在更多的标记,则返回 NULL 指针
7.查找时碰到字符串结尾 ,此时这个 也会也会被当成一个标记, 之后调用函数返回值都为空指针
9.2使用实例 10.strerror 10.1分析功能:返回错误码所对应的错误信息
参数:
errnum——库函数执行失败时,所设置的错误码
返回值: 返回系统中errno错误码所对应的描述错误文本(字符串)的地址
注意实现:
1.使用strerror必须包含的头文件#include
2.errno - C语言设置的一个全局的错误码存放的变量
10.2使用实例 二.字符操作函数 1.字符分类函数2.字符转换函数
函数 如果它的参数符合下列条件就返回真 iscntrl 任何控制字符 isspace 空白字符:空格‘ ’,换页‘f’,换行’n’,回车‘r’,制表符’t’或者垂直制表符’v’ isdigit 十进制数字 0~9 isxdigit 十六进制数字,包括所有十进制数字,小写字母af,大写字母AF islower 小写字母a~z isupper 大写字母A~Z isalpha 字母az或AZ isalnum 字母或者数字,az,AZ,0~9 ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印) isgraph 任何图形字符 isprint 任何可打印字符,包括图形字符和空白字符 int tolower (int c);//将大写字母转换为小写字母 int toupper (int c);//将小写字母转换为大写字母#include#include int main () { int i=0; char str[]="Test String.n"; char c; while (str[i]) { c=str[i]; if (isupper(c)) c=tolower(c); putchar (c); i++; } return 0; } 运行结果:test string.
三.内存操作函数 1.memcpy 1.1分析memcpy - 内存拷贝 memory - 记忆 - 内存 copy- 拷贝
功能:把一块独立的空间中的数据拷贝到另一块独立的空间
参数:
dest(destination)——目标数据内存空间的地址
src(source)——源数据内存空间的地址
num——拷贝数据的字节数
void* memcpy(void* dest, const void* src, size_t num );返回值:目标数据内存空间的地址(src)
注意事项:
1.函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置
2.这个函数在遇到’ ’的时候并不会停下来
3.如果source和destination有任何的重叠,复制的结果都是未定义的
1.2模拟实现memcpy#include2.memmove 2.1分析#include void* my_memcpy(void* dest, const void* src, size_t num ) { assert(dest&&src); void* ret = dest; while(num--) { *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } return ret; } int main() { int arr1[] = {1,2,3,4,5,6,7,8,9,10}; int arr2[] = {0}; my_memcpy(arr2, arr1, 28); int i = 0; for(i = 0; i < 7; i++) { printf("%d ",arr2[i]); } return 0; } 功能:把一块独立的空间中的数据拷贝到另一块独立的空间,允许源空间和目标空间出现重叠
参数:
dest(destination)——目标数据内存空间的地址
src(source)——源数据内存空间的地址
num——拷贝数据的字节数
void* memmove( void* dest, const void* src, size_t num );返回值:目标数据内存空间的地址(src)
注意事项:
1.和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的
2.如果源空间和目标空间出现重叠,就得使用memmove函数处理
2.2模拟实现memmove我们模拟实现时要注意,当源空间和目标空间出现重叠时,要考虑数据的拷贝方法,是从前向后拷贝还是从后向前拷贝,正确处理数据,才能得到正确的拷贝结果。有三种情况:
1.当dest
2.当dest>src且dest在src的空间范围内,数据要从后往前处理
3.当dest>src且dest不在src的空间范围内,数据从后往前处理或从前往后处理都可以
综上所诉,可以总结:
当dest
当dest>src时,数据要从后往前进行处理
#include3.memcmp 3.1分析#include void* my_mommove(void* dest, const void* src, int num) { assert(dest&&src); void* ret = dest; if(dest //前——>后 while(num--) { *(char*)dest = *(char*)src; dest = (char*)dest+1; src = (char*)src+1; } return dest; } else { //后——>前 while(num--) { *((char*)dest+num) = *((char*)src+num); } } } int main() { int arr1[] = {1,2,3,4,5,6,7,8,9,10}; my_memmove(arr1+2, arr1, 5); int i = 0; for(i = 0; i < 10; i++) { printf("%d ",arr1[i]); } return 0; } memcmp - memory compare 内存比较
功能:比较两个内存块
参数:
ptr1,ptr2——指向两个内存空间的指针
num——需要比较的字节数
int memcmp(const void* ptr1, const void* ptr2, size_t num)返回值:
注意事项:
1.与strcmp不同,该函数在遇到’ ’后,不会停止比较。
2.该函数是以字节为单位进行比较的。
使用实例:
3.2模拟实现memcmp#include4.memset 4.1分析#include int my_memcmp(const void* ptr1, const void* ptr2, size_t num) { assert(ptr1&&ptr2); while(num--) { if(*(char*)ptr1==*(char*)ptr2) { ptr1 = (char*)ptr1+1; ptr2 = (char*)ptr2+1; } else { return *(char*)ptr1 - *(char*)ptr2; } } } int main() { int arr1[] = {1,2,3,4,5}; int arr2[] = {1,3,2}; int ret = my_memcmp(arr1, arr2, 12); printf("%dn",ret); return 0; } memset - memory set 内存设置
功能:填充内存块
参数:
ptr——指向要填充的内存块的指针
value——要填充的值,该值作为 int 传递,但该函数使用此值的无符号 char* 转换来填充内存块
num——要填充为该值的字节数
void* memset(void* ptr, int value, size_t num)返回值:被填充的内存块的地址(ptr)
注意事项:可用于修改内存,value的类型为int, 但是使用时会转化为char*,例如97会转化为a
4.2模拟实现memset#include结语#include void* my_memset(void* ptr, int value, size_t num) { assert(ptr); void* ret = ptr; while(num--) { *(char*)ptr = (char*)value; ptr = (char*)ptr+1; } return ret; } int main() { int arr[] = "abcdef"; my_memset(arr,'x', 5); printf("%sn",arr); return 0; } 码字不易,跪求三连!!!



