目录

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。

字符串函数和内存函数相关推荐

  1. C语言—字符串函数和内存函数

    文章目录 1.前言 2.字符串函数 2.1 长度不受限制的字符串函数 2.1.1 strlen 内部细节 使用方法 模拟实现 2.1.2 strcmp 内部细节 使用方法 模拟实现 2.1.3 str ...

  2. C语言常见字符串函数、字符分类函数与内存函数的使用

    前言 C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在 常量字符串 中或者 字符数组 中.下面介绍C语言中的一些常用的字符串函数和内存函数的功能以及实现原理. 字 ...

  3. 字符串函数以及内存函数概述

    本人能力有限,难免有叙述错误或者不详细之处!希望读者在阅读时可以反馈一下错误以及不够好的地方!感激不尽! 目录 求字符串长度: strlen 长度不受限制的字符串函数: strcpy,strcat,s ...

  4. c语言字体移动函数,C语言字符函数、内存函数功能及实现代码

    C语言字符函数.内存函数 功能及实现 strlen函数(求字符串长度)注意点模拟实现 strcpy函数(字符串拷贝函数)注意点模拟实现 strcat函数(字符串衔接函数)注意点模拟实现 strcmp函 ...

  5. 字符函数和内存函数模拟实现

    字符函数和内存函数模拟实现 字符函数和内存函数模拟实现 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<str ...

  6. C语言函数:内存函数memmove()以及实现与使用。

    C语言函数:内存函数memmove()以及实现与使用. memmove(): 头文件:#include <string.h> 函数参数:          可以发现memmove()函数的 ...

  7. 【C语言笔记进阶篇】第二章:字符串函数和内存函数

    目录 (1)分类 (2)字符串函数 A:strlen(求字符串长度) B:strcpy(字符串复制_不受限制) C:strcat(字符串追加_不受限制) D:strcmp(字符串比较_不受限制) E: ...

  8. 字符函数、字符串函数、内存函数用法及其模拟实现

    目录 1.strlen strlen的模拟实现 2.strcpy strcpy模拟实现 3.strcat - 字符串追加 模拟实现strcat 4.strcmp - 比较字符串 模拟实现stcmp 5 ...

  9. C语言字符串函数,内存函数讲解及其模拟

    在这篇博客会讲解以下函数:strlen,strcpy,strcat,strcmp,strncpy,strncat,strncmp,strstr,strtok,memcpy,memmove,memset ...

最新文章

  1. JetBrains 宣布:IntelliJ 平台彻底停用 Log4j 组件,建议切换至 java.util.logging
  2. grunt.config()_gruntjs api
  3. LeetCode 340. Longest Substring with At Most K Distinct Characters
  4. HIve学习:Hive分区修改
  5. Sql Server 监控 Job 执行情况
  6. VMware Workstation 12新建虚拟机
  7. SO_REUSEADDR SO_REUSEPORT 解析
  8. Python中的一些特殊函数
  9. 微软推出新逆天开源语言,告别 for 循环,提高开发效率!
  10. 汉诺塔问题(递归思想)(堆栈学习)
  11. 公司这套架构统一处理try...catch这么香,求求你不要再满屏写了,再发现扣绩效!...
  12. curl: symbol lookup error: curl: undefined symbol: curl_mime_free
  13. mac上有哪些好用的图表软件?
  14. 解决 Intel Extreme Tuning Utility(XtuService)的日志占用过大(直接删Logs或卸载)
  15. 10款在线检查英语语法的网站
  16. 数据总线、地址总线、控制总线
  17. android 好用的工具,8款好玩实用APP推荐(安卓)
  18. c语言 日期加减天数返回日期 闰年,日期计算器(多图)
  19. 用go编写区块链系列之7--网络
  20. 《数据通信与网络》笔记--广域网SONET/SDH

热门文章

  1. 硬件基础知识---电阻的用法
  2. Sublime Text 3安装,使用技巧及快捷键笔记
  3. 基于容器的AI系统开发——百度PaddlePaddle解析
  4. 【ArchSummit】众安金融微服务架构演进实战
  5. 网络开发套接字以及UDP、TCP协议
  6. JS 之 (三)作用域链、闭包、面向对象
  7. #今日说码栏目# 第二十三集 动画,旅行的热气球
  8. Unity Prefab导入检查
  9. unbound prefix
  10. 操作系统diy-1-资料整理