目录
前言
一、处理字符和字符串的库函数的使用和注意事项
1. 求字符串长度
strlen
2. 长度不受限制的字符串函数(一定要找到 '\0')
strcpy:字符串拷贝
strcat:字符串追加
strcmp:比较字符串
长度受限制的字符串函数介绍
strncat
strncmp
字符串查找
strstr
strtok
错误信息报告
strerror
字符操作
字符分类函数
字符转换
内存操作函数
memcpy
memmove
memset -- 内存设置
memcmp
第一篇博客。
查找 \0 之前有多少个字符,返回类型为 size_t = unsigned int
源字符串必须以 '\0' 结束
会将源字符串中的 '\0' 拷贝到目标空间
目标空间必须足够大,以确保能存放源字符串
目标空间必须可变
// char* strcpy(char* destination, const char* source);
// 自己模拟的库函数
char* my_strcpy(char* dest, const char* src)
{
assert(dest != NULL);
assert(src);// 需引入#include
char* ret = dest;// 将目的空间的地址起始存入 ret
// 拷贝src指向的字符串到dest指向的空间,包含 '\0'
while (*dest++ = *src++)// 当拷贝到src = '\0'时,表达式判断为 0
{
;
}
// 返回目的空间的起始地址
return ret;
}
源字符串必须以 '\0' 结束
目标空间需要足够大,能容纳下源字符串的内容
目标空间必须可修改
// char* strcat(char* destination, const char* source);
char* my_strcat(char* dest, const char* src)
{
char* ret = dest; // 将目的空间的地址起始存入 ret
assert(dest != NULL);
assert(src);
// 1.找到目的字符串的 '\0'
while (*dest != '\0')
{
dest++;
}
// 2.追加
while (*dest++ = *src++)
{
;
}
return ret;
}
第一个字符串大于第二个字符串,返回大于0的数字
第一个字符串等于第二个字符串,返回等于0的数字
第一个字符串小于第二个字符串,返回小于0的数字
// char* strcmp(const char* str1, const char* str2);
// 模拟实现库函数
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0') {// 相等的情况下
return 0;
}
str1++;
str2++;
}
return (*str1 - *str2);
}
strncpy
代码如下(示例):
char* strncpy(char* destination, const char* source, size_t num);
从源字符串拷贝num个字节替换到目标空间
如果源字符串长度小于 num,则在拷贝完之后,在目标的后面追加0,直到num的长度
代码如下(示例):
char* strncat(char* destination, const char* source, size_t num);
代码如下(示例):
char* strncat(const char* str1, const char* str2, size_t num);
拓展知识:
代码如下(示例):
const char * strstr ( const char * str1, const char * str2 );
// 模拟实现库函数
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
char* p1 = NULL;// 如果不赋值空指针的话,p1就是一个野指针
char* p2 = NULL;
char* cur = str1;// 开始时的指针位置
if (*str2 == '\0') {
return (char*)str1;// 若str2是一个空字符,则直接返回str1
}
while (*cur)// 当我的str1指到 '\0'的时候停止
{
p1 = cur;// 我的p1每一次大的比较的时候都需要改变初始位置,找到str2的时候,
// 将这个时候cur的指针位置返回出去 ------ str1(abbbc) str2(abbc)
p2 = str2;
while ((*p1 != '\0') && (*p2 != '\0') && (*p1 == *p2))//
{
p1++;
p2++;
}
if (*p2 == '\0')
{
return cur;// 找到字串
}
if (*p1 == '\0')
{
return cur;// p2比p1要长
}
cur++;
}
return NULL;// 找不到字串
}
代码如下(示例):
char* strtok(char* str, const char* sep);
// 函数的使用方法
int main()
{
char arr[] = "[email protected]";
char* p = "@.";
char buff[1024] = { 0 };
strcpy(buff, arr);// 拷贝一份可修改的数据
// 切割buff中的字符串
for (char* ret = strtok(buff,p); ret != NULL; ret = strtok(NULL, p))
{
printf("%s\n", ret);
}
return 0;
}
代码如下(示例):
char* strerror(int errnum);
返回错误码所对应的错误信息
#include
int main()
{
// 错误码 -- 错误信息
// 0 -- No error
// 1 -- Operation not permitted
// 2 -- No such file or directory
// 404/500 -- Unknown error
// ....
// errno是一个全局的错误码变量
// 当C语言的库函数在执行过程中,发生了错误,就会把对应的错误码,赋值到errno中
char* str = strerror(errno);
printf("%s\n", str);
// 模拟错误
// 打开文件fopen
FILE* pf = fopen("test.txt", "r"); // 打开并读取这个文件
if (pf == NULL) {
printf("%s\n", strerror(errno));// 使用errno需引入#include
}
else {
printf("open file success\n");
}
return 0;
}
下列所有函数均有 ctype.h 提供,需引入#include
,返回值均为 int (非0为真,0为假)
函数 | 如果它的参数符合下列条件就返回真 |
---|---|
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 | 字母或者数字 |
ispunct | 标点符号,任何不属于数字或者字母的图形符号(可打印) |
isgraph | 任何图形字符 |
isprint | 任何可打印字符,包括图形字符和空白字符 |
代码如下(示例):
#include
int main()
{
char ch = 'Q';
int ret = isupper(ch);// 判断ch是否为大写,非0为真
printf("%d", ret);
return 0;
}
代码如下(示例):
#include
#include
int main()
{
char ch = tolower('Q');// 大写转小写
putchar(ch);// 输出字符
char ch2 = tolower('t');// 小写转大写
putchar(ch2);// 输出字符
return 0;
char arr[] = "I Am A Student";
int i = 0;
while (arr[i])
{
// 将所有大写字母转换为小写字母
if (isupper) {
arr[i] = tolower(arr[i]);
}
i++;
}
printf("%s\n",arr);
}
代码如下(示例):
void * memcpy ( void * destination, const void * source, size_t num );
memcpy的使用
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 0 };
memcpy(arr2, arr1, sizeof(arr1));
return 0;
}
模拟实现memcpy
// C语言标准规定:
// memcpy 只要能处理不重叠的内存拷贝的情况就够了
// memmove 处理重叠内存的拷贝
void* my_memcpy(void* dest, void* src, size_t num)
{
assert(dest);
assert(src);
void* ret = dest;// 为了防止dest中的数据指针位置变动
while (num--)
{
*(char*)dest = *(char*)src;// 因为void*是无属性类型不能进行解引用和加减操作,
// 所以分别将dest和src先强制转换为char*类型,再进行解引用操作
++(char*)dest;// 先进行强制转换操作,再进行前置++
++(char*)src;
}
return ret;
}
使用方法和参数与memcpy一样
代码如下(示例):
void * memmove ( void * destination, const void * source, size_t num );
模拟实现memmove
void* my_memmove(void* dest, void* src, size_t num)
{
void* ret = dest;// 为了防止dest中的数据指针位置变动
assert(dest && src);
// 从前向后拷贝的判断有两种
// 1.dest(char*)src + num,这种情况dest就越过了我们要拷贝的src的所有字节,也就不存在内存会不会重叠的问题了。
if (dest < src) {
while (num--)
{
*(char*)dest = *(char*)src;
++(char*)dest;// 先进行强制转换操作,再进行前置++
++(char*)src;
}
}
else {// 从后向前拷贝
while (num--)
{
// (若num=20则现在num=19,src+19正好找到第二十个字节)
// 找到src中的最后一个字节赋值给dest的最后一个字节
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
ptr是要设置内存地址
value是你要设置的字符
num的单位是字节
代码如下(示例):
void * memset ( void * ptr, int value, size_t num );
int main ()
{
char str[] = "almost every programmer should know memset!";
memset (str,'-',6);
puts (str);// ------ every programmer should know memset!
return 0;
}
代码如下(示例):
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
若ptr1的前num个字节小于ptr2的前num个字节,返回一个小于0的整数
若ptr1的前num个字节等于ptr2的前num个字节,返回一个等于0的整数
若ptr1的前num个字节大于ptr2的前num个字节,返回一个大于0的整数
int main()
{
int arr1[] = { 1,3,3,4,5,6,7,8,9,10 };
int arr2[] = { 1,2,3,5,7,6,8,2,5,6 };
int ret = memcmp(arr1, arr2, 8);
printf("%d", ret);
return 0;
}