字符函数和字符串函数


字符串以'\0'为结束标志,strlen函数返回的是’\0’前的字符个数,不包括'\0'
参数的指向的字符串必须是'\0'为结束标志,不然结果不确定
函数的返回类型是size_t(无符号的整型)
strlen的使用
#include <stdio.h>
#include <string.h>int main()
{char arr1[] = "hello world!";size_t ret = strlen(arr1);printf("%u", ret);return 0;
}
strlen的模拟使用
#include <stdio.h>int my_strlen(char* p)
{int sz = 0;while (*p){p++;sz++;}return sz;
}int main()
{char arr[] = "abcde";int sz=my_strlen(arr);printf("%d\n", sz);return 0;
}
易错点strlen的返回值是size_t
eg
#include <stdio.h>
#include <string.h>int main()
{const char* str1 = "abcdef";const char* str2 = "abc";if (strlen(str2) - strlen(str1) > 0){printf("str2>str1");}else{printf("str1>str2");}return 0;
}
stlen(str2)返回3,strlen(str1)返回6,3-6=-3,但是-3是无符号数>0,所以if里面的条件是真的
strcpy函数

原字符串必须以'\0'结束
会将原字符串的''\0'拷贝到目标空间
目标空间必须足够大,以确保可以存放源字符串
目标空间必须可变
学会模拟实现
strcpy的使用
#include <stdio.h>
#include <string.h>
int main()
{char arr1[100] = "123456789";char arr2[10] = "abcdef";strcpy(arr1, arr2);puts(arr1);return 0;
}

将arr2复制到arr1,覆盖了arr1原本的内容
strcpy的模拟实现
#include <stdio.h>
#include <string.h>void my_strcpy(char* arr1, char* arr2)
{while (*arr2){*arr1 = *arr2;arr1++;arr2++;}*arr1 = *arr2;
}
int main()
{char arr1[100] = "123456789";char arr2[10] = "abcdef";my_strcpy(arr1, arr2);puts(arr1);return 0;
}
strcat函数

源字符串必须以'\0'结束
目标空间必须足够大,能容纳下源字符串的内容
目标空间必须可以修改
字符串自己给自己追加,如何
strcat的实现
#include <stdio.h>
#include <string.h>int main()
{char arr1[100] = "12345";char arr2[10] = "6789";strcat(arr1, arr2);puts(arr1);return 0;
}

strcat函数的模拟实现
#include <stdio.h>
#include <string.h>void my_strcat(char* arr1, char* arr2)
{while (*arr2){if (*arr1 == '\0'){*arr1 = *arr2;arr2++;}arr1++;}arr1 = arr2;
}int main()
{char arr1[100] = "12345";char arr2[10] = "6789";my_strcat(arr1, arr2);puts(arr1);return 0;
}
自己给自己追加会发生什么

说明自己给自己追加是行不通的
strcmp函数

标准规定:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
sttrcmp函数的实现
#include <stdio.h>int main()
{char arr1[] = "abcd";char arr2[] = "abaa";int val = strcmp(arr1, arr2);printf("%d\n", val);return 0;
}

比较的是每一位字符对应的ASCII码值,c的ASCII码值大于a的,所以我们返回一个大于0的数字
strcmp的模拟实现
#include <stdio.h>int my_strcmp(const char* arr1, const char* arr2)
{while (*arr1 != '\0' || *arr2 != '\0'){if (*arr1 > *arr2){return 1;}if (*arr1 < *arr2){return -1;}arr1++;arr2++;}return 0;
}int main()
{char arr1[] = "abcd";char arr2[] = "abdd";int val = my_strcmp(arr1, arr2);printf("%d\n", val);return 0;
}
strncpy函数

拷贝num个字符从源字符到目标空间
如果源字符串长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个
strncpy函数的实现
#include <stdio.h>
#include <string.h>
int main()
{char arr1[100] = "abcdefghijklnm";char arr2[100] = "123456789";strncpy(arr1, arr2, 5);printf("%s\n", arr1);return 0;
}

