文章目录

  • 函数介绍
    • 一:求字符串长度
      • 1:strlen
        • (1):strlen的用法
        • (2):用函数的方法来实现strlen
    • 二:长度不受限制的字符串函数
      • 1:strcpy
        • (1):strcpy的用法
        • (2):用函数的方法来实现strcpy
      • 2:strcat
        • (1):strcat的用法
        • (2):用函数的方法来实现strcat
      • 3:strcmp
        • (1):strcmp的用法
        • (2):用函数的方法来实现strcmp
    • 三:长度受限制的字符串函数介绍
      • 1:strncpy
        • (1):strncpy的使用
        • (2):用函数的办法来实现strncpy
      • 2:strncat
        • (1):strncat的使用
        • (2):用函数的办法来实现strncat
      • 3:strncmp
        • (1):strncmp的使用
        • (2):用函数的办法来实现strncmp
    • 四:字符串查找
      • 1:strstr
        • (1):strstr的使用
        • (2):用函数的办法来实现strstr
      • 2:strtok
        • (1):strtok的使用
    • 五:错误信息报告
      • 1:strerror
        • (1):strerror的使用
    • 六:字符分类与字符转换函数
      • 1:字符分类函数
      • 2:字符转换函数
    • 七:内存操作函数
      • 1:memcpy
        • (1):memcpy的使用
        • (2):用函数的办法来实现memcpy
      • 2:memmove
        • (1):memmove的使用
        • (2):用函数的办法来实现memmove
      • 3:memset
        • (1):memset的使用
        • (2):用函数的办法来实现memset
      • 4:memcmp
        • (1):memcmp的使用
        • (2):用函数的办法来实现memcmp

函数介绍

一:求字符串长度

1:strlen

(1):strlen的用法

size_t strlen(const char* str);

  • 字符串以 '\0' 为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含’\0’ )。
  • 参数指向的字符串必须要以 ‘\0’ 结束。
  • 注意函数的返回值为size_t,是无符号的整数( 易错 )
#include#includeint main(){const char* str1 = "abcdef";const char* str2 = "bbb";if (strlen(str2) - strlen(str1) > 0){printf("str2>str1\n");}else{printf("str1>str2\n");}return 0;}//看起来打印结果是str1>str2,但实际上是str2>str1//因为strlen是无符号size_t整型,|3-6|=3>0

(2):用函数的方法来实现strlen

#include#include#includesize_t my_strlen(const char* str){assert(str);//防止空指针const char* start = str;const char* end = str;while (*end != '\0'){end++;}return end - start;}//指针-指针方式size_t my_strlen(const char* s){char* p = s;while (*p != '\0')p++;return p - s;}//计数器方式int my_strlen(const char* str){assert(str);//断言int count = 0;while (*str){count++;str++;}return count;}int main(){char arr[] = "abcdef";int len = my_strlen(arr);printf("%d\n", len);return 0;}

二:长度不受限制的字符串函数

1:strcpy

(1):strcpy的用法

char* strcpy(char * destination, const char * source );

  • 语法原理:
    • 把source指向地址的空间的数据,拷贝到destination所指向的空间里面去.
  • 特点:
    • 源字符串必须以 ‘\0’ 结束。
    • 会将源字符串中的 ‘\0’ 拷贝到目标空间。
    • 目标空间必须足够大,以确保能存放源字符串。
    • 目标空间必须可变。
#include#includeint main(){char arr1[10] = "xxxxxxxxx";char arr2[] = { 'b', 'i', 't', '\0' };strcpy(arr1, arr2);printf("%s\n", arr1);//bitreturn 0;}//结果:bit//注:因为arr1数组的容量比arr2大,因此如果strcpy(arr2,arr1)的话//会造成越界访问 导致代码出现错误

(2):用函数的方法来实现strcpy

#include#include#includechar* my_strcpy(char* dest, const char* src){assert(dest && src);char* ret = dest;while ((*dest++ = *src++)){;}return ret;}int main(){char arr1[10] = "abcdef";char arr2[] = "bit";my_strcpy(arr1, arr2);printf("%s", arr1);return 0;}//结果:bit

2:strcat

(1):strcat的用法

