字符串函数和内存函数
目录
1.字符串函数
1.1.字符串
1.2.strlen()
1.2.1.函数介绍
1.2.2使用时要注意的一些点
1.2.3.my_strlen()的实现
1.3.strcpy()
1.3.1.函数介绍
1.3.2使用时要注意的一些点
1.3.2.my_strcpy()的实现
1.4.strcat()
1.4.1.函数介绍
1.4.2使用时要注意的一些点
1.4.3.my_strcat()的实现
1.5.strcmp()
1.5.1.函数介绍
1.5.2使用时要注意的一些点
1.5.3.my_strcmp()的实现
1.6.strncmp()、strncpy()和strncat()
1.6.1.函数介绍
1.6.2使用时要注意的一些点
1.7.strstr()
1.7.1.函数介绍
1.7.2.my_strstr()的实现
1.8.字符分类函数
1.9.字符转换函数
2.内存函数
2.1.memcpy()
2.2.memmove()
2.3.memcmp()
2.4.memset()
1.字符串函数
此类函数的头文件为 <string.h>
1.1.字符串
在讲字符串函数前,我们先了解一下字符串,字符串是一串字符的集合,其特点是:以'\0'结尾;
这也是区分字符与字符串的关键。
字符串函数,字符串函数,意思就是对字符串进行操作的函数,为了安全起见,那么就要求参数得和字符串相关,那就得有字符串的标志:'\0'。
1.2.strlen()
1.2.1.函数介绍
unsigned int strlen(const char* str)
计算字符串有效长度的函数,只有一个参数,参数的类型是char*,指代要计算字符串的首元素地址,返回值类型是unsigned int,计算过程是从参数所指地址开始一个一个字节地向后访问,当被访问空间为 '\0' 时,就停止访问,返回 '\0' 前的字符个数。
1.2.2使用时要注意的一些点
当两个strlen()相减为负数的情况:前面我们提到了strlen()返回值的类型为 unsigned int ,两个这个类型的数进行加减运算时,计算的结果也会以%u 的形式解读,如果让两个strlen()函数相减,此时我们再判断其正负,就会得到,错误的结果,因为%u解读的数都是大于0的,不可能小于0!!!
1.2.3.my_strlen()的实现
实现的方法有三种:1.计数器法 2,指针法 3,不创建临时变量的递归法
由于计算字符串长度时,不需要进行修改,为了提高代码的健壮性,我们要在指针前加上const修饰。
1.计数器法
int My_strlen(const char* str)
{int count = 0;while (*str++){count++;}return count;
}
2.指针法
int My_strlen(const char* str)
{char* p = str;while (*str){str++;}return str - p;
}
//看到这要回忆一下 指针的运算 有哪些
3.递归实现
//这里不用创建临时变量
int My_strlen(const char* str)
{if (*str){return 1 + My_strlen(++str);}else{return 0;}
}
1.3.strcpy()
1.3.1.函数介绍
char* strcpy(char *strDestination, const char *strSource)
在目标空间内复制字符串,有俩个参数,第一个参数的类型为char*,指向复制的目标空间,第二个参数的类型是char*,指向待复制内容的空间,返回值的类型是char*,指向目标空间的首元素地址,复制过程是:依次将待复制内容的数据赋给目标空间,当指向待复制内容的指针指向'\0'时,就结束。
1.3.2使用时要注意的一些点
空间大小问题:当目标空间的大小不足以存放待复制的内容的话,会越界访问,就存在数据被非法覆盖的危机了,所以在使用strcpy()前,请确定目标空间足够大。
1.3.2.my_strcpy()的实现
char* My_strcpy(char* dest, const char* sor)
{char* p = dest;while (*dest++ = *sor++){;}return p;
}
1.4.strcat()
1.4.1.函数介绍
char* strcat(char *strDestination, const char *strSource)
在目标字符串的末尾追加字符串,有俩个参数,第一个参数的类型为char*,指向待被追加的目标空间,第二个参数的类型是char*,指向要追加内容,返回值的类型是char*,指向待被追加空间的首元素地址,追加的过程是:先访问待被追加的空间,当访问空间的内容为'\0'时停止向后访问,接着就从此位置开始,逐次将要追加的内容进行复制,复制的结束以要复制的空间内容为'\0'时停止。
1.4.2使用时要注意的一些点
在自己后面追加自己:当想使用strcat()实现在自己后头再追加自己时,就会出现一个bug,在清楚strcat()函数的执行逻辑后,在末尾进行复制追加的操作就会进入一个无尽循环,要追加内容永远不会时'\0'。
1.4.3.my_strcat()的实现
//有点像strlen()和strcpy()的结合
char* My_strcat(char* dest, const char* sor)
{char* p = dest;while (*dest){dest++;}while (*dest = *sor){dest++;sor++;}return p;
}
1.5.strcmp()
1.5.1.函数介绍
int strcmp(const char* str1, const char* str2)
str1与str2的先后顺序没有太大关系,只有当两者不同时会影响返回值的正负。
字符串比较函数,比较的不是字符串长度,而是逐个比较字符的ascii码值的大小,如果两个字符串都比较到末尾'\0'时,就会返回0,表示两个字符串相等,反之如果遇到两个不相等的字符时,就返回参数1字符串与参数2字符串的差值,差值大于0说明两个不相等字符中,前者的ascii码值更大,反之说明后者的更大,类似于按姓名拼音进行排序的大小比较。
1.5.2使用时要注意的一些点
1.5.3.my_strcmp()的实现
int My_strcmp(const char* str1, const char* str2)
{while (*str1 == *str2){if (*str1 == '\0') //这一步很关键{return 0;}str1++;str2++;}return *str1 - *str2;
}
---------------------------------------------------------------分割线---------------------------------------------------------
分割线以上的字符串操作函数都存在一个问题,就是当参数所指的“字符串”的最后如果不存在'\0',就会出现越界的风险,要是正好要操作的字符串后面是重要的数据,被函数一修改,那就麻烦了,
下面的函数在一定程度上降低了这种风险(加上了限制访问范围的n参数,统一加在最后)
1.6.strncmp()、strncpy()和strncat()
1.6.1.函数介绍
int strncmp( const char *string1, const char *string2, size_t count )
char *strncpy( char *strDest, const char *strSource, size_t count )
char *strncat( char *strDest, const char *strSource, size_t count )
就是在原来的基础上加上参数n作为函数功能结束的控制条件,不再以'\0'作为“灯塔”,而是n字节后的位置为“灯塔”,函数操作字符串的过程基本是一样的。
补:strncpy()和strncat()中,如果原字符的长度小于count时,在拷贝完原字符串后,后面默认补0,直至count个
1.6.2使用时要注意的一些点
n的单位是字节,虽然在字符串中一个元素就是一个字节,但不要就把它当成元素的个数看了。
1.7.strstr()
1.7.1.函数介绍
char* strstr(const char *string, const char *strCharSet )
在主串(string指向的字符串)中找子串(strCharSet指向的字符串)是否存在的函数,存在则返回子串的第一个字符在主串中的位置,不存在则返回NULL。
1.7.2.my_strstr()的实现
char* My_strstr(const char* str1, const char* str2)
{char* p1 = str1; //用于每次比较后的复位char* p1_c = str1; //用于做比较char* p2 = str2; //用于作比较//循环的终点是主串被遍历完
//其实可以考虑先求出两个字符串的长度,然后就可以避免一些重复的比较了
//因为当主串中剩余未遍历的字符串长度小于子串时,就没有比较的必要了
//复位操作也能优化一下,让子串尽可能地“右移”(等我学完数据结构中的串后再来修改)while (*p1){if (*p1 = *p2){while (*p1_c == *p2){p1_c++;p2++;}if (*p2 == '\0'){return p1;}p2 = str2;}p1++;p1_c = p1;}return NULL;
}
1.8.strerror()
char *strerror( int errnum )
识别错误码并返回表示错误信息的字符串,返回类型是char*,指向表示错误信息的字符串的第一个字符,参数的类型为int,需是能表示错误码的整型数。
可是要在程序运行后才能知道错误码是多少啊,我们怎么能在敲程序代码的时候就未卜先知了呢?这个时候就需要引用一个特殊的全局变量:errno,这个变量的作用是存放上次程序运行错误对应的错误码,如果程序运行过程中没有错误,则其值为默认的初始值0,而错误代码0指的是 no error,注意!在使用这个变量的时候,得引用一个库:<errno.h>。
1.9.strtok()
char* strtok(char* str, const char div)
字符串分割函数,将字符串按所给字符进行分割,返回的是遇到此次的第一个分割符处之前的字符串,分割参数div可以是单个字符,或者是分割符的字符串,字符串的每个字符都代表一个分割符。
注意:如果你上次引用strtok(),strtok()会记忆上次分割过的字符串位置,当想要获取第二段分割串时,参数1char* str,传NULL即可,当字符串不能再分割时,函数返回NULL。
1.9.字符分类函数
所需要引用的头文件为<ctype.h>
这类函数以 is 开头
函数结构:int isxxx(int x)
相当于英语中的疑问句,用于判断字符的属性:
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 任何可打印字符,包括图形字符和空白字符
上述函数的返回类型为bool类型,只有一个参数,类型为int,参数如果符合相应条件就返回ture,反之返回false。
1.10.字符转换函数
所需要引用的头文件为<ctype.h>
用来转换 字符 的大小写的功能:
int tolower ( int c );
int toupper ( int c );
如果参数合理,则返回转化后的字符对应的ascii码值。
------------------------------------------------------内存函数---------------------------------------------------------------
2.内存函数
所需引用的头文件:<string.h>
相较于字符串操作函数,内存函数在使用上显得更加顺手一点,因为其操作的对象是更加底层的内存,也就意味着它能操作任何存储在内存中的数据(只要有权限的话)
补:下列标红的文字
1.void*
注意函数返回值为void*时,虽然void*可以转化成任意类型的指针,但也不能直接用带类型的指针去接收,而是应该把返回值强制类型转化一下再赋给对应类型的指针。
2.size_t num
这里的单位时字节,不是指元素的个数!!!
2.1.memcpy()
void * memcpy ( void * destination, const void * source, size_t num )
从低地址到高地址,将source指向内存块的后size_t个字节空间的数据,拷贝到destination指向的内存块中,类似strncpy()。
这样的拷贝方式存在一个缺陷,试分析以下代码输出的结果:
int main()
{char string[10] = "memcpy";memcpy(string+2, string, 4);printf("%s\n", string);return 0;
}
这是因为destination指向的内存空间与source指向的内存空间发生了重叠,在顺序拷贝的过程中,也将source指向的内存空间进行了修改,但是你不先备份一份数据,在不申请额外空间的条件下,想将自身的某个部分拷贝到自身,这种现象是不可避免的吧?
其实是有解决办法的,下面的函数memmove()就是不申请额外空间,但是完成了这个要求。
2.2.memmove()
void * memmove ( void * destination, const void * source, size_t num )
与memcpy()所不同的是,memmove()函数不是一贯以从左向右进行拷贝的,而是先判断dest指向空间的地址与source指向空间的地址的先后顺序,如果dest指向的空间的地址低于source指向的地址,就从左向右进行拷贝,反之则从右向左进行拷贝。
规则巧记:
如果记不住这个规则,我这里做个比喻,将拷贝的动作想象成向目标地埋雷,埋雷者不能经过自己埋过雷的地方,否则就会有危险,当要埋雷的区域与埋雷者活动的区域重叠时,埋雷者应从自己活动范围的两端中选则在重叠部分的一端开始埋雷,这样就不会踩到自己埋的雷了。
2.3.memcmp()
int memcmp ( const void * ptr1, const void * ptr2, size_t num )
同strncmp()
2.4.memset()
void * memset ( void * ptr, int value, size_t num )
内存设置函数,在ptr指向地址后num个字节的空间中,将每一字节空间的数据设置为value。
字符串函数和内存函数相关推荐
- C语言—字符串函数和内存函数
文章目录 1.前言 2.字符串函数 2.1 长度不受限制的字符串函数 2.1.1 strlen 内部细节 使用方法 模拟实现 2.1.2 strcmp 内部细节 使用方法 模拟实现 2.1.3 str ...
- C语言常见字符串函数、字符分类函数与内存函数的使用
前言 C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在 常量字符串 中或者 字符数组 中.下面介绍C语言中的一些常用的字符串函数和内存函数的功能以及实现原理. 字 ...
- 字符串函数以及内存函数概述
本人能力有限,难免有叙述错误或者不详细之处!希望读者在阅读时可以反馈一下错误以及不够好的地方!感激不尽! 目录 求字符串长度: strlen 长度不受限制的字符串函数: strcpy,strcat,s ...
- c语言字体移动函数,C语言字符函数、内存函数功能及实现代码
C语言字符函数.内存函数 功能及实现 strlen函数(求字符串长度)注意点模拟实现 strcpy函数(字符串拷贝函数)注意点模拟实现 strcat函数(字符串衔接函数)注意点模拟实现 strcmp函 ...
- 字符函数和内存函数模拟实现
字符函数和内存函数模拟实现 字符函数和内存函数模拟实现 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<str ...
- C语言函数:内存函数memmove()以及实现与使用。
C语言函数:内存函数memmove()以及实现与使用. memmove(): 头文件:#include <string.h> 函数参数: 可以发现memmove()函数的 ...
- 【C语言笔记进阶篇】第二章:字符串函数和内存函数
目录 (1)分类 (2)字符串函数 A:strlen(求字符串长度) B:strcpy(字符串复制_不受限制) C:strcat(字符串追加_不受限制) D:strcmp(字符串比较_不受限制) E: ...
- 字符函数、字符串函数、内存函数用法及其模拟实现
目录 1.strlen strlen的模拟实现 2.strcpy strcpy模拟实现 3.strcat - 字符串追加 模拟实现strcat 4.strcmp - 比较字符串 模拟实现stcmp 5 ...
- C语言字符串函数,内存函数讲解及其模拟
在这篇博客会讲解以下函数:strlen,strcpy,strcat,strcmp,strncpy,strncat,strncmp,strstr,strtok,memcpy,memmove,memset ...
最新文章
- JetBrains 宣布:IntelliJ 平台彻底停用 Log4j 组件,建议切换至 java.util.logging
- grunt.config()_gruntjs api
- LeetCode 340. Longest Substring with At Most K Distinct Characters
- HIve学习:Hive分区修改
- Sql Server 监控 Job 执行情况
- VMware Workstation 12新建虚拟机
- SO_REUSEADDR SO_REUSEPORT 解析
- Python中的一些特殊函数
- 微软推出新逆天开源语言,告别 for 循环,提高开发效率!
- 汉诺塔问题(递归思想)(堆栈学习)
- 公司这套架构统一处理try...catch这么香,求求你不要再满屏写了,再发现扣绩效!...
- curl: symbol lookup error: curl: undefined symbol: curl_mime_free
- mac上有哪些好用的图表软件?
- 解决 Intel Extreme Tuning Utility(XtuService)的日志占用过大(直接删Logs或卸载)
- 10款在线检查英语语法的网站
- 数据总线、地址总线、控制总线
- android 好用的工具,8款好玩实用APP推荐(安卓)
- c语言 日期加减天数返回日期 闰年,日期计算器(多图)
- 用go编写区块链系列之7--网络
- 《数据通信与网络》笔记--广域网SONET/SDH