当前位置: 首页 > news >正文

C语言字符函数和字符串函数+内存操作函数

目录

本章重点

0、前言

1、函数介绍

1.1strlen

1.1.1strlen使用

1.1.2strlen的模拟实现

1.1.3 assert介绍

1.2strcpy

1.2.1strcpy的使用

1.2.2strcpy的模拟实现

1.3strcat

1.3.1strcat的使用

1.3.2strcat的模拟实现

1.4strcmp

1.1.1strcmp的使用

1.4.2strcmp的模拟实现

1.5strncpy

1.5.1strncpy的使用

1.5.2strncpy的模拟实现

1.6strncat

1.6.1strncat的使用

1.6.2strncat的模拟实现

1.7strncmp

1.7.1strncmp的使用

1.7.2strncmp的模拟实现

1.8strstr

1.8.1strstr的使用

1.8.2strstr的模拟实现

1.9strtok

1.9strtok的使用

1.10strerror

1.10.1strerror使用

1.11字符分类函数

1.12字符转换函数

1.13memcpy

1.13.1memcpy的使用

1.13.2momcpy的模拟实现

1.14mommove

1.14.1memmove的使用

1.14.2memmove的模拟实现

1.15memcmp

1.15.1memcmp的使用

1.15.2memcmp的模拟实现

1.16memset


本章重点

重点介绍处理字符和字符串的库函数的使用和注意事项

  • 求字符串长度
    • strlen
  • 长度不受限制的字符串函数
    • strcpy
    • strcat
    • strcmp
  • 长度受限制的字符串函数介绍
    • strncpy
    • strncat
    • strncmp
  • 字符串查找
    • strstr
    • strtok
  • 错误信息报告
    • strerror
  • 字符操作
  • 内存操作函数
    • memcpy
    • memmove
    • memset
    • memcmp

0、前言

        C语言中对字符和字符串的处理很繁琐,但是C语言本身是没有字符串类型的,字符串通常在常量字符串中或者字符数组中。

        字符串常量适用于那些对它不做修饰的字符串函数。

1、函数介绍

1.1strlen

1.1.1strlen使用

size_t strlen (const char * str);

  • 字符串已经'\0'作为结束标志,strlen函数返回的是在字符串中‘\0’前面出现的字符个数(不包含‘\0’)。
  • 参数指向的字符串必须要以‘\0’结束。
  • 注意函数的返回为 size_t( unsigned int),是无符号的(易错) 【因为是无符号的所以相减不会出现负值,不能通过减法来判断两个字符串长度的大小】。
  • 学会strlen函数的模拟实现

    注:如果所定义的字符串中没有放 \0 出现的是随机值。所以在传字符串时候一定要有‘\0’。

#include<stdio.h>
#include<string.h>  //strlen函数的头文件。
int main() {char arr[] = "abcdef";//abcdef\0int len = strlen(arr);printf("%d\0 ", len);return 0;
}

注意:下面比较两字符字符串长度大小的方法是错误的。

        解析:很明显可以看出arr字符串的长度为6,arr1字符串的长度为3。3 - 6 = -3 < 0,应该打印arr1 < arr。但是strlen返回size_t (unsigned  int)类型,无符号整形不会出现负数,所以很好理解这种方法为何出错啦。接下来进行改正。

1.1.2strlen的模拟实现

方法一:计数器方法

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>  //strlen函数的头文件。
#include<assert.h>
size_t my_strlen(char* str) {assert(str);//size_t count = 0;while (*str != '\0') {count += 1;str++;}return count;
}
int main() {char arr[] = "abcdef";size_t n = my_strlen(arr);printf("%d \n", n);return 0;
}

方法二:指针 - 指针

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>  //strlen函数的头文件。
#include<assert.h>
size_t my_strlen(char* str) {assert(str);//char* p = str;while (*str != '\0') {str++;}return str - p;
}
int main() {char arr[] = "abcdef";size_t n = my_strlen(arr);printf("%d \n", n);return 0;
}

方法三:递归的方法

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>  //strlen函数的头文件。
#include<assert.h>
size_t my_strlen(char* str) {assert(str);//if (*str != '\0') {return my_strlen(str += 1) + 1;}return 0;
}
int main() {char arr[] = "abcdef";size_t n = my_strlen(arr);printf("%d \n", n);return 0;
}
1.1.3 assert介绍