char* strcat(char* destination, const char* source);

  • 语法原理:

    • 把source指向地址空间的数据,拼接到destination所指向的空间末尾处,即把第1个字符串(source)拼接到第1个字符串末尾.
  • 特点:

    • 源字符串必须以 ‘\0’ 结束。
    • 目标空间必须有足够的大,能容纳下源字符串的内容。
    • 目标空间必须可修改。
    • 字符串自己给自己追加,\0已经被覆盖掉了,这个程序会崩溃
#include#includeint main(){char arr1[20] = "你好";char arr2[] = "hello world";strcat(arr1, arr2);printf("%s\n", arr1);return 0;}//结果:你好hello world

(2):用函数的方法来实现strcat

#include#include#includechar* my_strcat(char* dest, const char* src){assert(dest);assert(src);//1.先找目标空间中的\0char* cur = dest;while (*cur != '\0'){cur++;}//2.拷贝源头数据到\0之后的空间while (*cur++ = *src++){;}return dest;//返回目标空间起始地址}int main(){char arr1[20] = "hello ";//[]里如果不加数会导致数组越界访问char arr2[] = "world";printf("%s\n", my_strcat(arr1, arr2));return 0;}

3:strcmp

(1):strcmp的用法

int strcmp(const char* str1, const char* str2);

  • 语法原理:
    • 这个函数会从两个字符串的第一个字符开始对应比较,哪一个字符的ASCII码大,哪一个 字符串大,如果两个字符一样,就继续比较下一个字符。
  • 特点
    • 第一个字符串大于第二个字符串,则返回大于0的数字
    • 第一个字符串等于第二个字符串,则返回0
    • 第一个字符串小于第二个字符串,则返回小于0的数字
#include#includeint main(){//char arr1[] = "abcdef";//char arr2[] = "abq";//返回了一个小于0的数字(-1)char arr1[] = "abcd";char arr2[] = "abc";//返回了一个大于0的数字(1)//char arr1[] = "abc";//char arr2[] = "abc";//返回0////char arr1[] = { 'a', 'b', 'c' };//err////char arr2[] = { 'a', 'b', 'c' };//errint ret = strcmp(arr1, arr2);if (ret < 0)printf("arr1);else if (ret > 0)printf("arr1>arr2\n");elseprintf("arr1==arr2\n");printf("%d\n", ret);return 0;}

(2):用函数的方法来实现strcmp

#include#include#includeint my_strcmp(const char* str1, const char* str2){assert(str1 && str2);while (*str1 == *str2){if (*str1 == '\0'){return 0;}str1++;str2++;}//方法一:/*if (*str1 > *str2){return 1;}elsereturn -1;*///方法二:return *str1 - *str2;}int main(){char arr1[] = "abcd";char arr2[] = "abc";int ret = my_strcmp(arr1, arr2);printf("%d\n", ret);return 0;}

三:长度受限制的字符串函数介绍

1:strncpy

(1):strncpy的使用

char* strncpy(char* destination, const char* source, size_t num);

  • 语法原理:
    • 拷贝num个字符从源字符串到目标空间。
      如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加’\0’,直到num个。
  • 特点:
    • 返回的指针指向被改变的字符串的首字符地址。
#include#includeint main(){char arr1[10] = "abcedf";char arr2[10] = "xxxxxxxx";strncpy(arr2, arr1, 8);//8位看上去多了,但实际多了的位数后面自动添加'\0',直到补齐8位为止,//剩余还有2个空间是本身自带的'\0'printf("%s\n", arr2);return 0;}//结果:abcedf('\0''\0''\0''\0')

(2):用函数的办法来实现strncpy

#include#include#includechar* my_strncpy(char* dest, const char* src, size_t num){assert(dest && src);char* ret = dest;while (num-- && *src != '\0'){*dest++ = *src++;}return ret;}int main(){char arr1[] = "abcdef";char arr2[] = "xxxxxxxx";int ret = my_strncpy(arr2, arr1, 5);printf("%s\n", arr2);return 0;}

2:strncat

(1):strncat的使用

char* strncat(char* destination, const char* source, size_t num);

  • 语法原理
    • 可以对字符串加长限定数目的字符
  • 特点
    • 返回的指针指向被改变的字符串的首字符地址
