c语言|C语言进阶(五)——字符串+内存函数的介绍


文章目录

  • 一、字符串函数的介绍
    • 前言
    • 1.strlen函数的介绍及模拟实现
    • (1)strlen函数的使用
    • (2)strlen函数功能
    • (3)strlen的模拟实现
    • (4)易错点
    • 2.strcpy函数的介绍及模拟实现
    • (1)strcpy函数的使用
    • (2)strcpy函数功能
    • (3)strcpy 函数的模拟实现
    • 3.strcat函数的介绍及模拟实现
    • (1)strcat函数的使用
    • (2)strcat函数功能及使用
    • (3)strcat字符追加函数的模拟实现
    • (4)字符串能否给自己追加本身?
    • 4.strcmp函数的介绍及模拟实现
    • (1)strcmp函数的使用
    • (2)strcmp函数功能
    • (3)strcmp函数的模拟实现
    • 5.长度受限制的字符串函数的使用
    • (1)strncpy函数的介绍
    • (2)strncat函数的介绍
    • (3) strncmp函数的介绍
    • 6.strstr函数的介绍和模拟实现
    • (1)strstr函数的使用
    • (2)strstr函数的功能
    • (3)strstr函数的模拟实现
    • 7.strtok函数的介绍
    • 8.strerror函数的介绍
    • 9.字符操作函数
    • (1)字符分类函数
    • (2)字符转换函数
  • 二、内存操作函数介绍
    • 1.memcpy函数的介绍和模拟实现
    • (1)memcpy函数的功能
    • (2)memcpy函数的使用
    • (3) memcpy函数的模拟实现
    • (4)memcpy函数的缺点
    • 2.memmove函数的介绍和模拟实现
    • (1)memmove函数的功能
    • (2)memmove函数的模拟实现
    • 3.memcmp函数的介绍
    • (1)memcmp函数的功能
    • (2)memcmp函数的使用
    • 4.memset函数的介绍
    • (1)memset函数功能
    • (2)memset函数的使用
  • 未完待续!!

一、字符串函数的介绍 前言 ??C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串或者字符数组中。字符串常量适用于那些对他不做修改的字符串函数。


1.strlen函数的介绍及模拟实现
(1)strlen函数的使用
#include #include int main() { //字符串函数的实现 //字符串函数的功能 char a[6] = "abcde"; int len = strlen(a); printf("%d\n", len); return 0; }

执行效果如下:
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

(2)strlen函数功能 通过msdn函数功能查找得知strlen具体使用情况如下
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

??strlen的功能是获取字符串的长度,函数内部传的参数类型是 char *,返回的类型是size_t类型。返回值是字符串中字符出现的个数。
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

(3)strlen的模拟实现
size_t my_strlen(const char* p) { int count = 0; while (*p) { count++; p++; } return count; }


(4)易错点 注意:
#include #include int main() { const char*str1 = "abcdef"; const char*str2 = "bbb"; if(strlen(str2)-strlen(str1)>0) { printf("str2>str1\n"); } else { printf("srt1>str2\n"); } return 0; }

??如果按照我们平时的理解,我们所算的strlen(str1)=6,strlen(str2)=3,strlen(str2)—strlen(str1)<0,会打印str1>str2。但是实际上打印的结果却并不是我们想的那样。
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

??打印结果为str2>str1.那么我们想是strlen(str2)— strlen(str1)>0吗?并不是的,还记得我们说的strlen的返回类型是size_t 无符号数,是不存在负数的,减到小于0是会成为一个很大很大的数字,此时结果还是大于0,所以会出现上述打印的结果,这点很容易出现错误。牢记strlen的返回类型是无符号整型。


2.strcpy函数的介绍及模拟实现
(1)strcpy函数的使用
#include #include int main() { char arr1[30] = "*********************"; char arr2[] = "hello world"; /*strcpy(arr1,arr2); */ printf("%s\n", strcpy(arr1, arr2)); return 0; }

执行代码效果如下:
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

(2)strcpy函数功能 通过msdn函数功能查找得知strlen具体使用情况如下
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

