当前位置:网站首页>【学习笔记之菜Dog学C】字符串+内存函数
【学习笔记之菜Dog学C】字符串+内存函数
2022-07-27 01:26:00 【姜君竹】
文章目录
一、strlen函数以及模拟实现
- 函数使用
int main() {
char arr[] = "abc";
int len = strlen(arr);
printf("%d\n", len);
return 0;
}
- 函数介绍
字符串以’\0’作为结束标志,strlen函数返回的是在字符串中’\0’前面出现的字符个数(不包含’\0’);
参数指向的字符串必须要以 ‘\0’ 结束;
注意函数的返回值为size_t,是无符号的。
- 函数源码

size_t在<vcruntime.h>中定义typedef unsigned int size_t;,是无符号的;
接收一个char类型的数据,用const修饰,保证指针指向的内容不能通过指针来改变。 - 模拟实现
//计数器方式
int my_strlen(const char* str) {
int count = 0;//计数器
assert(str != NULL);//指针断言,确保指针的有效性
while (*str != '\0') {
count++;
str++;
}
return count;
}
//不能创建临时变量计数器
int my_strlen(const char * str) {
if(*str == '\0')
return 0;
else
return 1+my_strlen(str+1);
}
//指针-指针的方式
int my_strlen(char *s) {
char *p = s;
while(*p != ‘\0’ )
p++;
return p-s;
}
int main() {
char arr[] = "abc";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
- 与strlen函数的区别
int main() {
//因为strlen返回的是一个无符号数,所以打印 >
if (strlen("abc") - strlen("abcedf") > 0)
{
printf("strlen >\n");
}
else
{
printf("strlen <\n");
}
//我们的模拟的函数返回的是一个int类型是有符号的,所以打印 <
//如果我们想要和strlen一模一样,那就需要也返回一个无符号数
//把int改为size_t
if (my_strlen("abc") - my_strlen("abcedf") > 0)
{
printf("my_strlen >\n");
}
else
{
printf("my_strlen <\n");
}
return 0;
}
二、长度不受限制的字符串函数
1、strcpy函数以及模拟实现
- 函数使用
int main() {
char arr[20] = {
0 };
strcpy(arr, "hello");
printf("%s\n", arr);
return 0;
}
- 函数介绍
源字符串必须以’\0’结束;
会将源字符串中的 ‘\0’ 拷贝到目标空间;
目标空间必须足够大,以确保能存放源字符串;
目标空间必须可变。
- 函数源码

destination是目标的意思,也就是说destination这里放被替换的字符,即目标字符。source的意思是来源,就是source这里放替换字符,即源字符。所以strcpy接收两个参数,第一个参数为需要被替换的字符,第二个参数为替换字符; - 模拟实现
char* my_strcpy(char* dest, char* src) {
while (*dest++ = *src++) {
; }
}
int main() {
char arr[20] = {
0 };
my_strcpy(arr, "hello");
printf("%s\n", arr);
return 0;
}
2、strcat函数以及模拟实现
- 函数使用
int main() {
char arr1[20] = "hello";
char arr2[] = "world";
strcat(arr1, arr2);//字符串追加(连接)
printf("%s\n", arr1);
return 0;
}
- 函数介绍
源字符串必须以’\0’结束;
目标空间必须有足够的大,能容纳下源字符串的内容;
目标空间必须可修改;
strcat函数不能自己追加自己。![]()
原字符串会找到目标字符串的第一个\0,从\0开始追加。
如果自己追加自己,就会导致找不到\0,使程序无法结束。
- 函数源码

接收参数与strcpy是一样的。 - 模拟实现
char* my_strcat(char* dest, const char* str) {
char* ret = dest;
assert(dest && str);//断言,确保指针是有效的
//找到目标字符串中的\0
while (*dest) {
dest++;
}
//追加源字符串
while (*dest++ = *str++) {
; }
return ret;//strcat返回的是目标空间的起始地址,我们也返回目标空间起始地址
}
int main() {
char arr1[20] = "hello";
char arr2[] = "world";
my_strcat(arr1, arr2);//字符串追加(连接)
printf("%s\n", arr1);
return 0;
}
3、strcmp函数以及模拟实现
- 函数使用
int main() {
printf("%d\n", strcmp("abc", "abb"));
printf("%d\n", strcmp("abc", "abc"));
printf("%d\n", strcmp("abb", "abc"));
return 0;
}
- 函数介绍
第一个字符串大于第二个字符串,则返回大于0的数字;
第一个字符串等于第二个字符串,则返回0;
第一个字符串小于第二个字符串,则返回小于0的数字。
- 函数源码

- 模拟实现
int my_strcmp(const char* s1, const char* s2) {
assert(s1 && s2);
while (*s1 == *s2) {
s1++;
s2++;
if ('\0' == *s1 || '\0' == *s2) {
break;
}
}
return *s1 - *s2;
}
int main() {
printf("%d\n", my_strcmp("abc", "abb"));
printf("%d\n", my_strcmp("abc", "abc"));
printf("%d\n", my_strcmp("abb", "abc"));
return 0;
}
三、长度受限制字符串函数
1、strncpy函数以及模拟实现
- 函数使用
int main() {
char arr1[20] = "abcdef";
char arr2[] = "qwer";
printf("%s\n", strncpy(arr1, arr2, 2));
return 0;
}
- 函数介绍
拷贝n个字符从源字符串到目标空间;
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
- 函数源码

它比strcpy多了一个Count计数器,用来确定从原字符串中拷贝几个字符到目标空间。所以它被叫做长度受限制字符串函数,而strcpy被叫做长度不受限制的字符串函数。 - 模拟实现
char* my_strncpy(char* dest, char* src, int count) {
while (*dest++ = *src++) {
count--;
}
int i = 0;
for (i = 0; i < count - 1; i++) {
*dest++ = '\0';
}
}
int main() {
char arr1[20] = "abcdefdef";
char arr2[] = "qwer";
my_strncpy(arr1, arr2, 6);
printf("%s\n", arr1);
return 0;
}
2、strncat函数以及模拟实现
- 函数使用
int main() {
char arr1[20] = "abcd";
char arr2[] = "efgh";
strncat(arr1, arr2, 2);
printf("%s", arr1);
return 0;
}
- 函数介绍
将源字符串中n个字符追加到目标空间,并在最后加上一个终止的空字符;
如果源字符串的长度小于n个,则只将包含终止空字符在内的原字符串追加到目标空间。
- 函数源码

- 模拟实现
char* my_strncat(char* dest, const char* str, int count) {
char* ret = dest;
assert(dest && str);//断言,确保指针是有效的
//找到目标字符串中的\0
while (*dest) {
dest++;
}
int i = 0;
for (i = 0; i < count; i++) {
if ('\0' == *str) {
break;
}
*dest++ = *str++;
}
*dest++ = '\0';
return ret;
}
int main() {
char arr1[20] = "abcd";
char arr2[] = "efgh";
my_strncat(arr1, arr2, 2);
printf("%s", arr1);
return 0;
}
3、strncmp函数以及模拟实现
- 函数使用
int main() {
char* p = "abcde";
char* q = "abbc";
int ret = strncmp(p, q, 4);
printf("%d\n", ret);
return 0;
}
- 函数介绍
比较到出现另个字符不一样或者一个字符串结束或者n个字符全部比较完。
- 函数源码

- 模拟实现
int my_strncmp(const char* s1, const char* s2, int count) {
assert(s1 && s2);
int i = 0;
for (i = 0; i < count; i++) {
if (*s1 != *s2) {
break;
}
s1++;
s2++;
if (i == count - 1 || '\0' == *s1 || '\0' == *s2) {
return 0;
}
}
return *s1 - *s2;
}
int main() {
char* p = "abcde";
char* q = "abc";
int ret = my_strncmp(p, q, 4);
printf("%d\n", ret);
return 0;
}
四、strstr函数以及模拟实现
- 函数使用
int main() {
char arr1[20] = "abbbdefgh";
char arr2[] = "bbd";
char* ret = strstr(arr1, arr2);
if (NULL == ret) {
printf("没找到\n");
}
else {
printf("找到了:%s\n", arr1);
}
return 0;
}
- 函数介绍
如果str2是str1的子集,则返回str1中检测到与str2相同值的地址,如果str2不是str1的一部分,则返回空指针。
- 函数源码

- 模拟实现
char* my_strstr(const char* str1, const char* str2) {
char* cp = (char*)str1;
char* s1, * s2;
if (!*str2)
return((char*)str1);
while (*cp)
{
s1 = cp;
s2 = (char*)str2;
while (*s1 && *s2 && !(*s1 - *s2))
s1++, s2++;
if (!*s2)
return(cp);
cp++;
}
return(NULL);
}
int main() {
char arr1[20] = "abbbdefgh";
char arr2[] = "bbd";
char* ret = my_strstr(arr1, arr2);
if (NULL == ret) {
printf("没找到\n");
}
else {
printf("找到了:%s\n", arr1);
}
return 0;
}
五、strtok函数以及模拟实现
- 函数使用
int main() {
char arr[] = "[email protected]";
char* p = "[email protected]";
char tmp[20] = {
0 };
strcpy(tmp, arr);
char* ret = NULL;
for (ret = strtok(tmp, p); ret != NULL; ret = strtok(NULL, p)) {
printf("%s\n", ret);
}
return 0;
}
- 函数介绍
sep参数是个字符串,定义了用作分隔符的字符集合;
第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记;
strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改);
strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置;
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记;
如果字符串中不存在更多的标记,则返回 NULL 指针。
- 函数源码