对比strcpy与strncpy

发现strcpy是将arr2的全部放到arr1,arr1原来的字符不见了
strncpy是将num个字符从第1个字符开始从arr1开始替代,没有替代的字符不改变,而strcpy替代后,后面的字符变成了0
strncpy函数的模拟
#include <stdio.h>
#include <string.h>void my_strncpy(char* arr1, char* arr2, size_t num)
{while(num){ *arr1 = *arr2;arr1++;arr2++;num--;}
}int main()
{char arr1[100] = "abcdefgh";char arr2[100] = "123456789";my_strncpy(arr1, arr2, 5);printf("%s\n", arr1);return 0;
}
strncat函数

strncat的实现
#include <stdio.h>
#include <string.h>int main()
{char arr1[100] = "12345";char arr2[100] = "abcdefg";strncat(arr1, arr2, 3);printf("%s\n",arr1);return 0;
}
strncat与strcat的区别

strcat是将arr2全部的字符追加到arr1后面。strncat是将arr2里面num个字符追加到arr1
strncat的模拟实现
#include <stdio.h>
#include <string.h>void my_strncat(char* arr1,char* arr2,size_t num)
{while (num){if (*arr1 == '\0'){*arr1 = *arr2;arr2++;num--;}arr1++;}
}
int main()
{char arr1[100] = "12345";char arr2[100] = "abcdefg";my_strncat(arr1, arr2, 3);printf("%s\n",arr1);return 0;
}
strncmp函数

比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完
strncmp的实现
#include <stdio.h>
#include <string.h>int main()
{const char* arr1 = "abcdefg";const char* arr2 = "abab";int val=strncmp(arr1, arr2, 4);printf("%d\n", val);return 0;
}
strcmp与strncmp的区别

比较法则strncmp与strcmp一样,都是比较ASCII码,strcmp的比较,如果得不到结果,一直比较到最后一个字符,而strncmp比较字符,只比较到num个就结束了。
strncmp的模拟实现
#include <stdio.h>
#include <string.h>int my_strncmp(const char* arr1, const char* arr2, size_t num)
{while (num){if (*arr1 > *arr2){return 1;}if (*arr1 < *arr2){return -1;}arr1++;arr2++;num--;}return 0;
}int main()
{const char* arr1 = "abadefg";const char* arr2 = "abcb";int val=my_strncmp(arr1, arr2, 4);printf("%d\n", val);return 0;
}
strstr函数

strstr函数的实现
#include <stdio.h>
#include <string.h>int main()
{char arr1[] = "123abc456efg";char arr2[] = "abc";char* ret = NULL;ret = strstr(arr1, arr2);puts(ret);return 0;
}

在字符串arr1中查找字符串arr2,查到后返回查到字符串的首地址
如果查不到呢

返回一个空指针
strstr模拟实现
#include <stdio.h>
#include <string.h>char* my_strstr(const char* arr1, const char* arr2)
{char* s1 = NULL;char* s2 = NULL;char* pc = arr1;while (*pc){s1 = pc;s2 = arr2;while (*s1 && *s2 && * s1 == *s2){s1++;s2++;}if (*s2 == '\0'){return pc;}pc++;}return NULL;
}int main()
{char arr1[] = "abcdefabcdef";char arr2[] = "def";char* ret = NULL;ret = my_strstr(arr1, arr2);if (ret != NULL){puts(ret);}return 0;
}
strchr函数

strchr函数的实现
#include <stdio.h>
#include <string.h>
int main()
{const char* arr = "abcdefg";const char ch = 'c';char* tmp = NULL;tmp = strchr(arr, ch);puts(tmp);return 0;
}

