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

C语言进阶--字符串+内存函数

求字符串长度strlen()

长度不受限制的字符串函数strcpy()、strcat()、strcmp()

长度受限制的字符串函数strncpy()、strncat()、strncmp()

字符串查找函数strstr()、strtok()

错误信息报告strerror()

字符操作

内存操作函数memcpy()、memmove()、memset()、mencmp()

strlen()

size_t strlen(const char* str);

字符串将’\0’作为结束标志,strlen函数返回的是在字符串中’\0’前面出现的字符个数(不包括’\0’).

参数指向的字符串必须要以’\0’结束。

注意函数的返回值是size_t,是无符号的(易错)。

在这里插入图片描述

#include <stdio.h>
#include <string.h>int main()
{char arr[] = {"abcdef"}; //abcdef\0int len = strlen(arr);printf("%d\n", len); //6return 0;
}
#include <stdio.h>
#include <string.h>int main()
{char arr[] = {'b', 'i', 't'}; //[][][][][][][b][i][t][][][][]int len = strlen(arr); printf("%d\n", len); //随机值return 0;
}
#include <stdio.h>
#include <string.h>int main()
{//if (strlen("abc") - strlen("abcdef") > 0)  //size_t。error,>if (strlen("abc") > strlen("abcdef")) //<={printf(">\n");}else{printf("<=\n"); }return 0;
}

模拟实现strlen

1、计算器方法

2、指针-指针的方法

3、递归的方法

#include <assert.h>
#include <stdio.h>size_t my_strlen(const char* str)
{size_t count = 0;assert(str);while (*str != '\0'){count++;str++;}return count;
}
int main()
{char arr[] = "abcdef";size_t n = my_strlen(arr);printf("%u\n", n); //6return 0;
}

strcpy()

Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).

源字符串必须以’\0’结束。

会将字符串中的’\0’拷贝到目标空间。

目标空间必须足够大,以确保能存放源字符串。

目标空间必须可变。

在这里插入图片描述

#include <stdio.h>
#include <string.h>int main()
{char name[20] = {0};strcpy(name, "zhangsan"); //name = "zhangsan"; //error,name数组名是地址,地址是一个常量值,不能被赋值printf("%s\n", name);  //zhangsanreturn 0;
}
#include <stdio.h>
#include <string.h>int main()
{char name[20] = {0};strcpy(name, "zhang\0san"); printf("%s\n", name);  //zhangreturn 0;
}
#include <stdio.h>
#include <string.h>int main()
{char name[20] = "xxxxxxxxxxx";char arr[] = {'b', 'i', 't'};strcpy(name, arr); //原始数据须有\0printf("%s\n", name);  //zhangreturn 0;
}

在这里插入图片描述

#include <stdio.h>
#include <string.h>int main()
{char name[3] = "";char arr[] = "abcdef";strcpy(name, arr); printf("%s\n", name);  //abcdef,程序崩溃return 0;
}

在这里插入图片描述

#include <string.h>int main()
{char* p = "abcdef";char arr[] = "bit";strcpy(p, arr); //目标区域不可变return 0;
}

在这里插入图片描述

模拟实现strcpy

#include <stdio.h>
char* my_strcpy(char* dest, const char* src)
{assert(dest);assert(src);char* ret = dest;while (*src){*dest++ = *src++;}*dest = *src; // \0return ret; //返回目标空间的地址
}
int main()
{char arr1[] = {"abcdef"};char arr2[] = {0};my_strcpy(arr2, arr1);printf("%s\n", arr2); //abcdefreturn 0;
}
//优化
#include <stdio.h>
char* my_strcpy(char* dest, const char* src)
{assert(dest && src);char* ret = dest;while (*dest++ = *src++){;}return ret; //返回目标空间的起始地址
}
int main()
{char arr1[] = {"abcdef"};char arr2[] = {0};my_strcpy(arr2, arr1);printf("%s\n", arr2); //abcdefreturn 0;
}

strcat():字符串追加

源字符串必须以’\0’结束。

目标空间必须足够大,能容纳下源字符串的内容。

目标空间必须可修改。
在这里插入图片描述

#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = "hello ";strcat(arr1, "world");printf("%s\n", arr1); //hello worldreturn 0;
}

模拟实现strcat

#include <stdio.h>
#include <assert.h>char* my_strcat(char* dest, const char* src)
{char* ret = dest;assert(dest && src);//1.找到目标空间的末尾\0while(*dest != '\0'){dest++;}//2.拷贝字符串while (*dest++ = *src++){;}return ret;
}
int main()
{char arr1[20] = "hello ";my_strcat(arr1, "world");printf("%s\n", arr1); //hello worldreturn 0;
}