#include#includeint main(){char arr1[20] = "abcdef\0qqqq";char arr2[] = "xyz";strncat(arr1, arr2, 2);printf("%s\n", arr1);}//结果:abcdefxy('\0')(自己添加的'\0')

(2):用函数的办法来实现strncat

#include#includechar* my_strncat(char* dest, const char* src, size_t num){assert(dest && src);char* ret = dest;while (*dest != '\0'){dest++;}while (num-- && *src != '\0'){*dest++ = *src++;}return ret;}int main(){char arr1[20] = "abc";char arr2[] = "xyz";printf("%s\n", my_strncat(arr1, arr2, 2));return 0;}

3:strncmp

(1):strncmp的使用

int strncmp(const char* str1, const char* str2, size_t num)

  • 语法原理:
    • 这个函数会从两个字符串的第一个字符开始比较,哪一个字符的ASCII码大,哪一个字符串大,如果两个字符一样,就继续比较下一个字符。
  • 特点:
    • 这个函数可以比较限定数目的字符,由num来决定几个字符比较
#include #include int main(){char arr1[12] = "abcdef";char arr2[20] = "abcfg";int ret = strncmp(arr1, arr2, 3);printf("%d\n", ret);if (ret > 0){printf("arr1>arr2");}else if (ret == 0){printf("arr1=arr2");}else{printf("arr1);}return 0;}//结果:0 arr1=arr2

(2):用函数的办法来实现strncmp

#include#includeint my_strncmp(const char* str1, const char* str2, size_t num){assert(str1 && str2);while (num-- && *str1 == *str2 && *str1 != '\0'){if (num > 1){str1++;str2++;}}return *str1 - *str2;}int main(){char arr1[12] = "abcdef";char arr2[20] = "abcfg";int ret = my_strncmp(arr1, arr2, 3);if (ret > 0){printf("arr1>arr2");}else if (ret == 0){printf("arr1=arr2");}else{printf("arr1);}return 0;}

四:字符串查找

1:strstr

(1):strstr的使用

char* strstr(const char* str1, const char* str2);

  • 语法原理:
    • 查找一个字符串中是否存在另一个子字符串
      例如:abcdef中查找bcd就是存在的,打印结果从’b’开始一直到’\0’为止。而查找acd就是不存在的。
  • 特点:
    • 返回的指针为查找到的位置的地址,(也就是第一次子串出现的位置),如果不存在,则返回NULL.
      比如说上面的例子中我们找到了bcd那么返回的指针就指abcdef中的那个字符’b’
#include#includeint main(){char arr1[] = "abcdef";char arr2[] = "bcd";char* p = strstr(arr1, arr2);if (p == NULL)printf("不存在\n");elseprintf("%s\n", p);}//结果:bcdef('\0')

(2):用函数的办法来实现strstr

#include#includechar* my_strstr(const char* str1, const char* str2){assert(str1 && str2);char* s1 = (char*)str1;char* s2 = (char*)str2;char* cp = (char*)str1;//cp保存首字符的地址while (*cp){s1 = cp;while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2){s1++;s2++;}if (*s2 == '\0'){return cp;}s2 = (char*)str2;cp++;//cp++可以得到原起始位置的下一个位置}return NULL;}int main(){char arr1[] = "abcdef";char arr2[] = "bcd";char* p = my_strstr(arr1, arr2);if (p == NULL)printf("不存在\n");elseprintf("%s\n", p);}

2:strtok

(1):strtok的使用

char* strtok(char* str, const char* sep);

  • 语法原理
    • 第一个数组储存待拆分字符串
    • 第二个数组储存所有的分割符号
    • 函数会在待拆分字符串中从左到右找到一个分隔符号并将其赋值为\0
    • 返回的指针指向分割的那一部分字符串的开头,同时函数会记住原来分隔符的位置,我们第一个参数传NULL即可继续分割(NULL的时候才会用上记忆功能)
    • 例如:
      我们的数组一设置为:10535715@qq.com
      数组二设置为:.@
      第一次分割:10535715\0qq.com
      返回的地址指向1,内部存储的指针指向\0
      再次传递NULL,第二次分割:10535715\0qq\0com
      返回的地址指向q(第一个q),内部存储的指针指向下一个\0
      以此类推,直到字符串末尾