在字符串arr中查找字符’c',返回字符串arr中c的地址
strchr模拟实现
#include <stdio.h>
#include <string.h>char* my_strchr(const char* arr, const char ch)
{while (*arr){if (*arr == ch){return arr;}arr++;}return NULL;
}int main()
{const char* arr = "abcdefg";const char ch = 'c';char* tmp = NULL;tmp = my_strchr(arr, ch);puts(tmp);return 0;
}
strtok函数

delimited参数是个字符串,定义了用作分隔符的字符集合
strtok函数找到str中的下一个标记,并将其用'\0'结尾,返回一个指向这个标记的指针.(注:strtok函数会改变操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存其在字符串中的位置
strtok函数的第一个参数为NULL,函数将在同一个字符串被保存的位置开始,查找下一个标记
如果字符串不存在更多的标记,则返回NULL指针
strtok函数的实现
#include <stdio.h>
#include <string.h>int main()
{char* p = "1186888586@qq.com";const char* delimited = "@.";char* str = NULL;char arr[100] = {'0'};strcpy(arr, p);for (str = strtok(arr, delimited); str != NULL; str = strtok(NULL, delimited)){puts(str);}return 0;
}
利用·strcpy拷贝一份我们要用来查到的字符串
查到了返回查到之前起始位置的地址,将查到的字符置为'\0'
查不到返回一个空指针
查到后,下一次查找,第一个参数使用空指针
strerror函数

strerror函数的实现
#include <stdio.h>
#include <errno.h>
int main()
{FILE* pf = NULL;pf = fopen("test.txt", "r");if (NULL == pf){printf("%s\n", strerror(errno));}return 0;
}


通常我们打印错误信息还可以使用perror函数
#include <stdio.h>
#include <errno.h>
int main()
{FILE* pf = NULL;pf = fopen("test.txt", "r");if (NULL == pf){perror("fopen:");}return 0;
}

memcpy函数

函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存
这个函数在遇到'\0'的时候并不会停下来
如果source和destination有任何的重叠,复制的结果都是未定义的
#include <stdio.h>
#include <string.h>
int main()
{int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 11,12,13,14,15,16,17,18,19,20 };memcpy(arr1, arr2, 20);for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++){printf("%d ", arr1[i]);}return 0;
}

将arr2内的20个字节复制到arr1中
memcpy一般不做重叠的拷贝,即自己给自己拷贝
strcpy只能拷贝字符,memcpy可以拷贝所以类型的元素
memcpy函数的模拟
#include <stdio.h>
#include <string.h>void* my_memcpy(void* arr1, const void* arr2, size_t num)
{void* tmp = arr1;while (num){*(char*)arr1 = *(char*)arr2;arr1 = (char*)arr1 + 1;arr2 = (char*)arr2 + 1;num--;}return tmp;
}int main()
{int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 11,12,13,14,15,16,17,18,19,20 };my_memcpy(arr1, arr2, 20);for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++){printf("%d ", arr1[i]);}return 0;
}
自身拷贝推荐使用memmove函数,在vs中memcpy函数的设计与memmove一样,但是在其他平台我们不能保证,所以我们拷贝时可以统一使用memmove函数
memmove函数

和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的
如果源空间和目标空间出现重叠,就是使用memmove函数处理
memmove函数的实现
#include <stdio.h>
#include <string.h>int main()
{int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 11,12,13,14,15,16,17,18,19,20 };memmove(arr1, arr1 + 2, 20);for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++){printf("%d ", arr1[i]);}return 0;
}
memmove的模拟实现
#include <stdio.h>
#include <string.h>void* my_memmove(void* dest, void* src, size_t num)
{void* tmp = dest;if (*(char*)dest < *(char*)src){while (num){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;num--;}}else{while (num){*((char*)dest+num) = *((char*)src+num);num--;}*((char*)dest + num) = *((char*)src + num);}return tmp;
}int main()
{int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 11,12,13,14,15,16,17,18,19,20 };my_memmove(arr1+2, arr1 , 20);for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++){printf("%d ", arr1[i]);}return 0;
}
memcmp函数