上面代码使用了assert下面简单介绍一下                

         assert 是一个,用于在运行时检查一个条件是否为真,如果条件不满足,则运行时将终止程序的执行并输出一条错误信息。

1.2strcpy

1.2.1strcpy的使用

char* strcpy(char* destination【目标空间】, const char* source【原字符串】);

  • 原字符串必须以‘\0’结束。
  • 会将原字符串中的‘\0’拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放原字符串。
  • 目标空间必须可变。(变量,比如常量字符串不可改。)
  • 学会模拟实现。
#include<stdio.h>
#include<string.h>  //strlen函数的头文件。
#include<assert.h>
int main() {char name[20] = { 0 };char arr[] = "zhangsan";strcpy(name, arr);//name = arr;这种写法是错误的,arr数组名是地址,地址是一个常量值,不能被赋值printf("%s", name);return 0;
}
1.2.2strcpy的模拟实现
#include<stdio.h>
#include<string.h>  //strlen函数的头文件。
#include<assert.h>
char* my_strcpy(char* dest, char* src) {assert(dest && src);char* p = dest;while (*dest++ = *src++);//简化版本return p;
}
int main(){char name[20] = { 0 };char arr[] = "zhangsan";char*p = my_strcpy(name, arr); // 把arr复制到name中printf("%s\n", p);return 0;
}

1.3strcat

1.3.1strcat的使用

char* strcat(char* destination【目标空间】, const char* source【原字符串】);

  • 原字符串必须以‘\0’结束。
  • 目标空间必须足够的大,能容纳下字符串的内容。
  • 目标空间必须可修改。
  • 字符串自己给自己追加,如何?死循环】
#include<stdio.h>
#include<string.h>  //strlen函数的头文件。
int main(){char arr[20] = "hello ";strcat(arr, "world");printf("%s\n", arr);
}
1.3.2strcat的模拟实现
#include<stdio.h>
#include<string.h>  //strlen函数的头文件。
#include<assert.h>
char* my_strcat(char* dest, const char* src) {assert(dest && src);char* p = dest;while (*dest != '\0') {dest++;}while (*dest++ = *src++);return p;
}
int main(){char arr[20] = "hello ";char* ans = my_strcat(arr, "world");printf("%s\n", ans);
}

1.4strcmp

1.1.1strcmp的使用

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

注意:这里比较的是两个字符串,不是比较两个字符串的长度

#include<stdio.h>
#include<string.h>  //strcmp函数的头文件。
#include<assert.h>
int main(){char arr1[] = "abdc";char arr2[] = "abcdef";int ant = strcmp(arr1, arr2);if (ant > 0) {printf("arr1 > arr2");}else if (ant == 0) {printf("arr1 == arr2");}else {printf("arr1 < arr2");}
}

1.4.2strcmp的模拟实现
#include<stdio.h>
#include<string.h>  //strcmp函数的头文件。
#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 arr1[] = "abcdef";char arr2[] = "abcdef";int ans = my_strcmp(arr1, arr2);if (ans > 0) {printf("arr1 > arr2\n");}else if (ans == 0) {printf("arr1 == arr2\n");}else {printf("arr1 < arr2\n");}return 0;
}

1.5strncpy

1.5.1strncpy的使用

char* strncpy(char* destination【目标空间】, const char* source【原字符串】, size_t num);

        只拷贝num个字符。

#include<stdio.h>
#include<string.h>  //strncpy函数的头文件。
#include<assert.h>
int main() {char arr1[] = "aaaaaaa";//共7个字符char arr2[] = "bbbbbbbbb";//共9个字符strncpy(arr1, arr2, 5);printf("%s\n", arr1);return 0;
}

1.5.2strncpy的模拟实现

代码1:

#include<stdio.h>
#include<string.h>  //strncpy函数的头文件。
#include<assert.h>
char* my_strncpy(char* str1, const char* str2, int num) {assert(str1 && str2);char* p = str1;while (num > 0) {if (*str2 == '\0') {*str1 = '\0';str1++;}else {*str1 = *str2;str1++;str2++;}num--;}return p;
}
int main() {char arr1[] = "aaaaaaa";//共7个字符char arr2[] = "bbb";//共9个字符int n = 0;scanf("%d", &n);char* ant = my_strncpy(arr1, arr2, n);printf("%s\n", ant);/*int i = 0;for (i = 0; i < 7; i++) {if (*ant == '\0')printf("*");elseprintf("%c", *ant);ant++;}*/return 0;
}

