1.引言
本期带大家一起来学习字符串函数+内存函数😀 😃 😄
一、字符串函数📌📌
1. 求字符串长度 strlen🚀🚀
字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
#include<stdio.h>
#include<string.h>
int main()
{
char* p = "abcdef";
size_t len = strlen(p);
printf("len=%zd\n", len);
return 0;
}
strlen在库里面的参数是如此的⌛️⌛️
接下来我们来模拟实现strlen,接下来使用三种方法求字符串长度
//方法一 使用循环求字符串长度
#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* p)
{
assert(p);
size_t len = 0;
while (*p != '\0')
{
p++;
len++;
}
return len;
}
int main()
{
char* p = "abcdef";
size_t len = my_strlen(p);
printf("len=%zd\n", len);
return 0;
}
//方法二 递归求字符串长度
#include<stdio.h>
#include<assert.h>
unsigned int mystrlen(const char* p)
{
assert(p);
if (*p == '\0')
return 0;
return 1 + mystrlen(p + 1);
}
int main()
{
char arr[] = "abcdefghi";
unsigned int ret = mystrlen(arr);
printf("%u", ret);
return 0;
}
//方法三 运用指针求字符串长度
#include<stdio.h>
#include<assert.h>
unsigned int mystrlen(const char* p)
{
assert(p);
char* start = p;
while (*p != '\0')
{
p++;
}
return p - start;
}
int main()
{
char arr[] = "abcdefghi";
unsigned int ret = mystrlen(arr);
printf("%u", ret);
return 0;
}
注意点:
字符串是以’\0’作为结束的标志,strlen是统计字符串’\0’之前的字符。
参数指向的字符串必须要以 ‘\0’ 结束
字符串的返回类型是size_t类型。
2.长度不受限制的字符串函数🚀🚀
2.1 strcpy🌴🌴
strcpy在库里面的参数是如此的
接下来我们来模拟实现strcpy
#include<stdio.h>
#include<assert.h>
char* mystrcpy(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr[20] = "abcdef";
char str[20] = "hello world";
char *ret=mystrcpy(arr, str);
printf("%s\n", ret);
return 0;
}
strcpy函数注意点:⌛️⌛️
源字符串必须以 ‘\0’ 结束。
会将源字符串中的 ‘\0’ 拷贝到目标空间。
目标空间必须足够大,以确保能存放源字符串。
目标空间必须可变。🔑🔑
2.2 strcat🌴🌴
strcat是字符串追加函数,能够将源字符串的字符追加到目标字符串中。
💬💬 strcpy函数注意点:🔑🔑🔑
返回类型是char*(返回的是目标字符串首的地址)
接下来模拟实现strcat
#include<stdio.h>
#include<assert.h>
char* mystrcat(char* dest, const char* src)
{
assert(dest&&src);
char* ret = dest;
while (*dest)
{
dest++;
}
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr[20] = "hello ";
char* p = "abcdef";
char str[20] = "world";
char* ret = mystrcat(arr, str);
printf("%s\n", ret);
return 0;
}
注意点:strcat函数💬💬
源字符串 必须以’\0’ 结束
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。
不能自己给自己追加字符串,程序会崩溃❗️❗️❗️
📣📣当我们自己给自己追加的时候,会出现死循环,接下来看图解📣📣
2.3 strcmp🌴🌴
strcmp是字符串比较函数,该函数是从二个字符串的元素开始🚩🚩
进行比较 (比较本质为字母ascii码值的大小)
接下来模拟实现strcmp
#include<stdio.h>
#include<assert.h>
int mystrcmp(const char* p,const char * q)
{
assert(p && q);
while (*p == *q)
{
p++;
q++;
if (p == '\0')
return 0;
}
return *p - *q;
}
int main()
{
char* p = "abcdef";
char* q = "abcccc";
int ret = mystrcmp(p, q);
printf("%d\n", ret);
return 0;
}
标准规定: strcmp函数
第一个字符串大于第二个字符串, 则返回大于0的数字🌈
第一个字符串等于第二个字符串,则返回0🌈🌈
第一个字符串小于第二个字符串,则则返回小于0的数字🌈🌈🌈
3.长度受限制的字符串函数🍎🍎
上面的 strcmp,strcpy,strcat都是长度不限制字符串函数,具有一定的风险性,这和VS当中scanf函数一样,具有一定的风险,所以下面来介绍长度受限制的字符串函数 strncmp,strncpy,strncat
3.1 strncpy⚓️⚓️
这是strncpy的参数,前两个参数和 strcpy是一样的,不同的是第三个参数
第三个参数则是传入需要复制的 字符 个数
3.2 strncat⚓️⚓️
这是strncat的参数,前两个参数和 strcat是一样的,不同的是第三个参数
第三个参数则是传入需要连接第二个参数 src 的 字符 个数
当我们的传入的 第三个参数小于字符串长度,
后面会自动补 斜杠0
3.3 strncmp⚓️⚓️
这是strncmp的参数,前两个参数和 strcmpt是一样的,不同的是第三个参数
第三个参数则是传入需要比较的dest 和 src 的 字符 个数
比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完
当需要比较的字符个数小于实际的字符串长度
会提前结束
4.字符串查找💡💡
4.1 strstr🌱🌱
这是strstr的参数✔️✔️
返回的是在被查找字符串当中与查找字符串相同的首元素的地址
第一个参数是被查找字符串的首元素的地址
第二个参数是查找字符串的首元素地址
接下来我们来模拟实现strstr
方法一 :暴力求解🌴
方法二 :借助strncmp求解🌴🌴
方法三 :KMP算法求解🌴🌴🌴
//方法一:暴力求解
#include<stdio.h>
#include<assert.h>
char* mystrstr(const char* dest, const char* src)
{
assert(dest && src);
char* start = dest;
while (*start)
{
char* p = start;
char* q = src;
while (*p == *q && *p && *q )
{
p++;
q++;
}
if (*q == '\0')
return start;
start++;
}
return NULL;
}
int main()
{
char* p = "abcdededefabc";
char* q = "def";
char* ret = mystrstr(p, q);
printf("%s\n", ret);
return 0;
}
//方法二:借助strncmp求解
#include<stdio.h>
#include<assert.h>
#include<string.h>
char* mystrstr(const char* dest, const char* src)
{
assert(dest && src);
char* p = dest;
while (*p)
{
if (strncmp(p, src, strlen(src)) == 0)
return p;
p++;
}
return NULL;
}
int main()
{
char* p = "abcdededefabc";
char* q = "def";
char* ret = mystrstr(p, q);
printf("%s\n", ret);
return 0;
}
//方法三:KMP算法实现
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
void my_next(int* next,int n,const char* p)
{
int j = 0,k=-1;
next[0] = -1;
while(j<n)
{
if (k == -1 || p[j] == p[k])
{
next[j + 1] = k + 1;
j++;
k++;
}
else
k = next[k];
}
}
int KMP(const char* str1, const char* str2)
{
int i = 0, j = 0;
int len = (int)strlen(str2);
//next数组
int* next = (int*)malloc(len * sizeof(int));
assert(next);
my_next(next,len-1,str2);
while (str2[j])
{
if(j==-1||str1[i] == str2[j])
//j为-1时该位置下的i不会匹配成功,进入下一次匹配
{
i++;
j++;
}
else
{
j = next[j];//j进行回退
}
if (str1[i] == '\0')
{
free(next);
next = NULL;
return -1;
}
}
free(next);
next = NULL;
return i;
}
int main()
{
char arr[] = "abaabcdabcab";
char brr[] = "ef";
printf("%d\n",KMP(arr, brr));
return 0;
}
4.2 strtok🌱🌱
strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。
(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容
并且可修改。)
🔔strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
🔔🔔strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记
🔔🔔🔔如果字符串中不存在更多的标记 ,则返回 NULL 指针
#include<stdio.h>
#include<string.h>
int main()
{
char arr[20] = "abc@dfg#hi.123";
char* p = "@#.";
char str[30] = "0";
strcpy(str, arr);
char* ret = NULL;
for (ret = strtok(str, p); ret != NULL; ret = strtok(NULL, p))
{
printf("%s\n", ret);
}
return 0;
}
5.错误信息报告 strerror🌱🌱
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
FILE* pFile;
pFile = fopen("unexist.ent", "r");
if (pFile == NULL)
printf("Error opening file unexist.ent: %s\n", strerror(errno));
return 0;
}
🍗🍗 返回错误码,所对应的错误信息🍗🍗
返回的是错误信息
二、内存操作函数📌📌
1.memcpy🚁🚁
函数memcpy从source的位置开始向后
复制num个字节的数据到destination的内存位置。✏️✏️
这个函数在遇到 ‘\0’ 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。 🔑 💡🔑 💡
接下来我们来模拟实现一下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);
src = ((char*)src + 1);
}
return ret;
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int *ret=my_memcpy(arr, arr + 2,5 * sizeof(int));
int len = sizeof(arr) / sizeof(int);
while (len--)
{
printf("%d ", *ret);
ret++;
}
return 0;
}
🔍🔍my_memcpy的参数是void * ,🔎🔎
void*指针可以接收任何类型的指针,这样子可以接收任何类型的指针,
🔍🔍 并且用将其强制类型转换为char *指针,🔎🔎
每次拷贝一个字节的数据,这样子方便使用并且加强了代码的可执行性
但是我们可以发现,当我们传参到我们的my_memcpy当中,
第一个参数的地址比第二个参数的地址高的时候,
会出先重复的情况
❗️❗️❗️接下来看图解❗️❗️❗️
所以接下来我们来学习一下memmove函数,可以解决这个情况
2.memmove🚁🚁
和memcpy的差别就是memmove函数
处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。
接下来我们来模拟实现一下memmove⭐️⭐️⭐️
#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);
src = ((char*)src + 1);
}
}
else
{
while (num--)
{
*((char*)dest + num) = * ((char*)src + num);
}
}
return ret;
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr, arr + 2, 5 * sizeof(int));
my_memmove(arr+2, arr , 5 * sizeof(int));
char string1[60] = "abcdef123456";
my_memmove(string1 + 3, string1, 3);
char string2[60] = "abcdef123456";
printf("string1=%s\n", string1);
my_memmove(string2 , string2+3, 3);
printf("\nstring2=%s\n", string2);
return 0;
}
3.memset🚁🚁
memset是计算机中C/C++语言初始化函数。
作用是将某一块内存中的内容全部设置为指定的值,
这个函数通常为新申请的内存做初始化工作。
可以注意到第三个参数是需要改变字节的数目
⭐️⭐️⭐️接下来模拟实现memset⭐️⭐️⭐️
#include<stdio.h>
#include<string.h>
void* my_memset(void* dest,int c, size_t count)
{
while (count--)
{
*(char*)dest = (char)c;
dest = (char*)dest + 1;
}
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
my_memset(arr, 0,sizeof(int) * 10);
char str[20] = "abcdef";
my_memset(str,'a', sizeof(char) * strlen(str));
printf("%s", str);
return 0;
}
但是当我们将第二个参数传入1的时候,结果会和我们预想的不一样,这是为什么呢?⁉️⁉️⁉️
因为我们开头提到memset是一个字节一个字节初始化的
1 在内存当中 小端 存储方式如下
01 00 00 00
强制类型转换为char后
是01
所以得出来的结果是⭕️ ⭕️ ⭕️
4.memcmp🚁🚁
memcmp函数和strcmp函数是差不多的🚦
区别在于memcmp函数可以比较任何类型的数据 🚦🚦
而strcmp函数只能比较字符串 🚦🚦🚦
三、感谢与交流📌📌
🌹🌹🌹如果大家通过本篇博客收获了,对字符串函数以及内存操作函数 ,那么希望支持一下哦如果还有不明白的,疑惑的话,或者什么比较好的建议的话,可以发到评论区,
我们一起解决,共同进步 ❗️❗️❗️
最后谢谢大家❗️❗️❗️💯💯💯文章来源:https://www.toymoban.com/news/detail-416505.html
文章来源地址https://www.toymoban.com/news/detail-416505.html
到了这里,关于字符串函数+内存函数(详解)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!