字符串和内存函数

目录

strlen

模拟实现

长度不受限字符串函数 

strcpy

模拟实现

​编辑 strcat

模拟实现

 strcmp

 模拟实现

长度受限字符串函数

strncpy

模拟实现

strncat

strncmp

strstr 

模拟实现

 strtok

strerror

perror

字符分类函数

字符转换

示例:

​编辑内存函数

memcpy

模拟实现 

memmove

 模拟实现

memcmp

 memset


strlen

功能:统计字符串中\0之前的字符个数。

注意:如果没有\0则返回一个随机值

易错: 

 

strlen的返回值为size_t,也就是无符号整形,使用时要注意这点。 

模拟实现

#include <assert.h>
size_t my_strlen(const char* str)
{assert(str);const char* start = str;const char* end = str;while (*end != '\0'){end++;}return end - start;
}

长度不受限字符串函数 

strcpy

功能:将一个源头字符串拷贝到一个目标字符串中

注意:如果源头字符串没有\0则会报错。目标空间要足够大,且可变

 易错:

	char* p = "hello";//常量字符串char arr[] = "world";strcpy(p, arr);

模拟实现

char* my_strcpy(char* dest, const char* src)
{assert(dest);assert(src);char* str = dest;while (*dest++ = *src++)\\取巧写法,注意后置++不会对程序产生影响{;}return str;//能够被接收
}

测试结果: 

 strcat

功能:在一个字符串后面追加另一个字符串。

注意:目标空间要足够大,且可变。都需要包含\0

易错:

 追加位置在\0处:

模拟实现

char* my_strcat(char* dest, const char* src)
{assert(dest);assert(src);char* str = dest;while (*dest)//\0处追加,循环体内++{dest++;}while (*dest++ = *src++){;}return str;
}

注意不要利用strcat去追加自身,否则会造成死循环!

 strcmp

功能:比较字符串对应位置的ascii码大小

注意:都要包含\0。

 模拟实现

