目录
一、字符函数
(一)字符分类函数
(二)字符转换函数
二、字符串函数
(一)strlen、strcpy、strcat、strcmp的使用和模拟实现
1、strlen
(1)使用
(2)模拟实现
2、strcpy
(1)使用
(2)模拟实现
3、strcat
(1)使用
(2)模拟实现
4、strcmp
(1)使用
(2)模拟实现
(二)strncpy、strncat、strncmp的使用
1、strncpy的使用
2、strncat的使用
3、strncmp的使用
(三)strstr的使用和模拟实现、strtok、strerror的使用
1、strstr
(1)使用
(2)模拟实现
2、strtok函数的使用
3、strerror函数的使用
三、内存函数
(一)memcpy、memmove的使用和模拟实现
1、memcpy
(1)使用
(2)模拟实现
2、memmove
(1)使用
(2)模拟实现
(二)memset、memcmp的使用
1、memset的使用
2、memcmp的使用
一、字符函数
在编程的过程中,经常要处理字符和字符串,为了方便操作字符和字符串,C语言标准库中提供了一系列库函数
(一)字符分类函数
C语⾔中有一系列的函数是专门做字符分类的,也就是一个字符是属于什么类型的字符的;
这些函数的使用都需要包含一个头文件: ctype.h
这些函数的使用方法非常类似,说明一个即可:
int islower ( int c );
islower 的参数是整型,因为可以传入字符或者字符的ASCII码值,两者本质一样
islower 是能够判断参数部分的 c 是否是小写字母;
通过返回值来说明是否是小写字母,如果是小写字母就返回非0的整数,如果不是小写字母,则返回 0;
练习:写一个代码,将字符串中的小写字母转大写,其他字符不变
#include<stdio.h> #include<string.h> #include<ctype.h> int main() { char arr[] = "I like eat pizza!"; int len = strlen(arr); for (int i = 0; i < len; i++) { if (islower(arr[i])) arr[i] -= 32; putchar(arr[i]); } return 0; }
小写字母转为大写字母:小写字母的ASCII码值 - 32是大写字母的ascii码值
(二)字符转换函数
C语言提供了2个字符转换函数:
int tolower ( int c ); //将参数传进去的⼤写字⺟转⼩写
int toupper ( int c ); //将参数传进去的⼩写字⺟转⼤写
上面的练习代码中,将小写转大写,是-32完成的;有了转换函数,就可以直接使用 tolower 函数;可以将上面的练习改为:
#include<stdio.h>
#include<string.h>
#include<ctype.h>
int main()
{
char arr[] = "I like eat pizza!";
int len = strlen(arr);
for (int i = 0; i < len; i++)
{
if (islower(arr[i]))
arr[i] = toupper(arr[i]);
putchar(arr[i]);
}
return 0;
}
二、字符串函数
(一)strlen、strcpy、strcat、strcmp的使用和模拟实现
1、strlen
(1)使用
size_t strlen ( const char * str );
注意:
① 字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包 含 '\0' )
② 参数指向的字符串必须要以 '\0' 结束
③ 注意函数的返回值为 size_t,是无符号的( 易错 )
④ strlen的使用需要包含头文件 string.h
(2)模拟实现
strlen模拟实现有三种方法:
方法一:计数器
#include<stdio.h> #include<string.h> #include<assert.h> size_t my_strlen(const char* arr) { assert(arr); size_t count = 0; while (*arr) { count++; arr++; } return count; } int main() { char arr[] = "abcdef"; size_t re = my_strlen(arr); printf("字符串长度为:%zd", re); return 0; }
方法二:指针相减
#include<stdio.h> #include<string.h> #include<assert.h> size_t my_strlen(const char* arr) { assert(arr); char* p = arr; while (*arr) arr++; return (size_t)(arr - p); } int main() { char arr[] = "abcdef"; size_t re = my_strlen(arr); printf("字符串长度为:%zd", re); return 0; }
方法三:递推(不创建临时变量)
#include<stdio.h> #include<string.h> #include<assert.h> size_t my_strlen(const char* arr) { assert(arr); if (*arr == '\0') return 0; else return 1 + my_strlen(arr+1); } int main() { char arr[] = "abcdef"; size_t re = my_strlen(arr); printf("字符串长度为:%zd", re); return 0; }
2、strcpy
(1)使用
char* strcpy(char * destination, const char * source );
① 源字符串必须以 '\0' 结束;
② 会将源字符串中的 '\0' 拷贝到目标空间;
③ ⽬标空间必须足够大,以确保能存放源字符串;
④ ⽬标空间必须可修改;
注意:
① strcpy 复制原字符串包涵\0,字符拷贝使用不了;
② 为了实现链式访问(返回值可以用起来),strcpy的返回值是指针类型,返回的是目标空间的其实地址
(2)模拟实现
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* sour)
{
assert(dest && sour);
char* re = dest;
while (*dest++ = *sour++);
return re;
}
int main()
{
char source[] = "abcdef";
char dest[20] = { 0 };
char* re = my_strcpy(dest, source);
printf("目标字符为:%s", re);
return 0;
}
3、strcat
(1)使用
① 源字符串必须以 '\0' 结束,否则不知道追加到什么时候;
② 目标字符串中也得有 \0 ,否则没办法知道追加从哪里开始;
③ 目标空间必须有足够的大,能容纳下源字符串的内容;
④ 目标空间必须可修改;
⑤ 自己给自己追加,不保证合法
注意:
① 数字字符 '0' 的ascii码值为48;
② 终止字符 '\0' 的ascii码值为0,\0→\ddd,d表示1~3个8进制的数字,\0表示八进制的0,十进制也是0,ascii码值为0;而NULL,也表示0,空指针也可以赋0;
(2)模拟实现
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcat(char* dest, const char* sour)
{
assert(dest && sour);
char* p = dest;
while (*dest)
dest++;
while ((*dest++ = *sour++));
return p;
}
int main()
{
char source[] = "abcdef";
char dest[50] = "I like eat pizza ";
char* re = my_strcat(dest, source);
printf("目标字符为:%s\n", re);
return 0;
}
4、strcmp
(1)使用
标准规定:
第⼀个字符串大于第⼆个字符串,则返回大于0的数字;
第⼀个字符串等于第⼆个字符串,则返回0;
第⼀个字符串小于第⼆个字符串,则返回小于于0的数字
注意:
strcmp比较的是对应字符的大小,而不是长度
(2)模拟实现
#include<stdio.h>
#include<string.h>
#include<assert.h>
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;
}
int main()
{
char str1[] = "abcdef";
char str2[] = "abcpiz";
int re = my_strcmp(str1, str2);
if(re == 0)
printf("字符串相等");
else if (re > 0)
printf("str1大于str2");
else
printf("str1小于str2");
return 0;
}
(二)strncpy、strncat、strncmp的使用
1、strncpy的使用
char * strncpy ( char * destination, const char * source, size_t num );
① 拷贝 num 个字符从源字符串到目标空间;
② 若源头字符数超过限定的拷贝字数,拷贝完毕后不会自动补 '\0',除非源头包涵 '\0';
③ 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加 '\0',直到num个为止
2、strncat的使用
char * strncat ( char * destination, const char * source, size_t num );
① 将source指向字符串的前num个字符追加到destination指向的字符串末尾,再追加⼀个 '\0' 字符;
② 如果source指向的字符串的长度小于num的时候,只会将字符串中到 '\0' 的内容追加到destination指向的字符串末尾
使用例:
#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;
}
结果如下:
3、strncmp的使用
int strncmp ( const char * str1, const char * str2, size_t num );
比较str1和str2的前num个字符,如果相等就继续往后比较,最多比较num个字⺟,如果提前发现不一样,就提前结束,如果num个字符都相等,就是相等返回0
(三)strstr的使用和模拟实现、strtok、strerror的使用
1、strstr
(1)使用
char * strstr ( const char * str1, const char * str2);
① 函数返回字符串str2在字符串str1中第一次出现的位置;
② 字符串的比较匹配不包含 '\0' 字符,以 '\0' 作为结束标志
(2)模拟实现
#include<assert.h>
#include<stdio.h>
const char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
const char* s1 = NULL;
const char* s2 = NULL;
const char* check = str1;
if (*str2 == '\0')
return str1;
while (*check)
{
s1 = check;
s2 = str2;
while (*s1 && *s2 && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
return check;
check++;
}
return NULL;
}
int main()
{
char str[] = "This is a simple string";
char str1[] = "simple";
const char* re = my_strstr(str, str1);
if (re == NULL)
printf("不存在");
else
printf("%s", re);
return 0;
}
2、strtok函数的使用
char * strtok ( char * str, const char * sep);
① sep参数指向一个字符串,定义了用作分隔符的字符集合;
② 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记;
③ strtok函数找到str中的下一个标记,并将其用 '\0' 结尾,返回一个指向这个标记的指针;(注: strtok函数会改变被操作的字符串,所以被strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
④ strtok函数的第⼀个参数若不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置;strtok函数的第一个参数若为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记;
⑤ 如果字符串中不存在更多的标记,则返回 NULL 指针
取出被分隔符隔开的所有字符串:
#include<string.h> #include<stdio.h> int main() { char arr[] = "i.like#eat@pizza"; char sep[] = ".#@"; for (char* re = strtok(arr, sep); re != NULL; re = strtok(NULL, sep)) printf("%s ", re); printf("\n"); return 0; }
结果如下:
3、strerror函数的使用
char* strerror ( int errnum );
作用:将错误码对应的错误信息的字符串起始地址返回
在不同的系统和C语言标准库的实现中都规定了一些错误码,一般是放在 'errno.h' 这个头文件中说明的,C语言程序启动的时候就会使用一个全局的变量 errno 来记录程序的当前错误码,只不过程序启动的时候errno是0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会将对应的错误码,存放在 errno 中,而一个错误码的数字是整数,很难理解是什么意思,所以每⼀个错误码都是有对应的错误信息。strerror函数就可以将错误对应的错误信息字符串的地址返回。
打印部分错误码:
#include<string.h>
#include<stdio.h>
#include <errno.h>
int main()
{
int i = 0;
for (i = 0; i <= 10; i++) {
printf("%s\n", strerror(i));
}
return 0;
}
运行结果如下:
注意:
perror —— 将errorno中对应的错误信息直接打印出来,p是printf打印的意思;
void perror( const char* str )
先打印str指向的字符串,然后打印一个冒号和空格,再打印错误码对应的错误信息;
perror == printf + strerror, 如下:
printf("文件打开失败,原因是:%s", strerror(errorno));
perror("文件打开失败,原因是");
两者输出结果一样。
三、内存函数
内存函数:针对内存块来处理的(内存块:一块内存;面包块:一块面包);
mem - memory - 记忆、内存
(一)memcpy、memmove的使用和模拟实现
1、memcpy
(1)使用
void * memcpy ( void * destination, const void * source, size_t num );
① 函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置
② 这个函数在遇到 '\0' 的时候并不会停下来
③ 如果source和destination有任何的重叠,复制的结果都是未定义的。
④ 返回的是目标空间的起始地址;
⑤ 参数:目标空间的地址,原空间的地址,被拷贝的字节数
(2)模拟实现
#include<assert.h>
#include<string.h>
#include<stdio.h>
void* my_memcpy(void* p1, void* p2, size_t mun)
{
assert(p1 && p2);
void* p = p1;
while (mun--)
{
*(char*)p = *(char*)p2;
p = (char*)p + 1;
p2 = (char*)p2 + 1;
}
return p1;
}
int main()
{
int arr1[] = {1,2,3,4,5,6,7,8,9};
int arr2[20] = { 0 };
int* p = my_memcpy(arr2, arr1, 13);
for (int i = 0; i < 4; i++)
{
printf("%d ", *(p + i));
}
return 0;
}
2、memmove
(1)使用
void * memmove ( void * destination, const void * source, size_t num );
① 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的
② 如果源空间和⽬标空间出现重叠,就得使⽤memmove函数处理
(2)模拟实现
#include<assert.h>
#include<string.h>
#include<stdio.h>
void* my_memmove(void* dest, void* sour, size_t mun)
{
assert(dest && sour);
void* p = dest;
if (dest < sour)
{
while (mun--)
{
*(char*)dest = *(char*)sour;
dest = (char*)dest + 1;
sour = (char*)sour + 1;
}
}
else
{
while (mun--)
{
*((char*)dest + mun) = *((char*)sour + mun);
}
}
return p;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
my_memmove(arr+2, arr, 16);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
(二)memset、memcmp的使用
1、memset的使用
void * memset ( void * ptr, int value, size_t num );
memset是用来设置内存的,将内存中的值以字节为单位设置成想要的内容,使用例子如下:
#include<string.h>
#include<stdio.h>
int main()
{
char str[] = "hello world";
memset(str, 'x', 6);
printf(str);
return 0;
}
运行结果如下:
2、memcmp的使用
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
① 比较从ptr1和ptr2指针指向的位置开始,向后的num个字节;
② 返回值如下:
以上内容仅供分享,若有错误请多指正