- 模拟实现
对不起,我不配。
六、strerror函数以及模拟实现
- 函数使用
//使用函数库的时候
//调用库函数失败,都会设置错误码
int main() {
//文件打开失败会返回一个NULL指针
FILE* pf = fopen("test.txt", "r");
if (NULL == pf) {
printf("%s\n", strerror(errno));
return 1;
}
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
- 函数介绍
返回错误码,所对应的错误信息。
七、内存函数
1、memcpy函数以及模拟实现
- 函数使用
int main() {
int arr1[10] = {
0 };
int arr2[10] = {
1,2,3,4,5,6,7,8,9,10 };
memcpy(arr1, arr2, 20);
return 0;
}
- 函数介绍
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置;
这个函数在遇到 ‘\0’ 的时候并不会停下来;
如果source和destination有任何的重叠,复制的结果都是未定义的。
函数源码

模拟实现
void* my_memcpy(void* dest, 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;
}
}
int main() {
int arr1[10] = {
0 };
int arr2[10] = {
1,2,3,4,5,6,7,8,9,10 };
my_memcpy(arr1, arr2, 20);
return 0;
}
2、memmove函数以及模拟实现
- 函数使用
int main() {
int arr1[10] = {
1,2,3,4,5,6,7,8,9,10 };
memmove(arr1 + 2, arr1, 20);
return 0;
}
- 函数介绍
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的;
如果源空间和目标空间出现重叠,就得使用memmove函数处理。
函数源码
模拟实现
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;
}
int main() {
int arr1[10] = {
1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr1 + 2, arr1, 20);
return 0;
}
3、memcmp函数
- 函数使用
int main() {
float arr1[] = {
1.0,2.0,3.0,4.0 };
float arr2[] = {
1.0, 3.0 };
int ret = memcmp(arr1, arr2, 8);
printf("%d\n", ret);
return 0;
}
- 函数介绍
比较从ptr1和ptr2指针开始的num个字节;
第一块内存大于第二块内存,则返回大于0的数字;
第一块内存等于第二块内存,则返回0;
第一块内存小于第二块内存,则返回小于0的数字。
4、memset函数
- 函数使用
int main() {
int arr[10] = {
0 };
memset(arr, 1, 20);
return 0;
}
- 函数介绍
以字节为单位设置内存。