//写法1
int my_strcmp(const char* s1, const char* s2)
{assert(s1 && s2);while (*s1 == *s2){if (*s1 == '\0')//全等{return 0;}s1++;s2++;}if (*s1 > *s2)return 1;else return -1;
}
//写法2
int my_strcmp(const char* s1, const char* s2)
{assert(s1 && s2);while (*s1 == *s2){if (*s1 == '\0'){return 0;}s1++;s2++;}return *s1 - *s2;
}

长度受限字符串函数

strncpy

模拟实现

模拟实现一次,后续不再模拟实现。

具体逻辑是用一个无符号整数加入循环条件,如果需要拷贝的源头字符串超过了自身长度可以考虑给多余的地方拷贝\0。 

char* my_strncpy(char* dest, const char* src,size_t size)
{assert(dest);assert(src);char* str = dest;while (size && (*dest++ = *src++))//=优先级最低,所以加(){size--;}if(size)	//超出源头字符串长度while (--size){*dest++ = '\0';size--;}return str;
}

strncat

将n个子串拷贝到目标字符串后,自动补\0,可以自己增添自己。

strncmp

比较n个子串的大小,大于返回正数,小于返回负数,等于返回0。

 

strstr 

查找一个字符串里的子串,返回首次匹配所有子串的目标字符串中相应字符串的首地址。

模拟实现

法一:我的逻辑是能不能用strncmp负责比较字符串,用一个指针去遍历目标数组,注意结束条件为\0。但这样做有个漏洞,一次性比较多个字符串势必有越界的情况,我们以\0为突破口,能不能用它们的地址进行比较?于是思路就出现了。

char* my_strstr(const char* str1, const char* str2)
{assert(str1);assert(str2);const char* ptr = str1;int len1 = strlen(str1);int len2 = strlen(str2);while (strncmp(str1, str2, len2)!=0 && str1){if (str1 + len2 > ptr + len1){return NULL;}str1++;}return (char*)str1;
}

法二:四指针遍历法。两指针负责移动,两指针负责记录。

char* my_strstr(const char* str1, const char* str2)
{assert(str1);assert(str2);const char* p = str1;const char* src = str2;while (*p){str1 = p;str2 = src;while (*str1 != '\0' && *str2 != '\0' && * str1 == *str2)//注意\0{str1++;str2++;}if (*str2 == '\0'){return (char*)p;}p++;}return NULL;
}

 strtok

功能:分隔字符串,strtok函数找到str的下一个标记,并将其用\0替换,返回一个指向这个标记的指针。

注意:strtok会改变原数据的内容!一般修改临时拷贝的内容。

 

使用方法:

  • 第一个参数传字符串,第二个参数传字符串里分隔符
  • 第一个参数首次传递不为空,通过strtok函数找到指定分隔符位置后,将其替换成\0并记录下它的地址再返回回去,后面第一个参数一律为NULL(否则重置),从被保存的位置开始查找下一个分隔符所在位置。
  • 如果本次找不到分隔符,就返回NULL。

 测试:

 发现确实实现了分割并返回,但并不完全,我们可以写个循环:

strerror

功能:当函数调用失败时,将错误码(errno)转换成对应的错误信息或指向对应的地址。

perror

等价于printf + strerror函数,如需打印可以使用这个函数。

字符分类函数

int isalnum(int c):检查字符是否为数字或字母;(0~9,a~z,A~Z) 
int isalpha(int c):检查字符是否为字母;(a~z, A~Z) 
int iscntrl(int c):检查字符是否为控制字符;(八进制000~037以及177的字符) 
int isdigit(int c):检查字符是否为十进制数字;(0~9) 
int isgraph(int c):检查字符是否为图形表示,依赖于使用语言的环境;0~9,a~z,A~Z,以及标点符号) 
int islower(int c):检查字符是否为小写的字母;(a~z) 
int isprint(int c):检查字符是否为可打印的;(数字、字母、标点符号、空白字符) 
int ispunct(int c):检查字符是否为标点符号;(! ” # $ % & ’ ( ) * + , - . / : ; < = > ? @ [ ] ^ _ ` { | } ~等) 
int isspace(int c):检查字符是否为空白字符;(TAB、换行、垂直TAB、换页、回车、空格) 
int isupper(int c):检查字符是否为大写字母;(A~Z) 
int isxdigit(int c):检查字符是否为十六进制数字;(0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f) 

字符转换

int tolower(int c):转化字符为小写字母; 
int toupper(int c):转化字符为大写字母;

示例:


内存函数

memcpy

功能: 将一个内存空间的数据按字节复制到另一块空间。

模拟实现 

void* my_memcpy(void* dest, void* src, size_t num)
{void* ret = dest;assert(dest);assert(src);while(num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return ret;
}

memmove

使用memcpy拷贝空间出现重叠时分两种情况:

memcpy显然只能从一方进行拷贝,如果出现另一种情况,则会存在内存覆盖现象。而memmove的作用就是对重叠空间进行拷贝。(有些编译器memcpy可以实现重叠拷贝)

字符串重叠空间拷贝用memmove代替strncpy。

 模拟实现

void* my_memmove(void* dest, void* src, size_t num)
{assert(dest);assert(src);//(char*)dest++;不能这样写,强制暂时改变了类型,void*无法自增void* ret = dest;//从前往后if (src > dest){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;
}

 测试:

memcmp

内存比较函数,不多赘述。 

 memset

字节初始化内存空间。

测试: 

 

由于小端的存储方式,我们修改前9个字节实则将前3个整形变量修改成了0。 

 

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

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

相关文章

Net相关的各类开源项目

Net相关的各类开源项目 WPFHandyControlLive-ChartsWPFDeveloperswpf-uidesignStylet WebScheduleMasterYiShaAdminBlog.CoreNebula.AdminNewLife.CubeOpenAuth UnityuGUIUnityCsReferenceEpitomeMyUnityFrameWorkKSFrameworkTowerDefense-GameFramework-Demo 通用ClientServer…

SRTP交叉编译与移植

1 SRTP源码下载 源码下载在github采用的库为libsrtp2.5.0: weget https://github.com/cisco/libsrtp/archive/refs/tags/v2.5.0.tar.gz2 SRTP交叉编译 新增交叉编译脚本&#xff0c;这里需要支持openssl。 ./configure --hostarm-linux-androideabi --prefix$(pwd)/object …

《视觉 SLAM 十四讲》V2 第 6 讲 非线性优化 【高斯牛顿法、列文伯格-马夸尔特方法 、Ceres 库 和 g2o库 】

文章目录 6.1.2 最小二乘 寻找下降增量 Δ x k \Delta\bm{x}_k Δxk​的 4 种方法6.2.1 一阶和二阶梯度法(最速下降法、牛顿法)6.2.2 高斯牛顿法6.2.3 列文伯格-马夸尔特方法 【阻尼牛顿法】【信赖区域法】 6.3 实践6.3.1 手写高斯牛顿法 【Code】6.3.2 谷歌的优化库 Ceres 【最…

Linux自用笔记

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Linux相关 ✨特色专栏&#xff1a; My…

RabbitMQ核心总结

AMQP协议核心概念 RabbitMQ是基于AMQP协议的&#xff0c;通过使用通用协议就可以做到在不同语言之间传递。 server&#xff1a;又称broker&#xff0c;接受客户端连接&#xff0c;实现AMQP实体服务。 connection&#xff1a;连接和具体broker网络连接。 channel&#xff1a…

redis学习(二)——redis常见命令及基础数据类型

数据类型 基础数据类型 字符串 String abcMap集合 Hsah {name:“zhangsan”,age:18}列表 List [a, b, c, d]Set集合 Set {a,b,c}有序Set集合 SortSet {a:1,b:2,c:3} 特殊数据类型 GEO 地理坐标 {A:(100.2,35.1)}BitMap 位图&#xff0c;只存储0和1 01101011101HyperLog 基数…

软件设计师_数据结构与算法_学习笔记

文章目录 6.1 数组与矩阵6.1.1 数组6.1.2 稀疏矩阵 6.2 线性表6.2.1 数据结构的定义6.2.2 顺序表与链表6.2.2.1 定义6.2.2.2 链表的操作 6.2.3 顺序存储和链式存储的对比6.2.4 队列、循环队列、栈6.2.4.2 循环队列队空与队满条件6.2.4.3 出入后不可能出现的序列练习 6.2.5 串 6…

【Spring笔记02】Spring中的IOC容器和DI依赖注入介绍

这篇文章&#xff0c;主要介绍一下Spring中的IOC容器和DI依赖注入两个概念。 目录 一、IOC控制反转 1.1、什么是IOC 1.2、两种IOC容器 &#xff08;1&#xff09;基于BeanFactory的IOC容器 &#xff08;2&#xff09;基于ApplicationContext的IOC容器 二、DI依赖注入 2.…

【Python】读取显示pgm图像文件

文章目录 零. 前言一. pgm基本概念二. pgm基本信息读取三. pgm图像渲染四. 代码优化 零. 前言 这学期要学多媒体信息隐藏对抗&#xff0c;发现其中的图像数据集文件都是pgm文件形式的。虽然是图像文件&#xff0c;但是却不能直接通过图像查看器来打开&#xff0c;上网一搜&…

大模型 Decoder 的生成策略

本文将介绍以下内容&#xff1a; IntroductionGreedy Searchbeam searchSamplingTop-K SamplingTop-p (nucleus) sampling总结 一、Introduction 1、简介 近年来&#xff0c;由于在数百万个网页数据上训练的大型基于 Transformer 的语言模型的兴起&#xff0c;开放式语言生…

怎么利用互联网赚钱,网上赚钱的7种方法

互联网的兴起改变了我们的生活方式&#xff0c;不仅让我们的世界更为便捷&#xff0c;也为我们提供了赚钱的机会。越来越多的人开始通过互联网实现财富梦想。你是否曾想过&#xff0c;如何利用互联网来赚钱呢&#xff1f;今天&#xff0c;我将为大家分享七种赚钱方法&#xff0…

Leetcode hot 100之双指针(快慢指针、滑动窗口)

目录 数组 有序的平方仍有序 删除/覆盖元素 移动零&#xff1a;交换slow和fast 滑动窗口&#xff1a;最短的连续子串&#xff08;r可行解->l--最短解&#xff09; 最小长度的子数组 求和&#xff1a;sort、l i 1, r len - 1 三数之和abctarget 四数之和abcdtarg…