目录
1. 字符分类函数
2、字符转换函数
3. strlen的使⽤和模拟实现
4. strcpy 的使⽤和模拟实现
5. strcat 的使⽤和模拟实现
6. strcmp 的使⽤和模拟实现
7. strncpy 函数的使⽤
8. strncat 函数的使⽤
9. strncmp函数的使⽤
10. strstr 的使⽤和模拟实现
11. strtok 函数的使⽤
12. strerror 函数的使⽤
13、atoi函数的使用和模拟
正⽂开始
在编程的过程中,我们经常要处理字符和字符串,为了⽅便操作字符和字符串,C语⾔标准库中提供了 ⼀系列库函数,接下来我们就学习⼀下这些函数。
1. 字符分类函数
C语⾔中有⼀系列的函数是专⻔做字符分类的,也就是⼀个字符是属于什么类型的字符的。 这些函数的使⽤都需要包含⼀个头⽂件是 ctype.h
首先第一个函数原型为:
int iscntrl(int c);
检查所传的字符是否是控制字符。
如果 c 是一个控制字符,则该函数返回非零值,否则返回 0。
例如:可以用以下程序判断是否为控制字符
#include<stdio.h>
#include<ctype.h>
int main()
{char c = '\a';printf("%d ", iscntrl(c));return 0;
}
第二个函数的函数原型为:
int isspace(int c);
检查所传的字符是否是空白字符。
如果 c 是一个空白字符,则该函数返回非零值(true),否则返回 0(false)。
例如:
#include<stdio.h>
#include<ctype.h>
int main()
{char c = ' ';printf("%d ", isspace(c));return 0;
}
第三个函数原型为:
int isdigit(int c);
检查所传的字符是否是十进制数字字符。
如果 c 是一个数字,则该函数返回非零值,否则返回 0。
例如:
#include<stdio.h>
#include<ctype.h>
int main()
{char c = '8';printf("%d ", isdigit(c));return 0;
}
第四个函数原型为:
int isxdigit(int c);
检查所传的字符是否是十六进制数字,十六进制一般用数字 0 到 9 和字母 A 到 F(或 a~f)表示,其中 A~F 表示 10~15: 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F。
如果 c 是一个十六进制数字,则该函数返回非零的整数值,否则返回 0。
例如:
#include<stdio.h>
#include<ctype.h>
int main()
{char c = '8';printf("%d ", isxdigit(c));return 0;
}
第五个函数原型为:
int islower(int c);
检查所传的字符是否是小写字母。
如果 c 是一个小写字母,则该函数返回非零值(true),否则返回 0(false)。
例如:
#include<stdio.h>
#include<ctype.h>
int main()
{char c = 'a';printf("%d ", islower(c));return 0;
}
第六个函数声明为:
int isupper(int c);
检查所传的字符是否是大写字母。
如果 c 是一个大写字母,则该函数返回非零值(true),否则返回 0(false)。
例如:
#include<stdio.h>
#include<ctype.h>
int main()
{char c = 'A';printf("%d ", isupper(c));return 0;
}
第七个函数原型为:
int isalpha(int c);
检查所传的字符是否是字母。
如果 c 是一个字母,则该函数返回非零值,否则返回 0。
例如:
#include<stdio.h>
#include<ctype.h>
int main()
{char c = 'A';printf("%d ", isalpha(c));return 0;
}
第八个函数原型为:
int isalnum(int c);
检查所传的字符是否是字母和数字。
如果 c 是一个数字或一个字母,则该函数返回非零值,否则返回 0。
例如:
#include<stdio.h>
#include<ctype.h>
int main()
{char c = '5';printf("%d ", isalnum(c));return 0;
}
第九个函数原型为:
int ispunct(int c);
检查所传的字符是否是标点符号字符。
如果 c 是一个标点符号字符,则该函数返回非零值(true),否则返回 0(false)。
例如:
#include<stdio.h>
#include<ctype.h>
int main()
{char c = ',';printf("%d ", ispunct(c));return 0;
}
第十个函数原型为:
int isgraph(int c);
检查所传的字符是否有图形表示法。带有图形表示法的字符是除了空白字符(比如 ' ')以外的所有可打印的字符。
如果 c 有图形表示法,则该函数返回非零值,否则返回 0。
例如:
#include<stdio.h>
#include<ctype.h>
int main()
{char c = 'k';printf("%d ", isgraph(c));return 0;
}
第十一个函数原型为:
int isprint(int c);
检查所传的字符是否是可打印的。可打印字符是非控制字符的字符。
如果 c 是一个可打印的字符,则该函数返回非零值(true),否则返回 0(false)。
例如:
#include<stdio.h>
#include<ctype.h>
int main()
{char c = 'k';printf("%d ", isprint(c));return 0;
}
上面的代码都十分简单,下面来一个题目,体会一下字符分类函数:
写⼀个代码,将字符串中的⼩写字⺟转⼤写,其他字符不变。
例如:
#include <stdio.h>
#include <ctype.h>
int main()
{int i = 0;char str[] = "Test String.\n";char c;while (str[i]){c = str[i];if (islower(c))c -= 32;putchar(c);i++;}return 0;
}
运行结果为:
2、字符转换函数
C语⾔提供了2个字符转换函数:
int tolower ( int c ); //将参数传进去的⼤写字⺟转⼩写
int toupper ( int c ); //将参数传进去的⼩写字⺟转⼤写
上⾯的代码,我们将⼩写转⼤写,是-32完成的效果,有了转换函数,就可以直接使⽤ tolower 函 数。
#include <stdio.h>
#include <ctype.h>
int main()
{int i = 0;char str[] = "Test String.\n";char c;while (str[i]){c = str[i];if (islower(c))c = toupper(c);putchar(c);i++;}return 0;
}
3. strlen的使⽤和模拟实现
函数原型为:
size_t strlen ( const char * str );
• 字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前⾯出现的字符个数(不包 含 '\0' )。
• 参数指向的字符串必须要以 '\0' 结束。
• 注意函数的返回值为size_t,是⽆符号的( 易错 )
• strlen的使⽤需要包含头⽂件 string.h
例如我们看一道程序:
#include <stdio.h>
#include <string.h>
int main()
{const char* str1 = "abcdef";const char* str2 = "bbb";if (strlen(str2) - strlen(str1) > 0){printf("str2>str1\n");}else{printf("srt1>str2\n");}return 0;
}
运行结果为:
很明显,结果与我们的预期不符,实际上这是由于strlen函数的返回值导致的,size_t的返回值是无符号的整形,两个size_t的数相减仍为一个size_t的数,所以结果会是一个正数,在这一点一定要注意,因为比较容易出错。
strlen的模拟实现:
⽅式1:
/计数器⽅式
int my_strlen(const char* str)
{int count = 0;assert(str);while (*str){count++;str++;}return count;
}
⽅式2:
//不能创建临时变量计数器
int my_strlen(const char* str)
{assert(str);if (*str == '\0')return 0;elsereturn 1 + my_strlen(str + 1);
}
⽅式3:
//指针-指针的⽅式
int my_strlen(char* str)
{assert(str);char* p = str;while (*p !='\0')p++;return p - str;
}
4. strcpy 的使⽤和模拟实现
函数原型为:
char* strcpy(char * destination, const char * source );
• 源字符串必须以 '\0' 结束。
• 会将源字符串中的 '\0' 拷⻉到⽬标空间。
• ⽬标空间必须⾜够⼤,以确保能存放源字符串。
• ⽬标空间必须可修改。
strcpy的模拟实现:
char* my_strcpy(char* dest, const char* src)
{char* ret = dest;assert(dest != NULL);assert(src != NULL);while ((*dest++ = *src++)){;}return ret;
}
5. strcat 的使⽤和模拟实现
函数原型为:
char *strcat(char *dest, const char *src)
• 源字符串必须以 '\0' 结束。
• ⽬标字符串中也得有 \0 ,否则没办法知道追加从哪⾥开始。
• ⽬标空间必须有⾜够的⼤,能容纳下源字符串的内容。
• ⽬标空间必须可修改。
• 使用strcat函数不要让字符串给自己追加,也就是strcat函数的两个参数不能相同。
模拟实现strcat函数:
char* my_strcat(char* dest, const char* src)
{char* ret = dest;assert(dest != NULL);assert(src != NULL);while (*dest){dest++;}while ((*dest++ = *src++)){;}return ret;
}
6. strcmp 的使⽤和模拟实现
函数原型为:
int strcmp(const char *str1, const char *str2)
• 标准规定:
◦ 第⼀个字符串⼤于第⼆个字符串,则返回⼤于0的数字
◦ 第⼀个字符串等于第⼆个字符串,则返回0
◦ 第⼀个字符串⼩于第⼆个字符串,则返回⼩于0的数字
⽐较两个字符串中对应位置上字符ASCII码值的⼤⼩。
strcmp函数的模拟实现:
int my_strcmp(const char* str1, const char* str2)
{int ret = 0;assert(str1 != NULL);assert(str2 != NULL);while (*str1 == *str2){if (*str1 == '\0')return 0;str1++;str2++;}return *str1 - *str2;
}
7. strncpy 函数的使⽤
函数原型为:
char * strncpy ( char * destination, const char * source, size_t num );
• 拷⻉num个字符从源字符串到⽬标空间。
• 如果源字符串的⻓度⼩于num,则拷⻉完源字符串之后,在⽬标的后边追加0,直到num个。
模拟实现:
char* my_strncpy(char* dst, const char* src, size_t n)
{int i;for (i = 0; src[i] && i < n; i++){dst[i] = src[i];}if (i < n){dst[i] = 0;}return dst;
}
8. strncat 函数的使⽤
函数原型为:
char *strncat(char *dest, const char *src, size_t n)
将source指向字符串的前num个字符追加到destination指向的字符串末尾,再追加⼀个 \0 字 符。
如果source 指向的字符串的⻓度⼩于num的时候,只会将字符串中到 \0 的内容追加到destination指向的字符串末尾。
模拟实现:
char* my_strcat(char* dst, const char* src, size_t n)
{char* tmp = dst;while (*dst){dst++;}int i;for (i = 0; src[i] && i < n; i++){dst[i] = src[i];}dst[i] = 0;return tmp;
}
例如:
#include <stdio.h>
#include <string.h>
int main()
{char str1[20];char str2[20];strcpy(str1, "To be ");strcpy(str2, "or not to be");strncat(str1, str2, 6);printf("%s\n", str1);return 0;
}
运行结果为:
9. strncmp函数的使⽤
函数原型为:
int strncmp ( const char * str1, const char * str2, size_t num );
⽐较str1和str2的前num个字符,如果相等就继续往后⽐较,最多⽐较num个字⺟,如果提前发现不⼀ 样,就提前结束,⼤的字符所在的字符串⼤于另外⼀个。如果num个字符都相等,就是相等返回0。
用法与strcmp基本一样,就是要指定比较前多少项。
10. strstr 的使⽤和模拟实现
函数原型为:
char * strstr ( const char * str1, const char * str2);
函数返回字符串str2在字符串str1中第⼀次出现的位置
字符 串的⽐较匹配不包含 \0 字符,以 \0 作为结束标志
#include <stdio.h>
#include <string.h>
int main()
{char str[] = "This is a simple string";char* pch;pch = strstr(str, "simple");strncpy(pch, "sample", 6);printf("%s\n", str);return 0;
}
运行结果为:
strstr的模拟实现:
char* strstr(const char* str1, const char* str2)
{char* cp = (char*)str1;char* s1, * s2;if (!*str2)return((char*)str1);while (*cp){s1 = cp;s2 = (char*)str2;while (*s1 && *s2 && !(*s1 - *s2))s1++, s2++;if (!*s2)return(cp);cp++;}return(NULL);
}
11. strtok 函数的使⽤
函数原型为:
char * strtok ( char * str, const char * sep);
• sep参数指向⼀个字符串,定义了⽤作分隔符的字符集合
• 第⼀个参数指定⼀个字符串,它包含了0个或者多个由sep字符串中⼀个或者多个分隔符分割的标 记。
• strtok函数找到str中的下⼀个标记,并将其⽤ \0 结尾,返回⼀个指向这个标记的指针。(注: strtok函数会改变被操作的字符串,所以在使⽤strtok函数切分的字符串⼀般都是临时拷⻉的内容 并且可修改。)
• strtok函数的第⼀个参数不为 NULL ,函数将找到str中第⼀个标记,strtok函数将保存它在字符串 中的位置。
• strtok函数的第⼀个参数为 NULL ,函数将在同⼀个字符串中被保存的位置开始,查找下⼀个标 记。
• 如果字符串中不存在更多的标记,则返回 NULL 指针。
例如:
#include <stdio.h>
#include <string.h>
int main()
{char arr[] = "192.168.6.111";char* sep = ".";char* str = NULL;for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep)){printf("%s\n", str);}return 0;
}
运行结果为:
例如:
#include<stdio.h>
#include<string.h>
int main()
{char arr[] = "wang@year,net";char copy[20];strcpy(copy, arr);char sep[] = "@,";char* ret = strtok(copy, sep);printf("%s\n", ret);ret = strtok(NULL, sep);printf("%s\n", ret);ret = strtok(NULL, sep);printf("%s\n", ret);return 0;
}
运行结果为:
12. strerror 函数的使⽤
函数原型为:
char * strerror ( int errnum );
strerror函数可以把参数部分错误码对应的错误信息的字符串地址返回来。
在不同的系统和C语⾔标准库的实现中都规定了⼀些错误码,⼀般是放在 errno.h 这个头⽂件中说明的,C语⾔程序启动的时候就会使⽤⼀个全⾯的变量errno来记录程序的当前错误码,只不过程序启动 的时候errno是0,表⽰没有错误,当我们在使⽤标准库中的函数的时候发⽣了某种错误,就会讲对应 的错误码,存放在errno中,⽽⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。
注:一次只能打印一个错误。但是错误码可能会发生变化,只要是检测出一个与之前不同的错误,错误码就会随之改变。
另外,编译器报出的是语法错误,而这个错误码对应的错误信息是程序运行时的错误。
#include <string.h>
#include <stdio.h>
//我们打印⼀下0到10这些错误码对应的错误信息
int main()
{int i = 0;for (i = 0; i <= 10; i++) {printf("%s\n", strerror(i));}return 0;
}
运行结果为:
例如:
#include <stdio.h>
#include <string.h>
int main()
{FILE* pFile;pFile = fopen("unexist.ent", "r");if (pFile == NULL)printf("Error opening file unexist.ent: %s\n", strerror(errno));return 0;
}
运行结果为:
也可以了解⼀下perror函数,perror函数相当于⼀次将上述代码中的第9⾏完成了,直接将错误信息打 印出来。
perror函数打印完参数部分的字符串后,再打印⼀个冒号和⼀个空格,再打印错误信息。这个函数需要头文件stdio.h
例如:
#include <stdio.h>
int main()
{FILE* pFile;pFile = fopen("unexist.ent", "r");if (pFile == NULL)perror("Error opening file unexist.ent");return 0;
}
运行结果为:
13、atoi函数的使用和模拟
函数原型为:
int atoi(const char *str)
把参数 str 所指向的字符串转换为一个整数(类型为 int 型)。
该函数返回转换后的长整数,如果没有执行有效的转换,则返回零。
模拟实现:
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<limits.h>
#include<ctype.h>
int my_atoi(const char* str)
{assert(str);if (*str == '\0')return 0;while (isspace(*str)){str++;}int flag = 1;if (*str == '+'){flag = 1;str++;}else if (*str == '-'){flag = -1;str++;}long long ret = 0;while (*str != '\0'){if (isdigit(*str)){ret = ret * 10 + flag * (*str - '0');if (ret > INT_MAX || ret < INT_MIN){return 0;}}else{return (int)ret;}str++;}return (int)ret;}
欢迎读者到评论区留言,或者私信。