代码2:

#include<stdio.h>
#include<string.h>  //strncpy函数的头文件。
#include<assert.h>
char* my_strncpy(char* str1, const char* str2, int sum) {assert(str1 && str2);char* p = str1;while (*str2 != '\0' && (*str1++ = *str2++) && (sum--));while (sum > 0) {*(++str1) = '\0';sum--;}return p;
}
int main() {char arr1[20] = "abc";char arr2[] = "dd";char* ans = my_strncpy(arr1,arr2,10);printf("%s\n", ans);return 0;
}

1.6strncat

1.6.1strncat的使用

char* strncat(char* destination【目标空间】, const char* source【原字符串】,size_t sum);

追加在字符串后面追加sum个字符。

  • 目标空间要足够大。
#include<stdio.h>
#include<string.h>  //strncat函数的头文件。
#include<assert.h>
int main() {char arr1[20] = "abc";char arr2[] = "ddddd";strncat(arr1,arr2,3);printf("%s\n", arr1);return 0;
}

        如果所追加的字符个数大于所追加的字符长度,则只是把所追加的字符串追加完并加’\0’。

        比如:char arr[20] = "ab";  strncat(arr, "ddd", 6);则我们知道所追加的字符串只有3个字符要追加的个数为6个。那么arr会变成什么?答案abddd\0