自己给自己追加?死循环

#include <stdio.h>
#include <assert.h>char* my_strcat(char* dest, const char* src)
{char* ret = dest;assert(dest && src);//1.找到目标空间的末尾\0while(*dest != '\0'){dest++;}//2.拷贝字符串while (*dest++ = *src++){;}return ret;
}
int main()
{char arr1[20] = "hello ";my_strcat(arr1, arr1);printf("%s\n", arr1); return 0;
}

在这里插入图片描述

strcmp()

在这里插入图片描述
在这里插入图片描述

//error,这里是在比较2个地址,而不是比较2个字符串的内容
#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = "zhangsan";char arr2[] = "zhangsanfen";//比较两个字符串是否相等if (arr1 == arr2)  //arr1是数组名,数组名是数组首元素的地址;arr2是数组名,数组名是数组首元素的地址{printf("==\n");}elseprintf("!=\n"); //!=return 0;
}

2个字符串比较相等,应该使用strcmp。

#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = "zhangsan";char arr2[] = "zhangsanfen";int ret = strcmp(arr1, arr2);if (ret < 0)printf("<\n"); //<else if (ret == 0)printf("==\n");elseprintf(">\n");return 0;
}
#include <stdio.h>
#include <string.h>int main()
{char arr1[] = "abcdef";char arr2[] = "abq";  //一对一对比较ASCII码值int ret = strcmp(arr1, arr2);if (ret < 0)printf("<\n"); //<else if (ret == 0)printf("==\n");elseprintf(">\n");return 0;
}

模拟实现strcmp

#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++;}if (*str1 > *str2)return 1;elsereturn -1;
}
int main()
{char arr1[] = "abc";char arr2[] = "abc";  int ret = my_strcmp(arr1, arr2);if (ret < 0)printf("<\n"); else if (ret == 0)printf("==\n"); //==elseprintf(">\n");  return 0;
}
//优化
#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 arr1[] = "abc";char arr2[] = "abc";  int ret = my_strcmp(arr1, arr2);if (ret < 0)printf("<\n"); else if (ret == 0)printf("==\n"); //==elseprintf(">\n");  return 0;
}

strncpy()

长度受限制的字符串函数strncpy()、strncat()、strncmp()

在这里插入图片描述

#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = "abcdef";char arr2[] = "hello bit";strncpy(arr1, arr2, 5);printf("%s\n", arr1); //hellofreturn 0;
}

在这里插入图片描述

strncat()

在这里插入图片描述

在这里插入图片描述

strncmp()

#include <stdio.h>
#include <string.h>int main()
{char arr1[] = "abcdef";char arr2[] = "abcq";int ret = strncmp(arr1, arr2, 4);if (ret == 0)printf("==\n");else if (ret < 0)printf("<\n"); //<elseprintf(">\n");return 0;
}
#include <stdio.h>
#include <string.h>int main()
{char arr1[] = "abcdef";char arr2[] = "abcq";int ret = strncmp(arr1, arr2, 3);printf("%d\n", ret); //0return 0;
}

strstr():查找子串

在这里插入图片描述

#include <stdio.h>
#include <string.h>int main()
{char email[] = "zpw@bitejiuyeke.com";char substr[] = "bitejiuyeke";char* ret = strstr(email, substr);if (ret == NULL)printf("子串不存在\n");elseprintf("%s\n", ret); //bitejiuyeke.comreturn 0;
}

模拟实现strstr

#include <stdio.h>
#include <string.h>
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 (*p){s1 = p;s2 = str2;while (*s1!='\0' && *s2!='\0' && *s1 == *s2){s1++;s2++;}if (*s2 == '\0'){return (char*)p;}p++;}return NULL;
}
int main()
{char email[] = "zpw@bitejiuyeke.com";char substr[] = "bitejiuyeke";char* ret = my_strstr(email, substr);if (ret == NULL)printf("子串不存在\n");elseprintf("%s\n", ret); //bitejiuyeke.comreturn 0;
}

也可使用KMP算法:用来实现一个字符串中查找子字符串的,效率高,但是实现难度大。(B站搜索:大比特博哥)

strtok():切割字符串

在这里插入图片描述

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

sep参数是一个字符串,定义了用作分隔符的字符集合。

第一个参数指定一个字符串,它包含了0个或多个由sep字符串中一个或多个分隔符分割的标记。

