在C的库函数中,有丰富的字符串操作函数,在平时的coding中灵活运用这些库函数会达到事半功倍的效果
一:str系列
char *strcpy(s, ct) | 将字符串ct(包括'\0')复制到字符串s中,并返回s,需要注意s的长度是否容纳ct。 |
char *strncpy(s, ct, n) | 将字符串ct中最多n个字符复制到字符串s中,并返回s。如果ct中少于n个字符,则用'\0'填充 如果n小于ct的长度,即复制部分ct中的字符,是没有\0的,需要手动添加 在strncpy中,长度指定了多少个字符将被写入到目标字符数组里,如果源字符串比指定指定长度更长,则字符串将不会以\0字节结尾。 |
char *strcat(s, ct) | 将字符串ct连接到s的尾部,并返回s,src和dst重叠结果未定义,并且必须保证目标字符数组剩余空间足以容纳整个源字符串 |
char *strncat(s, ct, n) | 将字符串ct中最多前n个字符连接到字符串s的尾部,并以'\0'结束;返回s strncat函数的长度参数指定从源字符串复制过来的字符的最大数目,但它的结果始终以一个\0字节结尾。 |
int *strcmp(cs, ct) | 比较字符串cs和ct;当cs<ct时,返回一个负数;当cs==ct返回0;当cs>ct返回值大于0 |
int *strncmp(cs, ct,n) | 比较字符串cs和ct中签n个字符;当cs<ct时,返回一个负数;当cs==ct返回0;当cs>ct返回值大于0 |
char *strchr(cs, c) | 返回指向字符c在字符串cs中第一次出现的位置的指针;如果cs中不包括c,则该函数返回NULL |
char *strrchr(cs, c) | 返回指向字符c在字符串cs中最后一次出现的位置的指针,如果cs中不包括c。则返回NULL |
size_t strcspn(str1, str2) | 检索字符串str1开头连续有几个字符都不含字符串str2的字符 |
size_t strlen(str) | 计算字符串str的长度,直到空结束字符,但不包含空结束字符 |
char *strpbrk(str, c) | 在str字符串中检索第一个匹配str2中字符的字符,返回该位置(不包含\0) |
size_t strspn(str1, str2) | 检索字符串str1中第一个不在字符串str2中出现的字符下标 |
char *strstr(str1, str2) | 在str1中查找第一次出现str2的位置 |
char *strtol(str, delim) | 以delim为界分割字符串 |
在上面的函数中,有些是成对的出现如strcpy和strncpy,strcmp和strncmp,两个函数从命名上看就一字之差,后者加了个n,那是因为前者在某些条件下是不安全的,我们一般称之为不安全函数,后者的出现就是为了弥补不安全函数带来的隐患,但是前者已经使用了多年,也不好在原来的基础上改,所以另起了一个函数。
我们就以strcpy和strncpy为例来看看为什么说strcpy是不安全的
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
// please write your code here
char *myName = "ftz";
char oriarr[5] = {0};
strcpy(oriarr,myName);
printf("enough space:%s\n",oriarr);
char oriarr2[2] = {0};
strcpy(oriarr2,myName);
printf("not enough space:%s\n",oriarr2);
}
结果:
可以看到,在目的字符串的空间不足的情况下,源字符串还是拷贝过去了,踩到了目的字符串后边的内存,这会产生不可预料的错误。
在strncpy中增加了一个参数n,可以由调用者自己去灵活的设置需要拷贝的字节数,另外函数的说明里也提示了调用者应该怎么做保证安全。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
// please write your code here
char *myName = "ftz";
//strncpy(s, ct, n) normal
char oriarr[5];
strncpy(oriarr,myName,4);
printf("normal:%s\n",oriarr);
//strncpy(s, ct, n) ct中少于n个字符
char oriarr2[5];
strncpy(oriarr2,myName,5);
printf("ct中少于n个字符:%s\n",oriarr2);
//strncpy(s, ct, n) n小于ct的长度 需要手动添加\0
char oriarr3[5];
strncpy(oriarr3,myName,2);
oriarr3[2] ='\0';
printf("n小于ct的长度:%s\n",oriarr3);
}
结果:
二:mem系列
void *memchr(void *str, int c, size_t n) | 在参数 str 所指向的字符串的前 n 个字节中搜索第一次出现字符 c(一个无符号字符)的位置。若未出现字符则返回NULL |
int memcmp(str1, str2, n) | 把str1和str2的前n个字节进行比较。 如果返回值 < 0,则表示 str1 小于 str2。 如果返回值 > 0,则表示 str1 大于 str2。 如果返回值 = 0,则表示 str1 等于 str2。 |
void *memcpy(dst, src, n) | 从src复制n个字节到dst,并返回dst的指针 |
void *memmove(dst, src, n) | 从src复制n个字节到dst,并返回dst的指针。重叠时也能正确复制 |
void *memset(str, c, n) | 复制字符c到参数str所指向的字符串的前n个字节 |
个人在编码中mem系列的使用频次比str系列的高,利用mem系列的函数需要特别注意的是对最后一个传参n的保护,保证我们要操作的内存是绝对安全的,只对我们的目标内存进行操作。
三:两个系列的比较
1,memchr与strchr
memchr检测的是一段内存,strchr检查的是一个字符串;
strchr会停在\0但memchr不会;
memchr的效率也会更高;
2,memcmp与strcmp
功能比较:
二者都可以用于字符串的比较,但是二者是有比较大的差异的
strcmp是按照字节(byte-wise)比较的,并且比较的过程中会检查是否出现了"\0"结束符,一旦任意一个字符串指针前进过程中遇到结束符,将终止比较;
memcmp函数是用于比较两个内存块的内容是否相等,在用于字符串比较时通常用于测试字符串是否相等,不常进行byte-wise的字符串比较;
如果要比较的对象中包含一些由于边界对齐需求而填入结构对象中的空格、联合 (union)结束的额外空格、字符串所分配的空间未使用完的部分引起的“holes”的话,最好不能使用memcmp;
效率差异:
strcmp比较的字符串,strcmp需要时刻检查是否遇到了字符串结束的 \0 字符
memcmp比较的是内存块,不需要检查是否有\0
所以memcmp的效率要高于strcmp
3,memcpy与strncpy
二者对内存重叠均没有保护,区别在于:
当拷贝的字节数小于等于src字符串长度时,二者是等价的;当拷贝的字节数大于src字符串的长度时,strncpy使用\0补齐字节数,memcpy会按照地址继续复制,会造成故障。
strncpy根据指定长度的字符串进行内容拷贝,遇到0时会终止;memcpy不终止。
4,memcpy和memmove
当内存发生局部重叠的时候,memmove保证拷贝的结果是正确的,memcpy不保证拷贝的结果的正确。
memmove与memcpy的区别(ABD)
A、内存发生局部重叠的时候,memmove保证拷贝的结果是正确的,memcpy不保证拷贝的结果的正确
B、当src内存区域和dest内存区域重叠时且dest所在区域在src所在区域前,memcpy可以正确拷贝
C、当src内存区域和dest内存区域重叠时且src所在区域在dest所在区域前,memcpy可以正确拷贝
D、对于BC,memmove都可以正确拷贝
memcpy和memmove的描述正确的是【仅考虑执行结果,不考虑规范性】C
A、源、目的地址有重叠时只能用memmove
B、源、目的地址无重叠时只能用memcpy
C、源、目的地址有重叠,且源>目的时,只能用memmove
D、源、目的地址有重叠,且源<目的时,只能用memmove