字符串函数和内存函数

文章目录

  • 字符串函数
    • strlen函数
      • 模拟实现
    • strcpy函数
      • 模拟实现
    • strcat函数
      • 使用
      • 模拟实现
    • strcmp函数
      • 使用
      • 模拟实现
    • strncpy函数
      • 使用
      • 模拟实现
    • strstr函数
      • 使用
      • 模拟实现
    • strtok函数
      • 使用
    • strerror函数
    • 使用
  • 内存函数
    • memset函数
    • 使用
    • memcmp函数
    • memcpy函数
      • 使用
      • 模拟实现
    • memmove函数
      • 使用
      • 模拟实现
    • 总结

字符串函数

strlen函数

size_t strlen ( const char * str );
返回值是size_t
头文件——#include<string.h>
计算字符串的长度
不包括\0

模拟实现

计数器

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

指针-指针

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

递归

#define  _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* str)
{assert(str);if (*str == '\0')return 0;elsereturn 1 + my_strlen(str+1);}
int main()
{char arr[] = { "abcdefg" };size_t n = my_strlen(arr);printf("%u\n", n);return 0;
}

strcpy函数

char * strcpy ( char * destination, const char * source );
dst是目标空间,src是要复制的内容
拷贝内容到指定对象中
要确保指定对象有足够大的空间去容纳,否则可能会导致缓冲区溢出
目标空间必须可修改,不可以是常量字符串;
源字符串必须以\0结束
复制会把src指向的字符串包括\0复制过去

模拟实现

#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{assert(dest && src);//确保不是野指针char* dest_ptr = dest;//初始化目标字符串的指针//遍历源字符串while (*src!='\0'){*dest_ptr++ = *src++;}//添加空终止字符*dest_ptr = '\0';return dest;
}int main()
{char src[] = "hahahaha";char dest[20];my_strcpy(dest, src);printf("%s\n", dest);return 0;
}

在这里插入图片描述

strcat函数

追加内容,连接两个字符串
会将src指向的字符串(不包括\0)复制过去
所以不能追加自己本身,会死循环
目标空间足够大
复制完后dest会自动添加’\0’;

使用

#include<stdio.h>
#include<string.h>
int main()
{char src[] = "hahahaha";char dest[20] = "lololo ";strcat(dest, src);printf("%s\n", dest);return 0;
}

在这里插入图片描述

模拟实现

#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{assert(dest && src);char* dest_end = dest;while (*dest_end != '\0'){dest_end++;}while (*src){*dest_end++ = *src++;}*dest_end = '\0';return dest;
}
int main()
{char src[] = "hahahaha";char dest[20] = "yayaya ";my_strcat(dest, src);printf("%s\n", dest);return 0;
}

在这里插入图片描述

strcmp函数

int strcmp ( const char * str1, const char * str2 );
== 返回值==
在这里插入图片描述
比较字符串的大小,逐个逐个比,比较的是ASCII值

使用

#include<stdio.h>
#include<string.h>
int main()
{char* p = "abc";char* q = "abd";int ret=strcmp(p,q);printf("%d", ret);return 0;
}

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

#include<string.h>
#include<assert.h>
int main()
{char* p = "abcf";char* q = "abc";int ret=strcmp(p,q);printf("%d", ret);return 0;
}

在这里插入图片描述

模拟实现

#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strcmp(const char* s1, char* s2)
{assert(s1 && s2);while(*s1==*s2){if(*s1=='\0')return 0;s1++;s2++;}/*if (*s1 > *s2){return 1;}elsereturn -1;*/return *s1 - *s2;
}
int main()  
{char* p = "abc";char* q = "abd";int ret=my_strcmp(p, q);/*printf("%d", ret);*/if (ret > 0){printf("p>q\n");}else if (ret == 0){printf("p=q\n");}else{printf("p<q\n");}return 0;}

strncpy函数

长度受限制
char * strncpy ( char * destination, const char * source, size_t num );
复制完成后dest目标字符串不会自动添加\0;需要手动确保dest以\0结尾
注意
如果src包含空字符,strcpy会停止复制,可能会导致目标字符串没有正确以空字符结尾

使用

#include<stdio.h>
#include<string.h>
int main()
{char src[] = "hahahaha";char dest[20];strncpy(dest, src, 5);dest[5] = '\0';printf("%s\n", dest);return 0;
}

在这里插入图片描述

模拟实现

#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* src,int n)
{assert(dest && src);char* dest_ptr = dest;while ((*src != '\0')&& n>0){*dest_ptr++ = *src++;--n;}if (*src == '\0'){while (n > 0){*dest_ptr++ = '\0';--n;}}*dest_ptr = '\0';return dest;
}int main()
{char src[] = "hahahaha";char dest[20];my_strcpy(dest, src,5);printf("%s\n", dest);return 0;
}

strstr函数

const char * strstr ( const char * str1, const char * str2 );
char * strstr ( char * str1, const char * str2 );
字符串查找
用于在字符串中搜索子字符串,并返回子字符串第一次出现的位置。如果找不到子字符串,则返回 false