比较从ptr1和ptr2指针开始的num个字节

memcmp的实现
#include <stdio.h>
#include <string.h>int main()
{const char* p1 = "abcd";const char* p2 = "abad";printf("%d\n", memcmp(p1, p2, 4));int arr1[] = { 1,2,3,4 };int arr2[] = { 1,2,3,5 };printf("%d\n", memcmp(arr1, arr2, 16));return 0;
}

strcmp函数可以比较字符串,memcmp可以比较内存中所以类型的元素
memset函数

memset函数的实现
#include <stdio.h>
#include <string.h>int main()
{char arr[] = "hello world!";memset(arr, '*', 5);puts(arr);return 0;
}
将arr1字符串的5个字节置为'*'
#include <stdio.h>
#include <string.h>int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };memset(arr, 1, 40);return 0;
}
memset可以将10个元素置为1吗
memset是按字节处理,每一个直接都置为1,int类型占4个字节明显它不能将10个元素置为1

相关文章:

字符函数和字符串函数
字符串以\0为结束标志,strlen函数返回的是’\0’前的字符个数,不包括\0参数的指向的字符串必须是\0为结束标志,不然结果不确定函数的返回类型是size_t(无符号的整型)strlen的使用#include <stdio.h> #include <string.h&…...

【猜名次】-C语言-题解
1. 描述: 5位运动员参加了10米台跳水比赛,有人让他们预测比赛结果: A选手说:B第二,我第三; B选手说:我第二,E第四; C选手说:我第一,D第二&#x…...
对 equals() 和 hashCode() 的理解?
在 java.lang.Object 类中有两个非常重要的方法: public native int hashCode(); public boolean equals(Object obj) {return (this obj); }Object 类是类继承结构的基础,是每一个类的父类,都实现了Object 类中定义的方法。 equals()方法…...

IDEA插件安装慢、超时、不成功问题如何解决?
目录 一、打开国内插件的节点IP地址 二、修改本地hosts文件 三、刷新DNS缓存 一、打开国内插件的节点IP地址 国内插件的节点IP地址查询: http://tool.chinaz.com/speedtest/plugins.jetbrains.com 在下方的检测结果中,找到一个解析时间最短的IP地址,解…...
软考高级之信息系统案例分析七重奏-《5》
五十、项目需求管理可能存在的问题。 1、未制定项目需求管理计划; 2、项目沟通存在问题; 3、项目经理缺乏必要的项目管理经验; 4、没有有效地管理需求变更控制; 5、没有有效地维护对需求进行跟踪管理; 6、没有按照规范的需求开发和需求管理的内容和流程开展需求工作…...

JUC并发编程 Ⅳ -- 共享模型之无锁
文章目录CAS 与 volatile问题引入代码分析volatile为什么无锁效率高CAS特点原子整数原子引用ABA 问题及解决原子数组原子(字段)更新器原子累加器UnsafeUnsafe CAS 操作管程即 monitor 是阻塞式的悲观锁实现并发控制,本文我们将通过非阻塞式的乐观锁的来实现并发控制…...
Spring之AOP实现
1. AOP的实现方式 使用AspectJ的编译器来改动class类文件实现增强(使用不广泛) ----- 编译阶段 这种对class类文件增强的, 也可以增强static静态方法, 而通过代理方式就无法实现静态方法的增强 可通过查看编译后class文件反编译后的java代码验证 agent增强(使用不广泛) ----- 类…...

Spring之基于xml的自动装配、基于Autowired注解的自动装配
文章目录基于xml的自动装配①注解②扫描③新建Maven Module④创建Spring配置文件⑤标识组件的常用注解⑥创建组件⑦扫描组件⑧测试⑨组件所对应的bean的id基于注解的自动装配①场景模拟②Autowired注解③Autowired注解其他细节④Autowired工作流程Autowire 注解的原理Qualifier…...
【案例】--(非分布式)轻量级任务调度平台
目录 一、前言说明二、背景2.1、完成任务,顺便搭建了一个任务调度平台三、具体实现解析3.1、技术栈等选型3.2、完成具体功能解析(1)、支持基本任务功能(2)、支持日志收集功能(3)、支持用户异常,选择性关闭调度功能(4)、实时监控正在执行和任务队列的任务情况(5)、实时监控任务…...