??我们得知,strcpy是字符串拷贝函数,他的功能就是拷贝字符串,函数内部的参数:第一个参数是目标字符串,第二个参数是 char* str Source (起始字符串),最后将起始字符串拷贝到目标字符串中,达到最终效果。函数返回类型是 char*。返回值是目标字符串的起始地址处。
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

(3)strcpy 函数的模拟实现
#include #include #include char * my_strcpy(char *dest,const char *src) { char * p = dest; assert(dest && src ); while (*src) { *dest=*src; dest++; src++; } *dest=*src; return p; }int main() { char arr1[30] = "*********************"; char arr2[] = "hello world"; /*strcpy(arr1,arr2); */ printf("%s\n", strcpy(arr1, arr2)); return 0; }

??这里的模拟实现中有一点需要注意的,我们将源字符串拷贝到目标字符串后,函数要返回目标字符串的起始指针的地址处,但是dest已经++,所以在一开始我们要将dest的初始值保存起来,char *p=dest,最后返回p。

3.strcat函数的介绍及模拟实现
(1)strcat函数的使用
int main() { char arr1[20] = "hello "; char arr2[20] = "world"; /*my_strcat(arr1, arr1)*/ printf("%s\n", strcat(arr1, arr2)); return 0; }

代码实现效果:
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

(2)strcat函数功能及使用 通过msdn函数功能查找得知strlen具体使用情况如下
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

??该函数的功能是追加一个字符串,函数内部的参数:第一个参数是char*str Destination(目标字符串),第二个参数是 起始字符串,将源字符串追加到目标字符串后。返回类型是char *。返回的是目标字符串的起始地址处。
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

(3)strcat字符追加函数的模拟实现 ??首先我们问一个问题,如何实现字符追加,首先第一步先要找到目标字符串的’\0 ‘,然后将目标函数的’ \0 ‘改为源字符串的初始指针,再将src赋给dest直到*src=https://www.it610.com/article/’/0’,返回目标字符串的初始指针的地址处。
代码实现:
#include #include #include char*my_strcat(char*dest, const char*src) { assert(dest && src); char *ret = dest; //1.找到目标空间的\0 while (*dest) { dest++; } //2.追加 while ( *src) { *dest = *src; dest++; src++; } *dest = *src; return ret; }int main() { char arr1[20] = "hello "; char arr2[20] = "world"; /*strcat(arr1, arr2)*/ printf("%s\n", my_strcat(arr1, arr2)); return 0; }


(4)字符串能否给自己追加本身? ??关于字符追加函数能否给本身的字符串追加本身,我们可以根据上面的strcat模拟实现的函数进行分析。
回顾strcat字符追加函数的过程:
以下列代码举例
#include #include int main() { char arr="abc"; strcat(arr,arr); return 0; }

c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片



4.strcmp函数的介绍及模拟实现
(1)strcmp函数的使用 注意:
??strcmp函数比较的不是字符串的长度,而是字符串对应字符的ASCII码值
#include #include int main() { char arr1[]="abcdef"; chararr2[]="abc"; if(strcmp(arr1,arr2)<0) printf("arr1); else if(strcmp(arr1,arr2)>0) printf("arr1>arr2\n"); else if(strcmp(arr1,arr2)==0) printf("arr1=arr2"); return 0; }

代码显示效果:
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

(2)strcmp函数功能 c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

??strcmp函数的函数功能是比较两个字符串,那么如何进行比较呢?strcmp函数比较的是字符串对应的字符的ASCII码值,返回值是int类型的,分别向函数内部传入两个字符串s1、s2。
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

