目录
前言
在C语言中,字符串是没有类型的,通常我们将字符串放在字符数组当中,同时,我们对于字符串的操作是很频繁的,因为对于字符串的操作频繁,所以C语言本身提供了一些对字符串进行处理的库函数。如下:
函数 | 作用 |
strlen | 求字符串长度 |
strcpy | 复制字符串 |
strcat | 横向连接字符串 |
strcmp | 比较两个字符串的大小,返回比较的结果 |
strncpy | 复制字符串 |
strncat | 字符串的结尾追加n个字符 |
strncmp | 比较两个字符串的大小 |
strstr | 搜索一个字符串在另一个字符串中的第一次出现。找到所搜索的字符串,则该函数返回第一次匹配的字符串的地址; 如果未找到所搜索的字符串,则返回NULL。 |
strtok | 将字符串分割成一个个片段 |
strerror | 将错误码给转化成错误信息 |
memcpy | 内存拷贝 |
memmove | 拷贝一定长度的内存的内容 |
memset | 在一段内存块中填充某个给定的值 |
memcmp | 比较两个内存块 |
一、字符串函数
1. 1 strlen
size_t strlen (const char* str);
该函数要注意的细节点如下:
1)字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包
含 '\0' );
2)参数的字符串必须要以“ \0 ”结束,不能没有“ \0 ”;
3)注意函数的返回值是 size_t ,是无符号的。
size_t 实际就是无符号整型,虽然没有确切的证明,但是根据推测,size_t 就是对 unsigned int 的重命名而已,并不是一种新的数据类型。
函数实现:
/*模拟实现strlen*/ size_t my_strlen(const char* ch) { assert(ch); size_t count = 0; while (*ch++) { count++; } return count; }
2. 长度不受限制的字符串函数(操作的是整个字符串)
2.1 strcpy
char* strcpy (char* destination, const char* source);
该函数要注意的细节点如下:
1)源字符串必须以 '\0' 结束;
2)该函数会将源字符串中的“ \0 ”一同拷贝到目标空间,如果目标字符串原先就有内容,就会被拷贝的内容覆盖掉,包括“ \0 ”也是;
3)目标空间必须足够大,以确保能存放源字符串,如果放不下就会造成数组越界访问,为非法访问空间;
4)目标空间必须可变,不能是常量字符串。
函数实现:
/*模拟实现strcpy*/ #include<assert.h> char* my_strcpy(char* dest, const char* src) { char* p = dest; assert(src != NULL); assert(dest != NULL); while(*dest++ = *src++) { ; } return p; }
2.2 strcat
char* strcat (char* destination, const char* source);
该函数要注意的细节点如下:
1)源字符串必须以 '\0' 结束;
2)目标空间必须有足够的大,能容纳下源字符串的内容;
3)目标空间必须可修改。
函数实现:
/*模拟实现strcat*/ #include<assert.h> char* my_strcat(char* des, const char* src) { char* p = des; assert(des && src); while (*des++) { ; } des--; while (*des++ = *src++) { ; } return p; }
2.3 strcmp
int strcmp ( const char * str1, const char * str2 );
该函数要注意的细节点如下:
1)第一个字符串大于第二个字符串,则返回大于0的数字;
2)第一个字符串等于第二个字符串,则返回0;
3)第一个字符串小于第二个字符串,则返回小于0的数字。
ps:在 VS 环境中,第一种情况返回的是 1 ,第二种情况同样返回 0 ,第三种情况返回 -1 。
函数实现:
int my_strcmp(const char* str1, const char* str2) { assert(str1 && str2); while (*str1++ == *str2++) { if (*str2 == '\0') { return 0; } } str1--; str2--; return *str1 - *str2; }
3. 长度受限制的字符串函数
ps:上面的三个函数操作的都是整个字符串,而接下来的三个函数就像是它们的衍生版本,可以操作整个字符串,也可以操作字符串的部分内容。
3.1 strncpy
char* strncpy (char* destination, const char* source, size_t num);
需要注意的细节点有:
1)如果源字符串的长度小于 num ,则拷贝完源字符串之后,在目标的后边追加 0 ,直到 num 个;
2)拷贝 num 个字符就只会拷贝 num 个字符,不会再往后补上一个"\0 "。
3.2 strncat
char* strcat (char* destination, const char* source, size_t num);
需要注意的细节点有:
同样地,这个函数与 strcat 在使用上也只有新增一个参数来确认需要追加字符串中的多少个字符的区别而已,这个函数使用起来就比 strncpy 省心多了,因为这个函数会在追加之后再追加一个 “ \0 ”。
3.3 strncmp
char* strncmp (const char* str1, const char* str2, size_t num);
这个函数使用方法与 strcmp 相比也只有最后一个参数的区别,不多加说明。
4. 字符串查找
4.1 strstr
char* strstr (const char* str1, const char* str2);
这是一个可以判断一个字符串是否是另一个字符串的子串的函数。如果 str2 是 str1 的子串,即返回 str2 在 str1 中首次出现的位置的地址。这个函数使用起来很简单方便,并且也没有太多需要注意的细节,只需正常使用即可。
函数实现:
char* my_strstr(const char* ch1, const char* ch2) { assert(ch1 && ch2); const char* cp1 = ch1; const char* cp2 = ch2; const char* p = ch1; while (*p) { cp2 = ch2; cp1 = p; while (*cp1!='\0'&&*cp2!='\0'&& * cp1 == *cp2) { cp1++; cp2++; } if (*ch2 == '\0') { return (char*)p; } p++; } return NULL; }
4.2 strtok
char* strtok (char* str, const char* sep);
strtok,是一个特殊的函数,它可以将字符串分割,按照我们给出的分隔符分隔,我们进行第一次传参的时候,把字符串传过去,然后开始找分隔符,找到分隔符用'\0'代替,当要进行第二次分割的的时候,传参传空指针即可,当传参传空指针的时候,我们的strtok函数会找到上一次标记的地址,然后向后进行切割,如果在我们的字符串中,没有我们的分隔符,就会返回一个空指针。
5.错误信息报告
5.1strerror
char * strerror ( int errnum );
strerror是一个用来报告错误的函数,它可以将错误码转换成错误信息,其中我们的错误码会保存在一个叫做errno的函数中,它需要引头文件<errno.h>。
二、字符函数
字符分类函数:
函数 | 如果他的参数符合下列条件就返回真 |
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 | 任何可打印字符,包括图形字符和空白字符 |
字符转换:
大写 -> 小写:tolower
int tolower (int c);
小写 -> 大写:toupper
int toupper (int c);
三、内存操作函数
1. memcpy
void* memcpy (void* destination, const void* source, size_t num);
需要注意的细节点有:
1)函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置;
2)这个函数在遇到 '\0' 的时候并不会停下来;
3)如果source和destination有任何的重叠,复制的结果都是未定义的。
函数实现:
void* my_memcpy(void* dest, const void* src, size_t num) { void* p = dest; assert(dest && src); while (num--) { *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } return p; }
2. memmove
void* memmove (void* destination, const void* source, size_t num);
需要注意的细节点有:
1)和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的;
2)如果源空间和目标空间出现重叠,就得使用memmove函数处理。
函数实现:
void* my_memmove(void* dest, const void* src, size_t num) { void* p = dest; assert(dest && src); while (num--) { *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } return p; }
3. memcmp
int memcmp (const void* ptr1, const void* ptr2, size_t num);
需要注意的细节点有:
1)比较从ptr1和ptr2指针开始的num个字节;
2)返回值如下:(用到了msdn这个软件)
编辑
总结
上述的这些都是我们经常会在平时的代码中使用到的,熟练掌握起来为我们提供很大的帮助。当然,除此之外,C语言的库函数中还有许多有趣的有关字符和字符串的函数,如果你有兴趣想要了解,可以在下面的网站或软件找到它们,里面都有对每一个函数详细的各个部分的说明、作用的解析和示例,博主就不一一赘述了。链接如下:
cplusplus : cplusplus.com - The C++ Resources Network
cpprefrernce: cppreference.com
如果前俩个网址加载太慢也可以安装 MSDN 这个软件,这个软件也十分简洁方便,也可自行切换中文。
链接:https://pan.baidu.com/s/114FzIxhZWLUwFKSc01W3Rw?pwd=lsgb
提取码:lsgb