文章目录
-
一、字符串函数的介绍
- 前言
- 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)字符转换函数
- 二、内存操作函数介绍
- 未完待续!!
一、字符串函数的介绍
前言
C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串或者字符数组中。字符串常量适用于那些对他不做修改的字符串函数。
1.strlen函数的介绍及模拟实现
(1)strlen函数的使用
#include <stdio.h>#include <string.h>int main(){//字符串函数的实现 //字符串函数的功能char a[6] = "abcde";int len = strlen(a);printf("%d\n", len);return 0;}
执行效果如下:
(2)strlen函数功能
通过msdn函数功能查找得知strlen具体使用情况如下
strlen的功能是获取字符串的长度,函数内部传的参数类型是 char *,返回的类型是size_t类型。返回值是字符串中字符出现的个数。
(3)strlen的模拟实现
size_t my_strlen(const char* p){int count = 0;while (*p){ count++; p++;}return count;}
(4)易错点
注意:
#include <stdio.h>#include <string.h>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。但是实际上打印的结果却并不是我们想的那样。
打印结果为str2>str1.那么我们想是strlen(str2)— strlen(str1)>0吗?并不是的,还记得我们说的strlen的返回类型是size_t 无符号数,是不存在负数的,减到小于0是会成为一个很大很大的数字,此时结果还是大于0,所以会出现上述打印的结果,这点很容易出现错误。牢记strlen的返回类型是无符号整型。
2.strcpy函数的介绍及模拟实现
(1)strcpy函数的使用
#include <stdio.h>#include <string.h>int main(){char arr1[30] = "*********************";char arr2[] = "hello world";/*strcpy(arr1,arr2);*/printf("%s\n", strcpy(arr1, arr2));return 0;}
执行代码效果如下:
(2)strcpy函数功能
通过msdn函数功能查找得知strlen具体使用情况如下
我们得知,strcpy是字符串拷贝函数,他的功能就是拷贝字符串,函数内部的参数:第一个参数是目标字符串,第二个参数是 char* str Source (起始字符串),最后将起始字符串拷贝到目标字符串中,达到最终效果。函数返回类型是 char*。返回值是目标字符串的起始地址处。
(3)strcpy 函数的模拟实现
#include <stdio.h>#include <string.h>#include <assert.h>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;}
代码实现效果:
(2)strcat函数功能及使用
通过msdn函数功能查找得知strlen具体使用情况如下
该函数的功能是追加一个字符串,函数内部的参数:第一个参数是char*str Destination(目标字符串),第二个参数是 起始字符串,将源字符串追加到目标字符串后。返回类型是char *。返回的是目标字符串的起始地址处。
(3)strcat字符追加函数的模拟实现
首先我们问一个问题,如何实现字符追加,首先第一步先要找到目标字符串的’\0 ‘,然后将目标函数的’ \0 ‘改为源字符串的初始指针,再将src赋给dest直到*src=’\0’,返回目标字符串的初始指针的地址处。
代码实现:
#include <stdio.h>#include <assert.h>#include <string.h>char* my_strcat(char*dest, const char*src){assert(dest && src);char *ret = dest;//1.找到目标空间的\0while (*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 <stdio.h>#include <string.h>int main(){ char arr="abc"; strcat(arr,arr); return 0;}
4.strcmp函数的介绍及模拟实现
(1)strcmp函数的使用
注意:
strcmp函数比较的不是字符串的长度,而是字符串对应字符的ASCII码值
#include <stdio.h>#include <string.h>int main(){ char arr1[]="abcdef"; char arr2[]="abc"; if(strcmp(arr1,arr2)<0) printf("arr1<arr2\n"); else if(strcmp(arr1,arr2)>0) printf("arr1>arr2\n"); else if(strcmp(arr1,arr2)==0) printf("arr1=arr2"); return 0;}
代码显示效果:
(2)strcmp函数功能
strcmp函数的函数功能是比较两个字符串,那么如何进行比较呢?strcmp函数比较的是字符串对应的字符的ASCII码值,返回值是int类型的,分别向函数内部传入两个字符串s1、s2。
(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函数的介绍
功能介绍:
1.拷贝count个字符从源字符串到目标空间。
2.如果源字符串的长度小于count,则拷贝完源字符串之后,在目标的后边追加0,直到count个。
(2)strncat函数的介绍
功能介绍:
1.将source的num个字符追加到destination
2.如果source中的字符串长度小于num,则只复制到结束空字符之前的内容。
实现效果如下:
(3) strncmp函数的介绍
功能介绍:
比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。
6.strstr函数的介绍和模拟实现
(1)strstr函数的使用
int main(){char arr1[] = "abbbcdef";char arr2[] = "bcde";char * ret = strstr(arr1, arr2);if (ret == NULL){printf("找不到字串\n");}elseprintf("%s\n",ret );return 0;}
代码实现效果:
(2)strstr函数的功能
通过msdn函数功能查找得知strlen具体使用情况如下
我们可得知strstr函数的功能是查找一个字串,或者截取一个字串。第一个参数传一个字符串,第二个参数传一个要查找的字符串。返回类型是char *,如果查找到了,那么返回字符串中查找到的那个字符的指针,直到\0结束。如果未查找到,那么就返回NULL。
(3)strstr函数的模拟实现
#include <stdio.h>#include <string.h>#include <assert.h>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是一个用来分隔字符串的函数。
下面给一个例子来演示strtok的具体功能
#include <stdio.h>#include <string.h>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;}
代码显示效果:
好了,那么strtok函数,我们应该怎样使用呢?
对于第一、二条规则,我们用一个字符串来记录分隔符的集合。(以分隔符为标记,从而进行分割字符串操作)
strtok操作会对字符串进行修改,所以我们要拷贝内容到另一个字符串中。
以上面的例子代码为例,strtok 的第一个参数不为NULL,我们进行 strtok(arr1,p),将第一个分隔符@,改为\0。同时函数保存了第一个分隔符的位置。
第二次传参为NULL,我们进行 strtok(NULL,p),此时的NULL虽然传了一个空指针,但是指向了上一次保存的分隔符的位置。从这个位置开始,将下一个分隔符.,改为\0。同时函数保存此位置。
依次进行该操作…
可能有同学会问了:函数内部的变量出函数不是销毁了么,函数怎么保存一个地址变量呢?
我们猜测:在C语言关键字的学习中,我们学到了一个static 的关键字,出了函数也能保存下来。可能这个函数的实现过程中存在一个static关键字,所以每次的标记位置得以保存…
但是我们如果不知道字符串内部有多少分隔符,而且strtok(NULL,p)的操作重复多次,显得冗余,如何进行简化呢?
给出的解决冗余方案:
#include <stdio.h>#include <string.h>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函数的介绍
该函数相关信息如下:
功能介绍:
错误报告函数,把错误码转换为对应的错误信息,返回错误信息对应的字符串的起始地址。
那么我们平时如何使用呢?
首先引入头文件 <error.h>
#include <stdio.h>#include <error.h>int main(){FILE *pf=fopen("test.txt","r");if(pf==NULL)printf("fopen%s\n",strerror(error));return 0;}
实现效果:
9.字符操作函数
(1)字符分类函数
(2)字符转换函数
具体这里就不做更多介绍…
二、内存操作函数介绍
上述函数都是字符串或字符操作函数,那么如果我们想要拷贝一个整形数组,或者其他类型的数据,我们不能用字符串操作函数时,我们应该怎样拷贝呢?
在这里,我们引入内存操作函数的概念,我们直接对数据的内存进行操作。
1.memcpy函数的介绍和模拟实现
(1)memcpy函数的功能
memcpy函数的作用:在两个内存缓冲区进行拷贝数据
返回dest的起始地址处
我们发现memcpy函数的前两个参数都是void * 类型的,第三个参数是拷贝的字节数。
(2)memcpy函数的使用
#include <stdio.h>#include <memory.h>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;}
代码实现效果:
(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;}
实现效果如下
(4)memcpy函数的缺点
现在有一个要求:
所以,我们并不能按照我们的要求打印,内存相互重叠的情况下,内存的数字会发生改变。而在memmove 函数中则完美的解决了这个问题(内存重叠)。
2.memmove函数的介绍和模拟实现
(1)memmove函数的功能
memmove和memcopy 功能 和 函数的参数 都大部分相同
区别的是:
(2)memmove函数的模拟实现
首先我们要明确怎样拷贝不影响内存重叠
将 2,3,4,5 拷贝到 4,5,6,7。
这种情况下 src<dest, 我们将src中的数据从后向前进行拷贝,就可以避免内存重叠的影响。
将 6,7,8,9 拷贝到4,5,6,7.
这种情况下 src>dest,我们将src中的数据从前向后进行拷贝,可以避免内存重叠的影响。
我们模拟实现时,考虑如何从后向前拷贝,如何从前向后拷贝。
#include <assert.h>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;}
代码实现效果:
避免了内存重叠,成功实现!!
3.memcmp函数的介绍
(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;}
4.memset函数的介绍
(1)memset函数功能
函数的三个参数(目标的起始指针处,设置的字符,设置修改字符的字节),将目标的字符串或者其他数据改为设置的字符或其他类型。
(2)memset函数的使用
int main(){char arr[] = "###########";memset(arr, '*', 5);printf("%s\n", arr);}
好了,内存+字符串函数的说明就介绍到这里,希望大家多多练习,谢谢欣赏!!
未完待续!!
C语言进阶(六)——自定义类型详解(结构体+枚举+联合)已更新