1.6.2strncat的模拟实现
#include<stdio.h>
#include<string.h>  //strncat函数的头文件。
#include<assert.h>
char* my_strncat(char* str1, const char* str2, int sum) {char* p = str1;while (*str1 != '\0') {str1++;}while (sum > 0 && (*str1++ = *str2++)) {//*str1++ = *str2++;sum--;}return p;}
int main() {char arr1[20] = "abc";char arr2[] = "ddddd";char* ans = my_strncat(arr1,arr2,10);printf("%s\n", ans);return 0;
}

1.7strncmp

1.7.1strncmp的使用

int strncmp(conts char* str1, conts char* str2, size_t num);

#include<stdio.h>
#include<string.h>  //strncmp函数的头文件。
#include<assert.h>
int main() {char arr1[20] = "abcdef";char arr2[20] = "abc";int ans = strncmp(arr1,arr2,3);if (ans == 0) {printf("==\n");}else if (ans > 0) {printf(">\n");}else {printf("<\n");}return 0;
}

1.7.2strncmp的模拟实现
#include<stdio.h>
#include<string.h>  //strncmp函数的头文件。
#include<assert.h>
int my_strncmp(const char* str1, const char* str2, int sum) {assert(str1 && str2);while (sum > 0) {sum--;if (*str1 == *str2) {str1++;str2++;}else if ((*str1 == '\0') || (*str2 == '\0')) {return 0;}else {break;}}if ((*str1 == '\0') || (*str2 == '\0')) {return 0;}else {return *str1 - *str2;}
}
int main() {char arr1[20] = "abcdff";char arr2[20] = "abcd";int ans = my_strncmp(arr1,arr2,4);if (ans == 0) {printf("==\n");}else if (ans > 0) {printf(">\n");}else {printf("<\n");}return 0;
}

1.8strstr

1.8.1strstr的使用

在一个字符串中找子字符串

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

如果找到返回子串在主串的地址,如果找不到返回空(NULL)

#include<stdio.h>
#include<string.h>  //strstr函数的头文件。
#include<assert.h>
int main() {char arr1[20] = "zzabcdff";char arr2[20] = "abcd";char* p = strstr(arr1, arr2);  //在arr1中找arr2if (p == NULL) {printf("子串没找到\n");}else {printf("%s\n", p);}return 0;
}
1.8.2strstr的模拟实现
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>  //strstr函数的头文件。
#include<assert.h>
const char* my_strstr(const char* str1, const char* str2) {assert(str1 && str2);const char* s1 = str1;const char* s2 = str2;const char* p = str1;while (*s1 != '\0') {while (*s1 != '\0' && *s2!= '\0' && * s1 == *s2) {  //字符逐个比较s1++;s2++;}if (*s2 == '\0') {  //如果s2子串走到了\0 说明前面的字符匹配成功。return p;}//如果没有匹配成功继续从下一个字符下一个匹配p++;s1 = p;s2 = str2;}return NULL;  //如果循环结束说明没有匹配成功,返回NULL
}
int main() {const char arr1[20] = "zzabbbcdff";const char arr2[20] = "ff";const char* p = my_strstr(arr1, arr2);  //在arr1中找arr2if (p == NULL) {printf("子串没找到\n");}else {printf("%s\n", p);}return 0;
}

        注意:我们写的代码效率较低。KMP算法,这个算法也是在字符串中找子串,但是实现起来比较复杂难以理解。

1.9strtok

1.9strtok的使用

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

  • sep参数是个字符串,定义了用作分隔符字符集合
  • 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中分隔符分割符的标记。
  • strtok函数找到str中的下一个标记,并将其用\0结尾【分隔符被改为 \0 】,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串都是临时拷贝的内容并且可修改。)
  • strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
  • strtok函数第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
  • 如果字符串中不存在更多标记,则返回NULL指针
  • #include<stdio.h>
    #include<string.h>  //strtok函数的头文件。
    #include<assert.h>
    int main() {const char arr1[20] = "@.";char arr2[20] = "ff.gg@aa";char* ant = strtok(arr2, arr1);printf("%s\n", ant);ant = strtok(NULL, arr1);printf("%s\n", ant);ant = strtok(NULL, arr1);printf("%s\n", ant);return 0;
    }

        有时候我们并不知道字符串被分隔符分割几次,所以我们并不知道调用多少次strtok函数,所以下面的技巧很好的解决了这个问题。

#include<stdio.h>
#include<string.h>  //strtok函数的头文件。
#include<assert.h>
int main() {const char arr1[20] = "@.";char arr2[20] = "ff.gg@aa";char* ret = NULL;//利用for的特点for (ret = strtok(arr2, arr1);ret != NULL; ret = strtok(NULL, arr1)) {printf("%s\n", ret);}return 0;
}

1.10strerror

1.10.1strerror使用

#include<errno.h> //头文件。

char * strerror(int errnum);

返回错误码,所对应的错误信息。

C语言的库函数,在执行失败的时候,都会设置错误码; 0 1 2 等每个数字对应不同的错误情况。

#include<stdio.h>
#include<string.h>  //strtok函数的头文件。
#include<errno.h>   //strerror()头文件
int main() {FILE* pf = fopen("test.txt", "r");if (pf == NULL) {  //如果为空说明打开失败printf("%s\n", strerror(errno));  //errno—C语言设置的一个全局的错误码存放的变量}return 0;
}

1.11字符分类函数

上面的函数用法是一模一样的。都需要头文件这里就不挨个介绍啦。

1.12字符转换函数

字符大小写转换,tolower将大写转换小写。toupper转换为大写。

1.13memcpy

1.13.1memcpy的使用

1.13.2momcpy的模拟实现
#include<stdio.h>
#include<string.h>  //memcpy函数的头文件。
#include<assert.h>
void * my_memcpy(void* dest, const void* src,size_t num) {assert(dest && src);void* p = dest;  //保留首地址,方便返回。while(num > 0){*(char*)dest = *(char*)src;  //一个字节一个字节的拷贝dest = (char*)dest + 1;src = (char*)src + 1;num -= 1;}return p;
}
int main() {int arr1[5] = { 1,2,3,4,5 };int arr2[10] = {0};void* p = my_memcpy(arr2, arr1, 20);  //函数的第三个字符表示拷贝的字节数。int sz = sizeof(arr2) / sizeof(arr2[2]);int i = 0;for (i = 0; i < sz; i++) {printf("%d ", arr2[i]);}printf("\n");return 0;
}
  • memcmp 负则拷贝两块独立空间中的数据。
  • 重叠内存的拷贝,是怎么做的呢?memmove函数。

1.14mommove

1.14.1memmove的使用

 void *memmove(void *dest, const void *src, size_s count);

1.14.2memmove的模拟实现
#include<stdio.h>
#include<string.h>  //memmove函数的头文件。
#include<assert.h>
void* my_memmove(void* dest, const void* src, size_t num) {//函数的第三个参数表示拷贝的字节数assert(dest && src);void* p = dest;if (dest < src){while (num--) {*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}}else{while(num--){*((char*)dest + num) = *((char*)src + num);  //从后往前覆盖}}return p;
}
int main() {int arr1[20] = { 1,2,3,4,5,6,7,8,9,10 };my_memmove(arr1 + 2, arr1, 20);//打印int i = 0;for (i = 0; i < 10; i++) {printf("%d ", arr1[i]);}printf("\n");return 0;
}

1.15memcmp

1.15.1memcmp的使用

比较两块内存中的数据是否相同。

#include<stdio.h>
#include<string.h>  //memmove函数的头文件。
#include<assert.h>
int main() {int arr1[20] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[] = { 1, 2, 3, 5 };int tmp = memcmp(arr1, arr2, 16);//第三个参数单位是字节if (tmp > 0) {printf("arr1 > arr2\n");}else if (tmp < 0) {printf("arr1 < arr2\n");}else {printf("arr1 == arr2\n");}return 0;
}

1.15.2memcmp的模拟实现
#include<stdio.h>
#include<string.h>  //memcmp函数的头文件。
#include<assert.h>
int my_memcmp(const void* ptr1, const void* ptr2, size_t num) {assert(ptr1 && ptr2);while(num--){if (*((char*)ptr1) == *((char*)ptr2)) {ptr1 = (char*)ptr1 + 1;ptr2 = (char*)ptr2 + 1;}else {return *((char*)ptr1) - *((char*)ptr2);}}return 0;
}
int main() {int arr1[20] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[] = { 1, 2, 3 };int tmp = my_memcmp(arr1, arr2, 9);//第三个参数单位是字节if (tmp > 0) {printf("arr1 > arr2\n");}else if (tmp < 0) {printf("arr1 < arr2\n");}else {printf("arr1 == arr2\n");}return 0;
}

1.16memset

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

ptr设置填充空间的起始地址。

value设置填充的值。

num设置填充的字节数。

#include<stdio.h>
#include<string.h>  //memset函数的头文件。
int main() {char arr1[20] = "hello world";memset(arr1, 'x', 5);//第三个参数单位是字节printf("%s", arr1);return 0;
}

memset在设置填充时候是一个字节一个字节设置的。

http://www.dtcms.com/a/432666.html

相关文章:

  • 容桂营销网站建设如何做公司简介介绍
  • html5建设摄影网站意义网站建设如何推广
  • ai设计logo免费网站自助建站系统注册
  • 网站开发怎么自学开发app怎么赚钱
  • 网站外部链接合理建设外贸建站费用
  • 网站模板建站公司如何提升网站的流量
  • 湖北中英双语网站建设济南网站怎么做seo
  • 高创园网站建设方案wordpress 搬家 空白
  • 网站地图怎么做XML成都seo优化
  • 科普:使用 apt 或 pip安装软件包前,为何要执行更新update操作
  • 便利的集团网站建设外贸服装网站开发
  • 网站 分析广西城乡建设局和住建局官网
  • 昆明专业网站建设模板合肥建设集团信息网站
  • SSM整合 —— 在Spring中配置MyBtis
  • 黄龙云 加强网站建设外贸做网站公司
  • 山东省建设厅制一网站沈阳专业网站建设公司排名
  • 17做网店这个网站做起多少钱wordpress 框架选择
  • 企业展示网站 数据库设计网站重购
  • 湖南平台网站建设设计php网站开发说明文档
  • 个人网站主页设计教程ui培训费用
  • 进口跨境电商网站制作坚决把快准严细实要求落实到位
  • 计算机发展史之阿达·洛芙莱斯
  • 海搜网做的网站怎么样帮企业做网站的
  • 首钢建设二建设公司网站哪些网站的做的好看
  • 成品网站怎么被百度收录实验仪器销信应做何网站
  • 商会联盟网站建设方案有哪些做兼职的设计网站有哪些工作内容
  • 公司网站建设方案拓扑图高端网站
  • 英语工作室网站怎么做平面广告设计培训
  • 建网站找哪个平台好呢wordpress 评论 作者
  • 最优惠的手机网站建设网站空间买什么的好