(3)strcmp函数的模拟实现
int my_strcmp(const char *s1, const char *s2) { while (*s1 == *s2) { if (*s1 == '\0') return 0; s1++; s2++; } if (*s1 > *s2) return 1; else if (*s1 < *s2) return -1; // return *s1 - *s2; //}


注意:
??在模拟过程中我们可以定义 小于时返回-1,大于时返回1,相等时返回0。也可以直接返回*s1-*s2,字符串比较的效果一样。

5.长度受限制的字符串函数的使用
(1)strncpy函数的介绍 c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

功能介绍:
1.拷贝count个字符从源字符串到目标空间。
2.如果源字符串的长度小于count,则拷贝完源字符串之后,在目标的后边追加0,直到count个。

(2)strncat函数的介绍 c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

功能介绍:
1.将source的num个字符追加到destination
2.如果source中的字符串长度小于num,则只复制到结束空字符之前的内容。

实现效果如下:
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

(3) strncmp函数的介绍 c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

功能介绍:
比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。

6.strstr函数的介绍和模拟实现
(1)strstr函数的使用
int main() { char arr1[] = "abbbcdef"; char arr2[] = "bcde"; char * ret = strstr(arr1, arr2); if (ret == NULL) { printf("找不到字串\n"); } else printf("%s\n",ret ); return 0; }

代码实现效果:
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片



(2)strstr函数的功能 通过msdn函数功能查找得知strlen具体使用情况如下
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

??我们可得知strstr函数的功能是查找一个字串,或者截取一个字串。第一个参数传一个字符串,第二个参数传一个要查找的字符串。返回类型是char *,如果查找到了,那么返回字符串中查找到的那个字符的指针,直到\0结束。如果未查找到,那么就返回NULL。

(3)strstr函数的模拟实现
#include #include #include char * my_strstr(char * s1, char * s2) { assert(s1&&s2); if (*s2 == '\0') return s1; char * cp = s1; while (*s1 != '\0') { char *p2 = s2; char *p1 = cp; while (*p1 == *p2) { p1++; p2++; } if (*p2 == '\0') { return cp; } cp++; } return NULL; }


7.strtok函数的介绍 strtok是一个用来分隔字符串的函数。
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

下面给一个例子来演示strtok的具体功能
#include #include int main() { char arr1[] = "crq@2745131427qq.com"; char arr2[30] = { 0 }; char p[] = "@.#"; //分隔符的集合的字符串 strcpy(arr2, arr1); printf("%s\n", strtok(arr1, p)); printf("%s\n", strtok(NULL, p)); printf("%s\n", strtok(NULL, p)); return 0; }

代码显示效果:
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

好了,那么strtok函数,我们应该怎样使用呢?
对于第一、二条规则,我们用一个字符串来记录分隔符的集合。(以分隔符为标记,从而进行分割字符串操作)
strtok操作会对字符串进行修改,所以我们要拷贝内容到另一个字符串中。
以上面的例子代码为例,strtok 的第一个参数不为NULL,我们进行 strtok(arr1,p),将第一个分隔符@,改为\0。同时函数保存了第一个分隔符的位置。
第二次传参为NULL,我们进行 strtok(NULL,p),此时的NULL虽然传了一个空指针,但是指向了上一次保存的分隔符的位置。从这个位置开始,将下一个分隔符.,改为\0。同时函数保存此位置。
依次进行该操作…
??可能有同学会问了:函数内部的变量出函数不是销毁了么,函数怎么保存一个地址变量呢?
我们猜测:在C语言关键字的学习中,我们学到了一个static 的关键字,出了函数也能保存下来。可能这个函数的实现过程中存在一个static关键字,所以每次的标记位置得以保存…
??但是我们如果不知道字符串内部有多少分隔符,而且strtok(NULL,p)的操作重复多次,显得冗余,如何进行简化呢?
给出的解决冗余方案:
#include #include int main() { char arr1[] = "crq@2745131427qq.com"; char arr2[30] = { 0 }; char p[] = "@.#"; //分隔符的集合的字符串 strcpy(arr2, arr1); char *ret = NULL; for (ret = strtok(arr1, p); ret != NULL; ret = strtok(NULL, p)) { printf("%s\n",ret); } /*printf("%s\n", strtok(arr1, p)); */ //printf("%s\n", strtok(NULL, p)); //printf("%s\n", strtok(NULL, p)); return 0; }


8.strerror函数的介绍 c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

该函数相关信息如下:
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

功能介绍:
错误报告函数,把错误码转换为对应的错误信息,返回错误信息对应的字符串的起始地址。
那么我们平时如何使用呢?
首先引入头文件
#include #include int main() { FILE *pf=fopen("test.txt","r"); if(pf==NULL) printf("fopen%s\n",strerror(error)); return0; }

实现效果:
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片


9.字符操作函数
(1)字符分类函数 c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片


(2)字符转换函数 c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

具体这里就不做更多介绍…

二、内存操作函数介绍 ??上述函数都是字符串或字符操作函数,那么如果我们想要拷贝一个整形数组,或者其他类型的数据,我们不能用字符串操作函数时,我们应该怎样拷贝呢?
??在这里,我们引入内存操作函数的概念,我们直接对数据的内存进行操作。

1.memcpy函数的介绍和模拟实现
(1)memcpy函数的功能 c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

memcpy函数的作用:在两个内存缓冲区进行拷贝数据
返回dest的起始地址处
我们发现memcpy函数的前两个参数都是void * 类型的,第三个参数是拷贝的字节数。
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

(2)memcpy函数的使用
#include #include int main() { int arr1[] = { 1, 2, 3, 4, 5 }; int arr2[10] = { 0 }; memcpy(arr2, arr1, sizeof(arr1)); int i = 0; for (i = 0; i < 10; i++) { printf("%d", arr2[i]); } return 0; }

代码实现效果:
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片



(3) memcpy函数的模拟实现
void * my_memcpy(void * dest, void * src, int num) { char*ret = (char *)dest; while (num--) { *(char *)dest = *(char *)src; ++(char *)dest; ++(char *)src; } return ret; }

结构体数据的拷贝过程如下:
struct S { char name[20] ; int age; }; void * my_memcpy(void * dest, void * src, int num) { char*ret = (char *)dest; while (num--) { *(char *)dest = *(char *)src; ++(char *)dest; ++(char *)src; } return ret; }int main() { struct S arr1[] = { { "chen", 11 }, {"hai",20} }; struct S arr2[10] ; my_memcpy(arr2, arr1, sizeof(arr1)); int i = 0; for (i = 0; i < 2; i++) { printf("%s %d ", arr2[i].name,arr2[i].age); } return 0; }

【c语言|C语言进阶(五)——字符串+内存函数的介绍】实现效果如下
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

(4)memcpy函数的缺点 现在有一个要求:
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

??所以,我们并不能按照我们的要求打印,内存相互重叠的情况下,内存的数字会发生改变。而在memmove 函数中则完美的解决了这个问题(内存重叠)。

2.memmove函数的介绍和模拟实现
(1)memmove函数的功能 ??memmove和memcopy 功能 和 函数的参数 都大部分相同
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

区别的是:
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

(2)memmove函数的模拟实现 首先我们要明确怎样拷贝不影响内存重叠
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

将 2,3,4,5 拷贝到 4,5,6,7。
这种情况下 src 将 6,7,8,9 拷贝到4,5,6,7.
这种情况下 src>dest,我们将src中的数据从前向后进行拷贝,可以避免内存重叠的影响。
我们模拟实现时,考虑如何从后向前拷贝,如何从前向后拷贝。
#include void* my_memmove(void * dest, void *src, int num) { char * ret = (char*)dest; assert(dest&&src); if (src > dest) { //从前向后 while (num--) { *(char*)dest = *(char*)src; ++(char*)dest; ++(char*)src; } } else if (src < dest) while (num--) { *((char*)dest + num) = *((char*)src + num); } return ret; }

代码实现效果:
c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

避免了内存重叠,成功实现!!

3.memcmp函数的介绍 c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

(1)memcmp函数的功能 对各种类型进行比较
(2)memcmp函数的使用 例:整形数据的比较
int main() { int arr1[] = { 1, 5, 6, 7, 8, 9 }; int arr2[] = { 1, 2, 3, 4, 5, 6 }; int ret=memcmp(arr1, arr2, 8); printf("%d\n", ret); return 0; }

c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片



4.memset函数的介绍 c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片

c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片



(1)memset函数功能 ??函数的三个参数(目标的起始指针处,设置的字符,设置修改字符的字节),将目标的字符串或者其他数据改为设置的字符或其他类型。

(2)memset函数的使用
int main() { char arr[] = "###########"; memset(arr, '*', 5); printf("%s\n", arr); }

c语言|C语言进阶(五)——字符串+内存函数的介绍
文章图片





好了,内存+字符串函数的说明就介绍到这里,希望大家多多练习,谢谢欣赏!!






未完待续!!


C语言进阶(六)——自定义类型详解(结构体+枚举+联合)已更新

    推荐阅读