strtop函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针。(注意:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)

strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。

strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。

如果字符串中不存在更多的标记,则返回NULL指针。

#include <stdio.h>
#include <string.h>int main()
{const char* sep = "@.";char email[] = "zhangpengwei@bitejiuyeke.com";char cp[30] = {0}; strcpy(cp, email);char* ret = strtok(cp, sep);printf("%s\n", ret);ret = strtok(NULL, sep);printf("%s\n", ret);ret = strtok(NULL, sep);printf("%s\n", ret);return 0;
}

在这里插入图片描述

//显得啰嗦
#include <stdio.h>
#include <string.h>int main()
{const char* sep = "@.";char email[] = "zhangpengwei@bitejiuyeke.com";char cp[30] = {0}; strcpy(cp, email);char* ret = strtok(cp, sep);if (ret != NULL)printf("%s\n", ret);ret = strtok(NULL, sep);if (ret != NULL)printf("%s\n", ret);ret = strtok(NULL, sep);if (ret != NULL)printf("%s\n", ret);return 0;
}
//for循环修正
#include <stdio.h>
#include <string.h>int main()
{const char* sep = "@.";char email[] = "zhangpengwei@bitejiuyeke.com";char cp[30] = {0}; strcpy(cp, email);char* ret = NULL;for (ret = strtok(cp, sep); ret != NULL; ret = strtok(NULL, sep)){printf("%s\n", ret);}return 0;
}

在这里插入图片描述

strerror():返回错误码,所对应的错误信息

C语言的库函数,在执行失败的时候,都会设置错误码。0 1 2 3 4 5 6 7 8

#include <stdio.h>
#include <string.h>
int main()
{printf("%s\n", strerror(0));printf("%s\n", strerror(1));printf("%s\n", strerror(2));printf("%s\n", strerror(3));printf("%s\n", strerror(4));printf("%s\n", strerror(5));return 0;
}

在这里插入图片描述

//errno:C语言设置的一个错误码存放的全局变量,但需要包含头文件#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{FILE* pf = fopen("test.txt", "r");if (pf == NULL){printf("%s\n", strerror(errno));return 1;}else{//}return 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字母或者数字,a-z,A-Z,0-9
ispunct标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph任何图形字符
isprint任何可打印字符,包括图形字符和空白字符
#include <stdio.h>
#include <ctype.h>int main()
{int a = isspace(' ');printf("%d\n", a); //8return 0;
}
#include <stdio.h>
#include <ctype.h>int main()
{int a = isdigit('0');printf("%d\n", a); //4return 0;
}
#include <stdio.h>
#include <ctype.h>int main()
{int a = isdigit('x');printf("%d\n", a); //0return 0;
}

字符转换函数

tolower()

toupper()

#include <stdio.h>
#include <ctype.h>int main()
{printf("%c\n", tolower('W')); //wreturn 0;
}
#include <stdio.h>
#include <ctype.h>int main()
{printf("%c\n", tolower('@')); //@return 0;
}

memcpy():内存拷贝

strcpy()和strncpy()只能拷贝字符串。如果想要拷贝整型或者其它类型怎么办呢?

在这里插入图片描述

#include <stdio.h>
#include <string.h>
int main()
{int arr1[] = {1,2,3,4,5,6,7};int arr2[10] = {0};memcpy(arr2, arr1, 28);float arr3[5] = {1.0, 2.5, 3.0, 5.0, 6.0};float arr4[10] = {0.0};memcpy(arr4, arr3, 20);return 0;
}

在这里插入图片描述

模拟实现memcpy

#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{assert(dest && src);void* ret = dest;while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return ret;
}
int main()
{int arr1[] = {1,2,3,4,5,6,7};int arr2[10] = {0};my_memcpy(arr2, arr1, 28);return 0;
}

在这里插入图片描述
在这里插入图片描述
memcpy负责拷贝两块独立空间中的数据。

像上述案例,想要重叠内存的拷贝,是怎么做的呢?使用memmove()函数。

memmove()

windows自带的“画图”工具。【英文名:mspaint】

在这里插入图片描述
复习前半段:

#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{assert(dest && src);void* ret = dest;while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return ret;
}void test2()
{int arr1[] = {1,2,3,4,5,6,7,8,9,10};my_memcpy(arr1+2, arr1, 20); //1 2 1 2 3 4 5 8 9 10int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr1[i]);}
}
int main()
{test2();return 0;
}

在这里插入图片描述
并未如结果所示,所以使用memmove():