八、字符函数
1、字符分类函数
| 函数 | 如果他的参数符合下列条件就返回真 |
|---|---|
| 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 | 任何可打印字符,包括图形字符和空白字符 |
2、字符转换函数
int tolower ( int c );//将大写字母转换为小写字母
int toupper ( int c );//将小写字母转换为大写字母
边栏推荐
- The most complete basic knowledge of software testing in the whole network (a must for beginners)
- 制作ppt时间轴
- 30分钟彻底弄懂 synchronized 锁升级过程
- 数据湖(二十):Flink兼容Iceberg目前不足和Iceberg与Hudi对比
- Shell (38): SSH port forwarding
- Use the most primitive method to manually implement the common 20 array methods
- Activiti5.22.0扩展支持达国产数据库,以GBase据库为例
- 仿知乎论坛社区社交微信小程序
- A math problem cost the chip giant $500million!
- 记录一次,php程序访问系统文件访问错误的问题
猜你喜欢

百度云人脸识别

Alibaba cloud technology expert Yang Zeqiang: Construction of observability on elastic computing cloud

cocos小游戏实战-04-碰撞检测与NPC渲染

MySQL:互联网公司常用分库分表方案汇总

CAS部署使用以及登录成功跳转地址

185. 部门工资前三高的所有员工(必会)

关于url编解码应该选用的函数

次轮Okaleido Tiger即将登录Binance NFT,引发社区热议

Bulk copy baby upload prompt garbled, how to solve?

Worthington木瓜蛋白酶解离系统解决方案
随机推荐
Shell (38): SSH port forwarding
177. 第N高的薪水(简单)
图解 SQL,这也太形象了吧!
阿里云解决方案架构师张平:云原生数字化安全生产的体系建设
优炫数据库集群如何唯一标识一条用户SQL
太强了,一个注解搞定接口返回数据脱敏
coco test-dev 测试代码
基于.NetCore开发博客项目 StarBlog - (16) 一些新功能 (监控/统计/配置/初始化)
Marqueeview realizes sliding display effect
Integrated water conservancy video monitoring station telemetry terminal video image water level water quality water quantity flow velocity monitoring
[SQL简单题] LeetCode 627. 变更性别
2649: segment calculation
数据湖(二十):Flink兼容Iceberg目前不足和Iceberg与Hudi对比
再学RecyclerView的回收复用机制
[binary search medium] leetcode 34. find the first and last positions of elements in the sorted array
A math problem cost the chip giant $500million!
DNS记录类型及相关名词解释
记录一次,php程序访问系统文件访问错误的问题
Abbkine AbFluor 488 细胞凋亡检测试剂盒特点及实验建议
阿里云技术专家杨泽强:弹性计算云上可观测能力的构建

