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


文章目录


一、字符串函数的介绍

前言

  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;}

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

(2)strlen函数功能

通过msdn函数功能查找得知strlen具体使用情况如下

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

  strlen的功能是获取字符串的长度,函数内部传的参数类型是 char *,返回的类型是size_t类型。返回值是字符串中字符出现的个数。

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

(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。但是实际上打印的结果却并不是我们想的那样。

C语言进阶(五)——字符串+内存函数的介绍
  打印结果为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;}

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

(2)strcpy函数功能

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

  我们得知,strcpy是字符串拷贝函数,他的功能就是拷贝字符串,函数内部的参数:第一个参数是目标字符串,第二个参数是 char* str Source (起始字符串),最后将起始字符串拷贝到目标字符串中,达到最终效果。函数返回类型是 char*。返回值是目标字符串的起始地址处。

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

(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;}

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

(2)strcat函数功能及使用

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

  该函数的功能是追加一个字符串,函数内部的参数:第一个参数是char*str Destination(目标字符串),第二个参数是 起始字符串,将源字符串追加到目标字符串后。返回类型是char *。返回的是目标字符串的起始地址处。

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

(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;}

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

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;}

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

(2)strcmp函数功能

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

  strcmp函数的函数功能是比较两个字符串,那么如何进行比较呢?strcmp函数比较的是字符串对应的字符的ASCII码值,返回值是int类型的,分别向函数内部传入两个字符串s1、s2。

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语言进阶(五)——字符串+内存函数的介绍
功能介绍:

1.拷贝count个字符从源字符串到目标空间。

2.如果源字符串的长度小于count,则拷贝完源字符串之后,在目标的后边追加0,直到count个。


(2)strncat函数的介绍

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

1.将source的num个字符追加到destination

2.如果source中的字符串长度小于num,则只复制到结束空字符之前的内容。


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

(3) strncmp函数的介绍

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");}elseprintf("%s\n",ret );return 0;}

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

(2)strstr函数的功能

通过msdn函数功能查找得知strlen具体使用情况如下
C语言进阶(五)——字符串+内存函数的介绍
C语言进阶(五)——字符串+内存函数的介绍
  我们可得知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是一个用来分隔字符串的函数。
C语言进阶(五)——字符串+内存函数的介绍
C语言进阶(五)——字符串+内存函数的介绍

下面给一个例子来演示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;}

代码显示效果:
C语言进阶(五)——字符串+内存函数的介绍
好了,那么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函数的介绍

C语言进阶(五)——字符串+内存函数的介绍
该函数相关信息如下:
C语言进阶(五)——字符串+内存函数的介绍
功能介绍:

错误报告函数,把错误码转换为对应的错误信息,返回错误信息对应的字符串的起始地址。

那么我们平时如何使用呢?

首先引入头文件 <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;}

实现效果:

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


9.字符操作函数


(1)字符分类函数

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


(2)字符转换函数

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

C语言进阶(五)——字符串+内存函数的介绍
具体这里就不做更多介绍…


二、内存操作函数介绍

  上述函数都是字符串或字符操作函数,那么如果我们想要拷贝一个整形数组,或者其他类型的数据,我们不能用字符串操作函数时,我们应该怎样拷贝呢?

  在这里,我们引入内存操作函数的概念,我们直接对数据的内存进行操作。


1.memcpy函数的介绍和模拟实现


(1)memcpy函数的功能

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

memcpy函数的作用:在两个内存缓冲区进行拷贝数据

返回dest的起始地址处

我们发现memcpy函数的前两个参数都是void * 类型的,第三个参数是拷贝的字节数。

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

(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;}

代码实现效果:

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语言进阶(五)——字符串+内存函数的介绍

(4)memcpy函数的缺点

现在有一个要求:
C语言进阶(五)——字符串+内存函数的介绍
C语言进阶(五)——字符串+内存函数的介绍
  所以,我们并不能按照我们的要求打印,内存相互重叠的情况下,内存的数字会发生改变。而在memmove 函数中则完美的解决了这个问题(内存重叠)。


2.memmove函数的介绍和模拟实现


(1)memmove函数的功能

  memmove和memcopy 功能 和 函数的参数 都大部分相同
C语言进阶(五)——字符串+内存函数的介绍
区别的是:
C语言进阶(五)——字符串+内存函数的介绍

(2)memmove函数的模拟实现

首先我们要明确怎样拷贝不影响内存重叠

C语言进阶(五)——字符串+内存函数的介绍
将 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;}

代码实现效果:
C语言进阶(五)——字符串+内存函数的介绍
避免了内存重叠,成功实现!!


3.memcmp函数的介绍

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语言进阶(五)——字符串+内存函数的介绍

4.memset函数的介绍

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

(1)memset函数功能

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


(2)memset函数的使用

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

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




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






未完待续!!



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

上一篇:Java学习实例——数组_评委打分


下一篇:稀疏数组