#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{assert(dest && src);void* ret = dest;while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return ret;
}void test2()
{int arr1[] = {1,2,3,4,5,6,7,8,9,10};//my_memcpy(arr1+2, arr1, 20); //1 2 1 2 3 4 5 8 9 10memmove(arr1+2, arr1, 20);  //memcpy函数是不用来处理重叠的内存之间的数据拷贝;使用memmove函数来实现,重叠内存之前的数据拷贝int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr1[i]);}
}
int main()
{test2();return 0;
}

在这里插入图片描述
注意:VS下的内置memcpy()函数是可以实现重叠内存的数据拷贝,可自己尝试,由此看出函数也很卷啊!

模拟实现memmove()

#include <stdio.h>
#include <string.h>
#include <assert.h>void my_memmove(void* dest, const void* src, size_t num)
{assert(dest && src);void* ret = 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 ret;
}
void test3()
{int arr1[] = {1,2,3,4,5,6,7,8,9,10}; my_memmove(arr1+2, arr1, 20);  //my_memmove(arr1, arr1 + 2, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr1[i]);}
}
int main()
{test3();return 0;
}

有时候需要从前往后处理数据,有时候又需要从后往前处理数据。

memcmp()

在这里插入图片描述
在这里插入图片描述

#include <stdio.h>
#include <string.h>int main()
{int arr1[] = {1,2,3,4,5}; //01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00int arr2[] = {1,3,2};     //01 00 00 00 03 00 00 00 02 00 00 00int ret = memcmp(arr1, arr2, 12);printf("%d\n", ret); //-1return 0;
}

memset():内存设置

在这里插入图片描述

#include <stdio.h>
#include <string.h>
int main()
{char arr[] = "hello bit";memset(arr, 'x', 5);printf("%s\n", arr); //xxxxx bitreturn 0;
}
#include <stdio.h>
#include <string.h>
int main()
{char arr[] = "hello bit";memset(arr+6, 'x', 3);printf("%s\n", arr); //hello xxxreturn 0;
}
//将arr初始化为全1,答案并非我们所想
#include <stdio.h>
#include <string.h>
int main()
{int arr[10] = {0};memset(arr, 1, 40);int i = 0;for (i = 0; i < 10; i++){printf("%d\n", arr[i]);}return 0;
}

在这里插入图片描述
在这里插入图片描述

总结

今天就暂且更新至此吧,期待下周再会。如有错误还请不吝赐教。希望对您学习有所帮助,翻页前留下你的支持,以防下次失踪了嗷。

作者更新不易,免费关注别手软。

http://www.xdnf.cn/news/9828.html

相关文章:

  • R语言在生物群落数据统计分析与绘图中的实践应用
  • 【电拖自控】转速检测数字测速(脉冲计数测速)
  • SSH免密登录其它用户脚本
  • Hadoop MapReduce:大数据处理利器
  • 25 字符数组与字符串及多维数组详解:定义与初始化、访问与遍历、%s 格式符、内存剖析、编程实战
  • 什么是单片机?
  • Axure设计案例——科技感对比柱状图
  • 小白的进阶之路系列之五----人工智能从初步到精通pytorch张量
  • kibana解析Excel文件,生成mapping es导入Excel
  • Telegram平台分发其聊天机器人Grok
  • openfeignFeign 客户端禁用 SSL
  • 机顶盒CM311-5s纯手机免拆刷机,全网通,当贝桌面
  • 小表驱动大表更快吗,不是
  • RuoYi前后端分离框架集成手机短信验证码(一)之后端篇
  • 车载通信网络 --- 车载通信网络槪述
  • 计算机网络全维度解析:架构协议、关键设备、安全机制与新兴技术深度融合
  • Mysql中索引B+树、最左前缀匹配
  • LVS+KeepAlived
  • 【在线五子棋对战】一、项目简介 环境搭建
  • HTML实战:爱心图的实现
  • 本地Markdown开源知识库选型指南
  • 算法日记32:埃式筛、gcd和lcm、快速幂、乘法逆元
  • 基于esp32,控制IO1高低电平 和读取IO0按键的c程序
  • ByteBuddy入门:静态方法增强实战
  • 4.1.3 操作数据帧
  • 005 ElasticSearch 许可证过期问题
  • 深入剖析 Docker 容器化原理与实战应用,开启技术新征程!
  • VCS elab选项 -simprofile功能
  • 微软 Azure AI Foundry(国际版)十大重要更新
  • EXCEL中的TEXTJOIN用法(基础版),将Excel 多个单元格内容按条件合并到一个单元格