使用

int main()
{const char* p = "abcdff";;char* ret=strstr(p, "bcd");if (ret != NULL){printf("存在");}elseprintf("不存在");return 0;
}

模拟实现

#include<stdio.h>
#include<assert.h>
char* my_strstr(const char* s1, const char*s2)//const确保s1.s2不动,刚开始的起始位置不变,要创建新的
{assert(s1 && s2);const char* str1 = s1;const char* str2 = s2;const char* p = s1;while (*p){str1= p;//p赋值给srt1,p就不动先str2 = s2;while (str1!='\0'&&str2!='\0' && *str1 == *str2){str1++;str2++;}if (*str2 == '\0'){return p;//返回搜索到的起始位置}p++;}
}
int main()
{char arr1[] = { "hellowuwen" };char arr2[] = { "lo" };char* ret = my_strstr(arr1, arr2);if (ret == NULL){printf("子串不存在\n");}else{printf("%s\n",ret);}return 0;
}

在这里插入图片描述

strtok函数

char * strtok ( char * str, const char * delimiters );
delim为分隔符字符(如果传入字符串,则传入的字符串中每个字符均为分割符)
函数返回值
成功:返回被分割出的字符串
失败:NULL
传入NULL,会在原来保存的位置继续往下找

使用

#include<stdio.h>
#include<string.h>
int main()
{const char* sep = ",.";char arr[] = "anfnvbj,nsndu.vns";char copy[30] = { 0 };strcpy(copy, arr);//char* ret = strtok(copy, sep);//if(ret!=NULL)//printf("%s\n", ret);//有记忆功能,就像static静态变量一样,出了函数变量不销毁,一直都在//ret=strtok(NULL, sep);//传NULL是为了继续往下找//printf("%s\n", ret);//ret = strtok(NULL, sep);//printf("%s\n", ret);//简化char* ret = NULL;for (ret = strtok(copy, sep); ret != NULL; ret = strtok(NULL, sep)){printf("%s\n", ret); }return 0;
}

strerror函数

char * strerror ( int errnum );
返回错误信息
必须包含的头文件include<error.h>
C语言的库函数,返回失败都会设置错误码

使用

举例,打开文件
FILE * fopen ( const char * filename, const char * mode );
一定要有#include<errno.h>

#include<errno.h>
int main()
{FILE* pf = fopen("test.text", "r");//同个文件夹里的相对路径if (pf == NULL){printf( "%s\n",strerror(errno));return 1;}else{}return 0;}

在这里插入图片描述

内存函数

memset函数

void * memset ( void * ptr, int value, size_t num );
用于将一段内存中的所有字节设置为特定的值。
初始化数组或者内存块
字节为单位来进行初始化

使用

#include<stdio.h>
#include<string.h>
int main()
{char arr[] = "hello wuwen";memset(arr + 6, 'd', 4);printf("%s\n", arr);
}

在这里插入图片描述

memcmp函数

int memcmp ( const void * ptr1, const void * ptr2, size_t num );
size_t num是要比较的最大字节数
区别strcmp:strcmp只作用与字符串,memcmp作用于任何类型

#include<stdio.h>
#include<string.h>
int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[] = { 1,4,2 };int ret=memcmp(arr1, arr2, 12);if (ret < 0){printf("arr1<arr2");}else if (ret == 0){printf("arr1=arr2");}elseprintf("arr1>arr2");return 0;
}

在这里插入图片描述

memcpy函数

void * memcpy ( void * destination, const void * source, size_t num );
size_t num是要复制的字节数

使用

#include<stdio.h>
#include<string.h>
int main()
{int  arr[] = { 1,2,3,4,5 };int dest[6] = { 0 };memcpy(dest, arr,20);for (int i = 0; i < 5; i++){printf("%d ", dest[i]);}return 0;
}

但是要在原数组里复制可行吗?
eg:memcpy(arr,arr+2,12),打印出来是3,4,5,4,5
也就是说在vs里对于内存覆盖的复制是可行的,但实际上呢
我们通过测试会发现,memcpy不能复制源和目标内存区域重叠的数组

模拟实现

#include<stdio.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;//dest是void*类型,不能直接解引用,不能直接+-;src=(char*)src+1;}return ret;//不能直接return dest,dest已经被++了//由于返回是目的的地址,所以要保存一下
}
int main()
{int src[] = { 1,2,3,4,5,6,7,8,9,10 };int dest[20] = { 0 };my_memcpy(dest, src, 24);for (int i = 0; i < 6; i++){printf("%d ", dest[i]);}return 0;
}

测试下能不能复制同内存的
本应该是1 2 1 2 3 4 5 6 9 10
在这里插入图片描述
所以有可能会复制不了,这是从前往后复制的,那从后往前呢?
在这里插入图片描述
是可以的,这就相当于是memmove

memmove函数