#include#includeint main(){char arr1[] = "10535715@qq.com";const char* p = "@.";//方法一:方便理解//首元素地址非空//char* str = strtok(arr1, p);//printf("%s\n", str);//10535715//第一个\0开始算起,strtok函数的第一个参数为NULL,直到遇到.将其变成\0//str = strtok(NULL, p);//printf("%s\n", str);//qq//第二个\0开始算起,第一个参数还是NULL//str = strtok(NULL, p);//com//printf("%s\n", str);//方法二:char* str = NULL;for (str = strtok(arr1, p); str != NULL; str = strtok(NULL, p)){printf("%s\n", str);}return 0;}

五:错误信息报告

1:strerror

(1):strerror的使用

char * strerror ( int errnum );

  • 语法原理:
    • 把错误码转换成错误信息
      在C程序中存在一个全局变量errno,要想使用这个变量需要引用头文件errno.h
      当程序出现问题的时候这个变量就会存储一个对应这个错误的数字
      但是只有这个数字我们不知道这个错误是什么
      而这个函数可以根据这个errno的值找到对应的错误,返回错误内容的字符串
#include#include#includeint main(){printf("%s\n", strerror(0));//0,1,2,3,4分别为错误码(c语言中库函数报错的时候的错误码)printf("%s\n", strerror(1));printf("%s\n", strerror(2));printf("%s\n", strerror(3));printf("%s\n", strerror(4));return 0;}//结果://No error//Operation not permitted//No such file or directory//No such process//Interrupted function call//如果错误信息是字符串的话,返回的是每行首字符的地址
#include#include#includeint main(){FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("");//打印的依然是errno变量中错误码对应的错误信息//perror=printf+strerror//printf("%s\n", strerror(errno));return 1;}//读文件fclose(pf);pf = NULL;return 0;}//No such file or directory

六:字符分类与字符转换函数

1:字符分类函数

可以判断字符是否为所需要的那一种类型的字符

下面是这部分的一些函数:(头文件为ctype.h)

  • iscntrl 任何控制字符
  • isspace 空白字符:空格‘ ’,换页‘\f’,换行’\n’,回车‘\r’,制表符’\t’或者垂直制表符’\v’
  • isdigit 十进制数字 0~9(如果 c 是一个数字,则该函数返回非零值,否则返回 0)
  • 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 任何可打印字符,包括图形字符和空白字符

2:字符转换函数

  • 可以判断字符是否可以转化为所需要的那一种类型的字符,是则进行相应转换,不是则直接打印。
  • 对于字符串也可以对每一个字符进行相应操作。
    int tolower (int c); 大写字母转成小写字母(ch+32),不是大写字母的字符直接返回原字符。
    int toupper (int c);小写字母转成大写字母(ch-32),不是小写字母的字符直接返回原字符。

七:内存操作函数

1:memcpy

(1):memcpy的使用

void * memcpy ( void * destination, const void * source, size_t num );

  • 语法原理:

    • 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
  • 特点:

    • 这个函数在遇到 ‘\0’ 的时候并不会停下来。
    • 如果source和destination有任何的重叠,复制的结果都是未定义的。所以memcpy不能重叠拷贝
#include#includeint main(){int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 0 };memcpy(arr2, arr1, 8);//把arr1中的前8个字节的数拷贝到arr2里面去int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;}//结果:1 2 0 0 0 0 0 0 0 0

memcpy与strncpy很类似,但memcpy没规定参数

(2):用函数的办法来实现memcpy

#include#include #includevoid* my_memcpy(void* dest, void* src, size_t num){void* ret = dest;//定义起始位置retassert(dest);assert(src);while(num--){*(char*)dest = *(char*)src;//void*指针无法解引用dest = (char*)dest + 1;//有些编译器不能dest++和src++src = (char*)src + 1;}return ret;}int main(){int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 0 };my_memcpy(arr2, arr1, 20);//20为数组arr1中5个int元素的大小int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr2[i]);//1 2 3 4 5 0 0 0 0 0}return 0;}

