写这篇博客主要是为了疏理一下C/C++标准库自带字符串操作函数 ,为迎接9月的“细细诶夫“考试的孩子们(包括我自己咯)整理思路,在处理字符串问题时更加得心应手。
闲话少说,开始进入正体。C/C++中对字符串的操作函数有不少,集中分布在C string.h、stdlib.h,C++ string头文件中,当然不排除将其视为容器也可使用algorithm的算法(这个以后再讨论),主要涉及的字符串的复制、移动、连接、比较、搜索、到其他数值类型的相互转换、以及其他操作,接下来按功能进行分别解析各函数用法以及应用。此外,还将讨论一下其他有用的工具性函数。
C篇:
<string.h> / <cstring>
一.复制
1.(没什么卵用系列) void* memcpy(void* destination,const void* source, size_t num)
void* memmove(void* destination, const void* source, size_t num)
这两个函数属于对内存块进行操作函数,操作对象是内存,因此无视\0l字符的终止限定,从source指针指向的内存往后数num bytes,将其copy/move到destination,copy与move均不会导致destination内存的自动分配,因此需要程序员自己预先分配足够的内存,使用memcpy需要注意source与destination不能有重叠,即存在共有部分,而memmove则允许存在重叠部分,因此比memcpy更安全。
2.(有点用)char* strcpy(char* destination, const char* source)
char* strncpy(char* destination, const char* source, isize_tnum)
与上面两个mem氏函数不同,str氏的操作对象是字符数组/c风格字符串,因此会受到\0限定,这也可以从参数与返回值类型为char*而不是void*中看出,于是存在不指定num的情况和指定num的情况,指定num主要对于有特定需求(截取前num字节)进行复制操作,同样,这两个函数也不会对内存执行分配操作,因此需要程序员自己管理内存,防止溢出。
二.连接(有点用)
char* strcat(char* destination, const char* source)
char* strncat(char* destination, const char* source, size_t num)
这两个函数功能为将source的(带有n则是前num个)字符连接到destination尾部,同样需要程序员保证不会溢出,同时,通过以上我们也能知道c函数库的命名的套路:操作对象+操作,如果只对前n个字节/字符操作,需要在中间加上n,参数为目标字符数组+源字符数组+num,返回值为目标字符数组。
三.比较(有用)
int strcmp(const void* ptr1, const void* ptr2)
int strncmp(const* char* ptr1, const char* ptr2, size_t num)
这两个函数功能为将ptr字符数组与ptr2字符数组按字典顺序进行比较,ptr1 > ptr2返回1,ptr1 == ptr2返回0,ptr1 < ptr2返回-1。(n的作用同上)
四.搜索(有用)
1. char* strchr(char* str, int character)
char* strrchar(char* str, int character)
在str中搜索character字符出现的第一个/最后一个,如果搜索到,返回一个指针指向这个字符,如果不存在,返回NULL。
char* strstr(char* str1, char* str2)
在str1中搜索字串str2,如果搜索到,返回一个指针指向这个字符,如果不存在,返回NULLl。
2.size_t strspn(const char* str1, const char* str2) (特定情况有用)
size_t strcspn(const char* str1, const char* str2)
中间不带有c的函数(即strspn)功能为从str1第一个字符从前往后查找在str2中出现过的字符,直到遇到不属于str2的字符,返回之前在str2出现过的字符的个数。
中间带有c的函数(即strcspn)功能“相反”,从str1第一个字符从前往后查找未在str2中出现的字符,直到遇到属于str2的字符,返回之前在str2中未出现的字符的个数。
char* strpbrk(const char* str1, const* str2)
在str1中查找第一次出现的属于str2的字符,并返回一个指针指向这个字符,如果不存在,返回NULL。
3.char* strtok(char* str, const char* delimiters) (有用+)
字符串分割函数,这个函数使用起来相比之前略复杂,第一次调用的第一个参数是需要分割的字符串,第二个为分割的标志字符串,而以后每一次调用第一个参数需要调整为NULL,第二个参数不变,返回值为指向分割后的字串的指针,在每一次查找到后,将找到的标志赋值为NULL(\0)。回顾整个流程,相当于将字符串中的标志字符串全部用\0替代,在每一次调用时返回每个字串的首地址。
五.长度(最常用)
size_t strlen(const char* str)
返回字符串的长度,以\0作为终止符。
<stdlib.h>/<cstdlib>
一.字符串转换函数
首先说一下命名的套路:a和str都代表字符串,to代表转换,数值数据类型的前面的字母代表其他数值数据类型,如i代表int,l代表long,f代表float,
d代表double,然后是没什么多用的ul,代表usigned long,其中当后面的为f,i,l时,a代表字符串,为d,l时str代表字符串。
atox的参数为字符数组,返回值为到第一个不为数字之前的字符字串转换成为的数字,例如"12306str",将返回12306,"123 06"将返回123,而“str12306”将返回0,超出int范围将引发为定义的行为。
那么就会有人想,如果我需要获取譬如"12306str12580"这样的字符串中的每一个数值字串的值呢,strtox可以做到。strtox提供了第二个参数,char** endptr,每次调用函数后,*endptr将会指向转换后的数值的后一个字符,譬如说第一次调用strtol("12306str12580“, &endPtr, 10)后,endptr将会指向's',第二次调用后将会指向't',第三次指向'r',第四次指向最后\0,对于非小数类型,还提供了第三个参数,表示进制数,如16,则可以将"0xf"转换为15,如2,则可以将"110"转换为6。
二.算法
只有两个,快速排序函数和二分搜索函数,由于使用起来较为繁琐,一般会被STL中的sort和find函数代替。
void qsort(void* base, size_t num, size_t size, int (*comptr)(const void*, const void*) )
void* bsearch(const void* key,const void* base, size_t num, size_t size,int (*comptr)(const void*, const void* ) )
由于函数本身不知道传进去的数据类型,因此需要指定数组元素size大小,函数也不知道数组长度,需要指定数组大小,提供比较器则是指定比较的规则,注意bsearch返回的是void*,因此在使用时要注意进行显示的转换。
三.数学运算
1.绝对值
abs和labs,取绝对值,分别对应int型和long型
2.整除
div和ldiv,返回值是结构体div_t、ldiv_t,
typedef struct { typedef struct {
int quot; long quot;
int rem; long rem;
} div_t; } ldiv_t;
quot代表整除的结果,rem代表余数。
<math.h>/<cmath>
1.绝对值函数
abs与fabs,二者之间并没有什么明显的区别,主要对浮点数进行操作,返回值为float、double,与stdlib中的相混合可能会让人比较纠结,但是一个强制类型转换就可以解除选择困难症的问题,博主一般用fabs。
2.舍入
ceil,floor,round:ceil为向上取整,floor为向下取整,round返回距离参数最近的整数。
3.乘方/开方
pow,sqrt:常用函数,不多解释了。
C++篇:
<string>
终于到了c++的舞台了,被c中繁琐的函数纠缠的欲生欲死?系加加是你的福音。
首先,谈到string头文件就有必要谈谈string类本身了。
string类本身可以视为一种STL容器类,它拥有iterator,也拥有begin(),end(),push_back(),pop_back(),insert(),erase()等基本函数,因此可以某种意义上可以将string当作vector<char>来使用,algorithm中的算法也可以完美的应用在string类上。这些都是后话了,现在主要讨论string作为string所具有的独特函数:
1.构造函数:
default (1)
string(); //默认构造函数,没什么可说的
copy (2)
string (const string& str); //通过另外一个string的复制构造函数,也没有什么好说的
substring (3)
string (const string& str, size_t pos, size_t len = npos); //通过另外一个string的某一部分,某种意义上相当于取字串
from c-string (4)
string (const char* s); //通过c风格字符串,是c-string到string的途径
from sequence (5)
string (const char* s, size_t n); //通过c风格的字串创建
fill (6)
string (size_t n, char c); //用n个相同的字符创建
range (7)
template <class InputIterator> //通过迭代器创建
string (InputIterator first, InputIterator last);
2.析构函数
pass~
3.获取大小
size()方法和length()方法,并无什么区别,可能是为了与传统的length和STL的size兼容而特意弄出两个来。
4.连接
+=重载或者append()方法
5.复制
=运算符重载
6.替换
replcae()方法,前两个参数为位置 + 长度,这个格式在之前的c函数中也频繁出现,后面的参数为字符串的各种表示方法以及取字串添加的数字。
7.获取字符
[]运算符重载,或者at方法
8.查找
find()方法,参数是要查找的字符串/字符 + 查找起始位置,要查找的字符串为c-string还可以加上一个数字指明c-string的长度。
r_find()为反向查找。
*注意,这里如果没有找到返回的是string::nopos。
9.比较
compare()方法,按照字典顺序比较
10.截取字串
substr()方法,参数为起始位置+长度。
11.转化为c-string
c_str()方法。
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
写到这里博主有必要说以下,刚才发现string中其他函数全是c++11的,为了突显针对“系系诶夫”的主题,博主决定去除博客c++11的内容,以免产生误导作用,但
值得一提的是,c/c++/java等各个语言都在与时俱进,都在发展,而考试却仅仅停留在98标准,实在让人感到费解,新标准中加入了对原有标准的补充与修复,是值
的去学习的,也希望“系系诶夫”有一天能发挥预期的作用。写了两三个小时,后面的有些简略,以后有空完善,如果有错误敬请指出。
休息会去了==下个博客见。