void * memmove ( void * destination, const void * source, size_t num );
memmove很好的解决了memcpy内存覆盖的问题

使用

#include<stdio.h>
#include<string.h>
int main()
{int src[] = { 1,2,3,4,5,6,7,8,9,10 };//int dest[20] = { 0 };memmove(src+2, src, 24);for (int i = 0; i < 10; i++){printf("%d ", src[i]);}return 0;
}

在这里插入图片描述

如何实现呢?

在这里插入图片描述

看重叠部分是被拷贝数据的前半部分还是后半部分

模拟实现

#include<stdio.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;//dest是void*类型,不能直接解引用,不能直接+-;src = (char*)src + 1;}}else{while (num--){*((char*)dest + num) = *((char*)src + num);}}return ret;
}
int main()
{int src[] = { 1,2,3,4,5,6,7,8,9,10 };//int dest[20] = { 0 };my_memmove(src+2, src, 24);for (int i = 0; i < 10; i++){printf("%d ", src[i]);}return 0;
}

总结

看完相信你对字符串函数和内存函数有了一定认识,有什么问题欢迎在评论区指出来~
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/520269.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机二级 第2套

一、选择题 二、编程题

工作纪实46-关于微服务的上线发布姿势

蓝绿部署 在部署时&#xff0c;不需要将旧版本的服务停掉&#xff0c;而是将新版本与旧版本同时运行&#xff0c;新版本测试无误之后再将旧版本停掉。这样可以避免再升级的过程中如果失败服务不可用的问题&#xff0c;因为同时部署了两个版本的程序&#xff0c;使得硬件资源是…

如何在Linux系统Docker部署Dashy并远程访问内网服务界面

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【排序算法】深入理解快速排序算法:从原理到实现

目录 1. 引言 2. 快速排序算法原理 3. 快速排序的时间复杂度分析 4. 快速排序的应用场景 5. 快速排序的优缺点分析 5.1 优点&#xff1a; 5.2 缺点&#xff1a; 6. Java、JavaScript 和 Python 实现快速排序算法 6.1 Java 实现&#xff1a; 6.2 JavaScript 实现&#…

稀疏数组实现

博文主要是自己学习的笔记&#xff0c;供自己以后复习使用&#xff0c; 参考的主要教程是B站的 尚硅谷数据结构和算法 稀疏数组(sparse array) 实际需求&#xff1a;五子棋程序中的存盘退出和续上盘的功能 问题分析&#xff1a; 如果直接用二维数组&#xff0c;很多值是默认…

SqlServer如何查询mdf的数据库版本

问题描述 今天附件数据库一直报错&#xff0c;百思不得其姐。最后发现可能数mdf数据库版本太低了&#xff0c;那么如何查询mdf文件的数据库版本呢&#xff1f; 解决方案&#xff1a; DBCC CHECKPRIMARYFILE(C:\Program Files\Microsoft SQL Server\MSSQL16.MSSQLSERVER\MSSQL…

【Unity】【VR开发】用控制器摇杆改变Canvas的大小和位置

【背景】 做一个VR投屏工具,希望能够用右手控制器的摇杆,前后控制Canvas距离,左右控制Canvas大小。 【分析】 需要解决几个问题: 获取摇杆在横纵轴方向上的输入值需要通过合适的Event触发改变Canvas大小和距离的函数写具体的Canvas改变大小和距离的功能【技术选型】 VR…

Gin 获取请求参数

POST 请求参数 Gin 获取Post请求URL参数有三种方式 func (c *Context) PostForm(key string) string func (c *Context) DefaultPostForm(key, defaultValue string) string func (c *Context) GetPostForm(key string) (string, bool)大多数情况下使用的是application/x-www…

Cloud-Eureka服务治理-Ribbon负载均衡

构建Cloud父工程 父工程只做依赖版本管理 不引入依赖 pom.xml <packaging>pom</packaging><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.9.RELEA…

【嵌入式——QT】Model/View

【嵌入式——QT】Model/View 基本原理数据模型视图组件代理Model/View结构的一些概念QFileSystemModelQStringListModelQStandardItemModel自定义代理 基本原理 GUI应用程序的一个很重要的功能是由用户在界面上编辑和修改数据&#xff0c;典型的如数据库应用程序&#xff0c;数…

【ArcGIS Pro二次开发】(84):WPF_给Combobox加点料

一、要实现的功能 在WPF中&#xff0c;一个正常的Combobox是长这样的&#xff1a; 当点击下拉框的时候&#xff0c;下拉列表就是简单的文本&#xff0c;看起来很单一。 这里我们给它加点料&#xff0c;让它变成这样&#xff1a; 就是给文本前面加个图标&#xff0c;这个图标可…

高精度减法

#include<iostream> #include<vector>using namespace std;//判断是否有A>B, bool cmp(vector<int> &A,vector<int> &B) {if(A.size()!B.size()) return A.size()>B.size();for(int iA.size()-1;i>0;i--)if(A[i]!B[i])return A[i]>…