头文件ctype.h
字符分类函数
| 函数名 | 返回真的条件 | 考试核心备注 |
|---|---|---|
iscntrl |
任意控制字符(ASCII 0~31、127) | 不可打印,比如退格、响铃 |
isspace |
空白字符:空格 、换页\f、换行\n、回车\r、水平制表\t、垂直制表\v |
常用来分割字符串,区分普通空格 |
isdigit |
十进制数字:'0' ~ '9' |
只识别阿拉伯数字字符 |
isxdigit |
十六进制字符:0~9,a~f,A~F | 包含十进制数字 + abcdef 大小写 |
islower |
小写英文字母:a ~ z |
|
isupper |
大写英文字母:A ~ Z |
|
isalpha |
英文字母:a~z 或 A~Z | 纯字母,不含数字 |
isalnum |
字母 或者 数字(`isalpha | |
ispunct |
可打印标点符号(不属于字母、数字的图形字符) | ! " # $ % & ' () * + , - . /等 |
isgraph |
任意可见图形字符(除空白以外的可打印字符) | 字母、数字、标点都算,不含空格 |
isprint |
全部可打印字符:图形字符 + 空格 |
范围最大,包含空格 |
方便记忆:

将小写字符转化为大写字符
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <ctype.h>
int main(){
char arr[] = { "I am a student." };
int i = 0;
while (arr[i] != '\0') {
if (islower(arr[i])) {
arr[i] -= 32;
}
i++;
}
printf("%s\n", arr);
return 0;
}
字符转换函数tolower、toupper
示例
cpp
char ch = toupper('a');
printf("%c\n",ch);
将小写字符转化为大写字符
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <ctype.h>
int main(){
char arr[] = { "I am a student." };
int i = 0;
while (arr[i] != '\0') {
if (islower(arr[i])) {
arr[i] = isupper(arr[i]);
}
i++;
}
printf("%s\n", arr);
return 0;
}
strlen(求字符串长度)
头文件string.h
示例
cpp
char arr[] = "abcdef";
size_t len = strlen(arr);
printf("%zd\n",len);
功能具体实现
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main(){
if (strlen("abc") - strlen("abcdef") > 0) {
printf(">");
}
else {
printf("<=");
}
return 0;
}
结果是>,因为size_t是无符号整型
要让结果是<=
换成方法1.strlen("abc") > strlen("abcdef")
或2.在strlen前加上(int)强制类型转换
strlen模拟实现
1.计数器方式
2.指针-指针
3.递归方式
1.计数器方式
要模拟实现strlen,创建一个计数器,在遍历字符串的过程中,每遇到一个非'\0'的字符,就让计数器+1
cpp
size_t my_strlen(const char* str) {
int count = 0;//创建一个计数器
assert(str != NULL);//确保传入的不是空指针
//遍历字符串
while (*str != '\0') {
count++;//遇到有效字符,计数器+1
str++;//移动到下一个字符
}
return count;
}
2.指针-指针
通过记录字符串的起始位置和结束位置,最后用两个指针相减得到长度
cpp
size_t my_strlen(const char* str) {
const char* strat = str;
assert(str != NULL);
while (*str != '\0') {
str++;
}
return str - strat;
}
3.递归方式
计算一个字符串的长度,可以看作是1+剩余子串的长度
cpp
size_t my_strlen(const char* str) {
if (*str != '0') {
return 1 + my_strlen(str + 1);
}
else {
return 0;
}
}
长度不受限制的字符串函数
strcpy(复制字符串到字符串数组中)
char* strcpy(char* destination,const char* source)
函数使用
cppchar arr1[ ] = "abcdef"; char arr2[20]; strcpy(arr2,arr1);包括\0也会拷贝
拷贝到的目标空间必须足够大
strcpy的模拟实现
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <assert.h>
char* my_strcpy(char* dest, const char* src) {
assert(dest && src);
char* ret = dest;
while (*src != '\0') {
*dest = *src;
src++;
dest++;
}
*dest = *src;//处理\0
return ret;
}
int main(){
char arr1[] = "abcdef";
char arr2[20];
printf("%s\n", my_strcpy(arr2, arr1));
return 0;
}
dest不加const,而src加const限制
是因为dest指向的空间要修改,src指向的空间不要被修改
优化
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <assert.h>
char* my_strcpy(char* dest, const char* src) {
assert(dest && src);
char* ret = dest;
while (*dest++ = *src++) {
;
}
return ret;
}
int main(){
char arr1[] = "abcdef";
char arr2[20];
printf("%s\n", my_strcpy(arr2, arr1));
return 0;
}
*dest++ = *src++
将arr2中的字符拷贝过去后,再判断表达式的值
最后当拷贝完\0后,才会判断为假,停止循环
strcat(拼接字符串)
使用
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main(){
char arr1[20] = "hello";
char arr2[] = "world";
strcat(arr1, arr2);
printf("%s\n",arr1);
return 0;
}
字符串不能自己给自己追加
strcat的模拟实现
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <assert.h>
char* my_strcat(char* dest,const char* src) {
char* ret = dest;
assert(dest && src);
//要存入arr1中,dest首先得找到\0
while (*dest != '\0') {
dest++;
}
//拷贝arr2到arr1里,将 arr1里的\0也覆盖掉
while (*dest++ = *src++) {
;
}
//要返回目标空间的起始地址
return ret;
}
int main(){
char arr1[20] = "hello ";
char arr2[] = "world";
my_strcat(arr1, arr2);
printf("%s\n",arr1);
return 0;
}
strcmp(比较对应位置上的字符大小)
使用
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main(){
char arr1[20] = "abcdef ";
char arr2[] = "abcdh";
int ret = strcmp(arr1, arr2);
printf("%d\n",ret);
return 0;
}
VS上的返回值只有-1、0、1
标准的是<=、=、>=
strcmp模拟实现
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <assert.h>
int my_strcmp(const char* str1, const char* str2) {
while (*str1 == *str2) {
if (*str1 == '\0') {
return 0;
}
str1++;
str2++;
}
if (*str1 > *str2) {
return 1;
}
else {
return -1;
}
//也可以把这里的if语句换成return(*str1-*str2)
}
int main(){
char arr1[20] = "abcdef ";
char arr2[] = "abcdh";
int ret = my_strcmp(arr1, arr2);
printf("%d\n",ret);
return 0;
}
长度受限制的字符串函数
strncpy函数
char* strncpy(char * dest,const char* src,size_t num)
比strcpy多了第三个参数,意思是最大拷贝的字符数
使用
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main(){
char arr1[20] = "abcdef";
char arr2[20] = "xxxxxxxx";
strncpy(arr2, arr1, 3);
printf("%s\n",arr2);
return 0;
}
strncpy(arr2, arr1, 8);
如果要拷贝的数量大于字符串长度,比如这里,将arr1拷贝8个字符到arr2里面,但arr1中只有6个字符,剩下两位会补\0
如果拷贝的数量小于字符串长度,那就是复制几个就是几个,不补\0
strncat函数
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main(){
char arr1[20] = "abcdef";
char arr2[20] = "xxxx";
strncat(arr2, arr1, 3);
printf("%s\n",arr2);
return 0;
}
追加几个然后自动补\0
字符串可以自己给自己追加
strncmp函数
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main() {
char arr1[20] = "abcdef";
char arr2[20] = "abqwqq";
int ret = strncmp(arr1, arr2, 3);
printf("%d\n", ret);
return 0;
}
结果为-1
strstr的使用(长串中找短串)
在str1中找str2这个字符串,第一次出现的位置
如果找到了,就返回这个第一次出现的起始地址,打印出来的值就是从这个地址开始往后的字符串
如果找不到,就返回NULL
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main() {
char arr[] = "abcdefabcdef";
const char* p = "efab";
char* ret = strstr(arr, p);
if (ret == NULL) {
printf("不存在\n");
}
else {
printf("%s\n", ret);
}
return 0;
}
strstr的模拟实现

思路:
strstr函数功能实现在长串中匹配短串,匹配成功就返回该次匹配的起始地址
起始地址cur
s1从cur位置出发,s2从str2位置出发,只要遇到字符相同,就同时++
3.判断结果
(1)字符相同就让s1和s2继续++,如果s2到了\0说明找完了,就返回当前的cur值
(2)字符不同,让cur++
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <assert.h>
char* my_strstr(const char* str1, const char* str2) {
assert(str1 && str2);
const char* s1 = NULL; //这个地址必须要受限制
const char* s2 = NULL;
const char* cur = str1;
if (*str2 == '\0') { //特殊情况,c语言规定要这样返回
return (char*)str1;
}
while (*cur != '\0') {
s1 = cur;
s2 = str2;
while ( *s1 != '\0'&& *s2 != '\0'&& * s1 == *s2) {
s1++;
s2++;
}
if (*s2 == '\0') {
return (char*)cur;
}
cur++;
}
return NULL;
}
int main() {
char arr[] = "abcdefabcdef";
const char* p = "efab";
char* ret = my_strstr(arr, p);
if (ret == NULL) {
printf("不存在\n");
}
else {
printf("%s\n", ret);
}
return 0;
}
还有更优的算法,KMP算法
strtok函数(按指定的分隔符拆分字符串)
192.168.110.123
ip地址,这是点分十进制的表示方式
这里的.点是分隔符
这里的@是分隔符
char* strtok(char* str,const char* sep)第一个参数是整个字符串
sep放分隔符
此函数每次调用完之后,会保存上次找到的位置
//两个数组,一个放含有分隔符的字符串,一个放分隔符char arr = "aaaamelia@qq.com";
char sep ="@.";
//如果不想破坏原始字符串,就在分割前先用 strcpy 拷贝一份副本到另一个数组中
char buf 256 = {0};
strcpy(buf,arr);
//要切割buf字符串,用strtok函数
char* ret = strtok ( buf , sep ) ;//首次调用:传入需要被分割的字符串指针
printf ( " %s\n ", ret ) ;
//strtok会将分隔符改变为\0
//后续调用:传入 NULL 就可以,函数会继续从上次断开的地方分割
//传NULL是因为strtok函数每次调用完之后,都会保存上次找到的位置
ret = strtok ( NULL , sep ) ;
printf ( "%s\n ", ret ) ;
正因为strtok函数每次调用完会保存上次找到的位置,
所以实际上写的时候利用循环调用strtok函数
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main() {
char arr[] = "aaaamelia@qq.com";
char buf[256] = { 0 };
strcpy(buf, arr);
const char* sep = "@.";
char* ret = NULL;
for(ret=strtok(buf,sep);ret!=NULL;ret = strtok(NULL,sep))
{
printf("%s\n", ret);
}
return 0;
}
strerror函数(错误码转文字)
char* strerror ( int errnum );
错误码里有对应的错误信息,strerror就会把这个错误信息的起始地址返回来
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main() {
for (int i = 0; i <= 10; i++) {
printf("%d:%s\n", i,strerror(i));
}
return 0;
}
结果:

strerror模拟实现
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main() {
FILE* pf = fopen("data.txt", "r");//打开文件,以读文件的形式,如果文件不存在就打开失败
if (pf == NULL) {
printf("打开文件失败,原因是:%s", strerror(errno));
return 1;
}
else {
printf("打开文件成功\n");
fclose(pf);
pf = NULL;
}
return 0;
}

在文件对应位置手动新建data.txt
记得打开文件扩展名

用prror函数
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main() {
FILE* pf = fopen("data.txt", "r");//打开文件,以读文件的形式,如果文件不存在就打开失败
if (pf == NULL) {
//printf("打开文件失败,原因是:%s", strerror(errno));
perror("打开文件失败,原因是");
return 1;
}
else {
printf("打开文件成功\n");
fclose(pf);
pf = NULL;
}
return 0;
}
strerror :将错误码对应的错误信息的字符串的起始地址返回
perror :将errno中错误码对应的错误信息打印出来
perror函数先打印str指向的字符串打印,再打印一个空格,再打印错误码对应的错误信息perror是printf和strerror函数一起的功能