key的作用原理与列表的遍历、追加、搜索、排序
目录 一、key的作用原理 二、实现列表遍历并对在列表最前方进行追加元素 三、实现列表过滤搜索 1、用computed计算属性来实现 2、用watch监听输入值的变化来实现 四、按年龄排序输出列表 一、key的作用原理 1. 虚拟DOM中key的作用: key是虚拟DOM对象的标识&a…...

SQL性能优化的47个小技巧,你了解多少?
收录于热门专栏Java基础教程系列(进阶篇) 1、先了解MySQL的执行过程 了解了MySQL的执行过程,我们才知道如何进行sql优化。 客户端发送一条查询语句到服务器;服务器先查询缓存,如果命中缓存,则立即返回存…...

DPDK — 数据加速方案的核心思想
目录 文章目录 目录DPDK 数据加速方案1、使用用户态协议栈来代替内核协议栈Linux UIO FrameworkDPDK UIO Framework2、使用轮训来代替中断Kernelspace igb_uio DriverUserspace PMD3、使用多核编程代替多线程无锁环队列:CPU 核间无锁通信DPDK 数据加速方案...

[python入门㊽] - 自定义异常 raise 关键字
目录 ❤ 自定义抛出异常关键字 - raise ❤ 使用raise主动引发异常 ❤ raise 关键字的用法 ❤ 触发异常 ❤ 自定义异常类 在前面我们学过异常三个关键字分别是try、except 以及 finally 在编程过程中合理的使用异常可以使得程序正常的执行。有直接抛出异常的形式&…...

DDOS攻击
注:本博客只是为了自己的学习,记录自己的学习,请勿用于其他途径、1、winR-->cmd2、ping 网站3、替换IP1 import java.io.BufferedInputStream;2 import java.io.IOException;3 import java.net.MalformedURLException;4 import java.net.U…...

网络编程套接字
文章目录1. socket编程接口1-1 socket 常见API1-2 sockaddr结构2. 简单的UDP网络程序2-1 日志(固定用法:标准部分自定义部分)2-2 服务器代码实现1. 框架2. 初始化服务器3. 服务器运行4. 调用服务器封装函数(UdpServer)…...

海量数据相似数据查询方法
1、海量文本常见 海量文本场景,如何寻找一个doc的topn相似doc,一般存在2个问题, 1)、两两对比时间o(n^2) 2)、高维向量比较比较耗时。 文本集可以看成(doc,word)稀疏矩阵,一般常见的方法是构建到排索引,然后进行归并…...
Codeforces Round #822 (Div. 2)
A(签到) - Select Three Sticks 题意: 给你一个长度为 n 的正整数序列,你可以操作任意次,每一次操作可以选择任意一个元素,把它 1 或者 - 1,问最少多少次操作可以使得序列中存在三个相同的数字以构成一个等边三角形.…...
华为OD机试 - 最短木板长度(JS)
最短木板长度 题目 小明有 n n n块木板,第 i i i(1≤ i i </...

java设计模式——观察者模式
概述 定义:又被称为发布-订阅(Publish/Subscribe)模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。 结构 在观察者模式…...

linux高级命令之线程的注意点
线程的注意点学习目标能够说出线程的注意点1. 线程的注意点介绍线程之间执行是无序的主线程会等待所有的子线程执行结束再结束线程之间共享全局变量线程之间共享全局变量数据出现错误问题2. 线程之间执行是无序的import threading import timedeftask():time.sleep(1)print(&qu…...

UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...