2:memmove

(1):memmove的使用

void * memmove ( void * destination, const void * source, size_t num );

  • 语法原理:
    • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
    • 如果源空间和目标空间出现重叠,就得使用memmove函数处理。
#include#includeint main(){int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };memmove(arr + 2, arr, 20);//在arr数组的首元素+2的位置处拷贝arr数组中前5个元素int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;}//结果:1 2 1 2 3 4 5 8 9 10

(2):用函数的办法来实现memmove

#include#include#includevoid* my_memmove(void* dest, const void* src, size_t num){char* s1 = (char*)dest;char* s2 = (char*)src;if (s1 <= s2){while (num--)//dest小于src时,从前向后拷贝{*s1 = *s2;s1++;s2++;}}else{while (num--){*(s1 + num) = *(s2 + num);//dest大于src时,从后向前拷贝}}return dest;}int main(){int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };my_memmove(arr + 2, arr, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);//1 2 1 2 3 4 5 8 9 10}return 0;}

3:memset

(1):memset的使用

void * memset ( void * ptr, int value, size_t num );

  • 语法原理:
    • 将ptr所指向的内存块的首个num字节(起始地址开始的字节数)设置成一个特定的值(也可解释为unsigned char)
    • value值需要被设置,该值需要int传递,但函数利用该值是unsigned char类型来填充内存块
#include#includeint main(){int arr[] = { 1,2,3,4,5 };memset(arr, 0, 8);//用0代替数组arr中的前2个元素(8个字节)int i = 0;for (i = 0; i < 5; i++){printf("%d ", arr[i]);//0 0 3 4 5}return 0;}

(2):用函数的办法来实现memset

#include#includevoid* my_memset(void* ptr, int value, size_t num){void* ret = ptr;assert(ptr);while (num--){*(char*)ptr = value;ptr = (char*)ptr + 1;}return ret;}int main(){int arr[] = { 1,2,3,4,5,6,7,8,9,10 };my_memset(arr, 0, 4);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);//0 2 3 4 5 6 7 8 9 10}return 0;}

4:memcmp

(1):memcmp的使用

int memcmp ( const void * ptr1, const void * ptr2, size_t num );

  • 语法原理:
    • 比较从ptr1和ptr2指针开始的num个字节
  • 特点:
    • 如果ptr1里面字节的数据大于ptr2,那就返回>0
    • 如果ptr1里面字节的数据等于ptr2,那就返回 = 0
    • 如果ptr1里面字节的数据小于ptr2,那就返回<0
#include#includeint main(){int arr1[] = { 1,2,3,4 };//小端存储:01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00int arr2[] = { 1,2,3,0 };//01 00 00 00 02 00 00 00 03 00 00 00 00 00 00 00int ret = memcmp(arr1, arr2, 12);//按照内存在第十二个字节数进行比较->00比00->返回0printf("%d\n", ret);return 0;}#include<stdio.h>#includeint my_memcmp(const void* str1, const void* str2, size_t count){assert(str1);assert(str2);if (!count){return 0;}while (--count && *(char*)str1 == *(char*)str2){str1 = (char*)str1 + 1;str2 = (char*)str2 + 1;}return ((unsigned char*)str1 - (unsigned char*)str2);}int main(){int arr1[] = { 1,2,3,4,5 };int arr2[] = { 0 };int ret = my_memcmp(arr2, arr1, 12);//返回了一个大于0的数printf("%d\n", ret);return 0;}

memcmp和strncmp很类似,但memcmp没规定参数。

(2):用函数的办法来实现memcmp

#include#includeint my_memcmp(const void* str1, const void* str2, size_t count){assert(str1);assert(str2);if (!count){return 0;}while (--count && *(char*)str1 == *(char*)str2){str1 = (char*)str1 + 1;str2 = (char*)str2 + 1;}return ((unsigned char*)str1 - (unsigned char*)str2);}int main(){int arr1[] = { 1,2,3,4,5 };int arr2[] = { 0 };int ret = my_memcmp(arr2, arr1, 12);//返回了一个大于0的数printf("%d\n", ret);return 0;}