C字符串+内存操作函数strlen strcpy strcmp strstr strtok strerror memcpy memmove memset memcmp

 C语言本身没有字符串类型,字符串通常放在常量字符串或者字符数组中,字符串常量适用于那些对它不做修改的字符串函数。

目录

1. 字符串函数strlen strcpy strcmp

1.1 strlen函数介绍

1.1.1 strlen使用与模拟

一、使用

二、三种模拟实现

1.2 strcpy函数介绍

1.2.1 strcpy使用与模拟

一、使用

 二、模拟

1.3 strcat函数介绍

1.3.1 strcat使用与模拟

一、使用

 二、模拟

1.4  strcmp函数介绍

1.4.1 strcmp函数使用与模拟

一、使用

 二、模拟

2. 字符串函数strncpy strncat strncmp

2.1 strncpy

 一、使用

2.2 strncat

2.3 strncmp

3. 字符串函数strstr strtok strerror

3.1 strstr函数介绍

3.1.1strstr函数使用与模拟

一、使用

二、模拟

3.2 strtok函数介绍

3.2.1strtok函数使用

一、使用

3.3 strerror函数介绍

3.3.1strerror函数使用

一、使用

4. 内存操作函数

4.1 memcpy函数介绍

一、使用

二、模拟

4.2 memmove函数介绍

一、使用

二、模拟

4.3 memset函数介绍

一、使用

4.4 memcmp函数介绍


1. 字符串函数strlen strcpy strcmp

1.1 strlen函数介绍

使用需引用头文件<string.h>

size_t strlen(const char*string);

功能:字符串以'\0'作为结束标志,strlen函数返回的值为在字符串'\0'之前出现的字符个数

           返回类型为size_t,无符号整型

1.1.1 strlen使用与模拟

一、使用

在使用strlen时,只需要把地址传入即可

#include <stdio.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; 
}

 "abcdef"和"bbb"都为常量字符串,相当于把a,b的地址分布存入到str1和str2中,其中的strlen(str1)为6,strlen(str2)为3。

3-6原本应为-3,因为都为无符号数,所以其结果大于0。输出"str2>str1"。

所以在比较长度大小时要避免使用这种相减的方式,直接进行比较大小或强制转换为int型后进行相减。

二、三种模拟实现

计数器

int istrlen(const char*string)
{
    int count=0;
    while(*string != '\0')
    {
        count++;
        string++;
    }
    return count;
}

递归

int istrlen1(const char* string)
{
    if (*string != '\0')
    {
        return 1 + istrlen1(++string);//string++错,后置++

    }
    else
        return 0;
    
}

指针-指针

int istrlen2(const char* string)
{
    const char* p = string;
    while (*string != '\0')
    {
        string++;
    }
    return string - p;
}

1.2 strcpy函数介绍

使用需引用头文件<string.h>

char* strcpy(char* dest,const char* src);

功能:源字符串必须以'\0'结束;目标空间必须足够大,以确保能存放源字符串;目标空间必须可   变;拷贝时会将源字符串中的'\0'拷贝到目标空间。

1.2.1 strcpy使用与模拟

一、使用

使用时strcpy(add1,add2);add1传入目标字符串地址,add2传入源字符串元素地址。

#include<stdio.h>
#include<string.h>
int main()
{

 char arr[20]="asdfg";
 char arr1[]="mmm";
 strcpy(arr,arr1);
 printf("%s\n",arr);
 printf(arr);

 return 0;
}

 运行结果如下图,strcpy会将目标空间覆盖拷贝。

 

 二、模拟


char* strcpy1(char* arr, const char* arr1)
{
    char* p = arr;
    assert(arr != NULL);//不满足条件报错
    assert(arr1 != NULL);
    while (*arr++ = *arr1++)//后置++,先赋值后++
    {
        ;
    }
    return p;
}

1.3 strcat函数介绍

 使用需引用头文件<string.h>

char* strcat(char* dest,const char* src);

功能:源字符串必须以'\0'结束;目标空间必须足够大,以确保能存放源字符串;目标空间必须可修改。

1.3.1 strcat使用与模拟

一、使用

使用时strcat(add1,add2);add1传入目标字符串地址,add2传入源字符串元素地址。

#include<stdio.h>
#include<string.h>
int main()
{
 char arr[20]="wfghjkl";
 char arr1[]="Zxcvbn";
 strcat(arr,arr1);
 printf("%s",arr);

 return 0;
}

 strcat会在目标字符串的'\0'处把源字符串内容拼接上去。

 

自己接自己,由于'\0'被覆盖,将会发生一直循环放入,直至这个数组空间存满,例如上述的arr数组

 二、模拟

char* strcat1(char* str,const char* str1)
{

    assert(str);
    assert(str1);
    char* p=str;
    while (*str)//*str++多加一次超过\0
    {
        str++;
    }
    while ((*str++=*str1++))
    {
        ;
    }
    return p;
}

1.4  strcmp函数介绍

 使用需引用头文件<string.h>

int strcmp(char* str,const char* str1);

功能:第一个字符串大于第二个字符串,返回大于0的数字;

           第一个字符串等于第二个字符串,返回等于0的数字;

           第一个字符串小于第二个字符串,返回小于0的数字;

           注意返回的具体数字每个编译器有不同的结果。

1.4.1 strcmp函数使用与模拟

一、使用

使用时strcmp(add1,add2);add1传入需比较字符串地址,add2传入要比较字符串元素地址。

#include<stdio.h>
#include<string.h>
int main()
{
 char arr[20]="wfghjkl";
 char arr1[]="Zxcvbn";
 
 printf("%d",strcmp(arr,arr1));

 return 0;
}

 strcmp在进行比较是会从第一个字符开始,逐个进行其ASCII码值的大小比较,如果前几个字符相同,会一直比较到不同字符得出结果。

 

 二、模拟

int strcmp1(const char* string, const char* string1)
{
    assert(string != NULL);
    assert(string1 != NULL);
    while (*string||*string1)//有1个到了'\0'就该出结果了
    {
        if (*string > *string1)
        {
            return 1;
        }
        else if (*string == *string1)
        {
            string++;
            string1++;
        }
        else
            return -1;
    }
    return 0;
}

2. 字符串函数strncpy strncat strncmp

从前面的strcpy,strcat,strcmp中我们可以发现要进行拷贝,追加,比较时,无法指定源字符串中字符的具体个数,而这几个函数可以帮我们实现这个功能。

2.1 strncpy

  其中的size_t num单位是字节。

char* strncpy(char* dest,const char* source,size_t num);

 一、使用

#include<stdio.h>
#include<string.h>
int main()
{
  char arr[]="qwerttyr";
  char arr1[]="wasd";
  strncpy(arr,arr1,2);
  printf(arr);

  return 0;
}

 

 其模拟实现,以下两个函数的模拟介绍与strcpy,strcat,strcmp类似就不在做详细描述。

2.2 strncat

char* strncpy(char* dest,const char* source,size_t num);

2.3 strncmp

int* strncpy(const char* dest,const char* source,size_t num);

3. 字符串函数strstr strtok strerror

3.1 strstr函数介绍

  使用需引用头文件<string.h>

char* strstr(const char* str,const char* str1);

功能:寻找在str字符串中是否含有str1字符串相同内容

           找到后返回被查找字符串的首元素地址,失败返回NULL,

           如果查的是char arr[]={0},也返回被查找字符串首元素地址。

3.1.1strstr函数使用与模拟

一、使用

使用时strstr(add1,add2);add1传入需要在被查找的字符串地址,add2传入需要查找的字符串地址

#include <stdio.h>
#include <string.h>
int main ()
{
  char str[] ="This is a simple string";
  char * pch;
  pch = strstr (str,"simple");
  strncpy (pch,"sample",6);
  puts (str);
  return 0;
}

 

二、模拟

我们需要创建一个指针来存放被查找字符串首元素地址,和一个依次往后用于移动查找的指针

char* strstr1(const char*s1,const char*s2)
{
    char* p = (char*)s1;//用于输出打印
    char* ss2 = (char*)s2;//存放查找数组首地址
    if (!*s2)//s2空把s1全打出来
    {
        return p;
    }
    while (*s1)//s1遍历完没结果就没找到
    {
        s2 = ss2;//找一次,找不到返回首地址
        s1 = p;//怕bbbcsf,bbc这种情况一次加一个找
        while (*s2 && *s1 && !(*s1 - *s2))//一直往后找s1,s2,,!(*s1-*s2)相等继续
        {
            s1++;
            s2++;
        }//s1和s2完全相同,会越界
            if(!*s2)//s2到0说明找到了,越界了也行
            {
                return p;
            }
            p++;//没找到指标后移
    }
        return NULL;
    
}

3.2 strtok函数介绍

 使用需引用头文件<string.h>

char* strtok(char* str,const char* set);

功能:切割函数

          set参数是个字符串,定义了用作分隔符的字符集合

          第一个参数指定一个字符串它包含了0个或者多个由set字符串中一个或者多个分隔符分割的标记。
          

3.2.1strtok函数使用

一、使用

strtok函数找到str中的下一个标记,并将标记变成\0 ,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)

strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。

strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
 如果字符串中不存在更多的标记,则返回 NULL 指针。
#include <stdio.h>
#include <string.h>
int main()
{
    char str[] = "- Me, a handsome boy.";
    printf("%p\n", str);
    printf("M的地址%p\n", str+2);
    printf("a的地址%p\n", str+6);
    printf(".的地址%p\n", str+20);
    char* pp;
    printf("%s\n", str);
    pp = strtok(str, " ,.-");
    printf("%p\n", pp);
    printf("%s\n", pp);
    printf("\n\n\n", pp);
    while (pp != NULL)
    {
        printf("%s\n", pp);

        pp = strtok(NULL, " ,.-");
        printf("%p\n", pp);
    }
    return 0;
}

 简单来说strtok会把遇到字符前的所有分隔符切掉,并返回遇到第一个字符的地址,并将字符后的分隔符变为'\0',再次进行传参时可以直接传NULL,函数会记住上一次分割符的位置,接着往后找,循环这个过程,直到找到字符串结束位置'\0'。

3.3 strerror函数介绍

  使用需引用头文件<string.h>

char* strerror(int errnum);

功能:返回错误码所对应的错误信息。

3.3.1strerror函数使用

一、使用

比如我们搜索网页时出现404,这个404就是一个错误码,用strerror用来查看其对应的错误信息

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
int main ()
{
  int* p=(int*)malloc(INT_MAX);
   if (p == NULL)
   {
     printf (strerror(errno));//errno为错误码,会自动放入,使用需引用头文件erron.h
   }
   perror("Malloc");//不需要使用printf可以直接打印出,Malloc:对应错误信息,字母大小写不影响
   return 0; 
}

4. 内存操作函数

上面介绍的函数只能对字符串进行操作,但是如果我们对整型数组或者其它类型数组操作就不适用,这个时候就轮到我们的内存操作函数登场了。

4.1 memcpy函数介绍

使用需引用头文件<string.h>或<memory.h>都可

void* memcpy (void* dest,const void* src,size_t num);

 功能:函数从src的位置开始向后复制num个字节到dest的内存位置

            此函数进行复制时遇到'\0'时并不会停下来

            如果src和dest有任何的重叠,复制的结果是未定义的

提示:现在的编译器已经将memcpy和memmove的功能实现的一样,不会出现上述情况,但我们仍需了解一下原本二者的区别所在。

一、使用

#include <stdio.h>
#include <string.h>
int main()
{
    int arr[] = { 1,1,1,1,1,1 };
    int arr1[] = { 22,55,44 };
    int i;
    for (i = 0;i < 6;i++)
    {
        printf("%d ", *((int*)(memcpy(arr, arr1, 4))+i));
    }
    
    return 0;
}

 当自己对自己复制产生空间重叠又会发生什么,我们在模拟的函数中可以进行观察

#include <stdio.h>
#include <string.h>
int main()
{
    int arr[] = { 1,2,3,4,5,6 };
    int i;
    for (i = 0;i < 6;i++)
    {
        printf("%d ", *((int*)(memcpy(arr, arr+1, 8))+i));
    }
    
    return 0;
}

二、模拟

void* f_memcpy(void* dest, const void* src, int count)
{
    assert(dest && src);
    void* ret = dest;
    while (count--)
    {
        *(char*)dest = *(char*)src;
        dest = (char*)dest + 1;
        src = (char*)src + 1;
    }
    return ret;
}

 当自己对自己进行复制发生空间重叠时

 可以看到并没有像我们预想的那样变成asddf,因为f在往后复制时已经被d给覆盖掉了。

4.2 memmove函数介绍

使用需引用头文件<string.h>

void* memmove (void* dest,const void* src,size_t num);

 功能:和memcpy的区别就是memmove函数处理时,源内存块和目标内存块是可以重叠的,也就是说我们可以在同一个数组内部进行操作,不需要两个数组。

一、使用

#include <stdio.h>
#include <string.h>
int main ()
{
  char str[] = "memmove can be very useful......";
  memmove (str+20,str+15,11);
  puts (str);

  return 0;
}

 

二、模拟

分两种情况进行考虑

void* f_memmove(void* dest, const void* src, int count)//一个数组内部操作
{
    assert(dest&&src);
    void *mm= dest;
    if (dest < src)//从前往后拷
    {
        while (count--)
        {
            *(char*)dest = *(char*)src;
            dest = (char*)dest + 1;
            src = (char*)src + 1;
        }
    }
    else
    {
        while (count--)
        {
            *((char*)dest + count) = *((char*)src + count);
        }
    }
    return mm;

}

4.3 memset函数介绍

使用需引用头文件<string.h>或<memory.h>

void* memset (void* dest,int c,size_t num);

 功能:以字节为单位初始化内存单元;

            c为要每个字节要设置的数字;

            num为要操作的字节数。

一、使用

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

int main()
{
    int arr[] = { 1,2,8,7,9,2 };
    memset(arr, 10, 4);
    int i;
    for (i = 0; i < 6; i++)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}

 arr数组中的1,补码为00000000000000000000000000000001

                          转换为16进制为00 00 00 01  4个字节

                          每个字节变为10,变为16进制为A,0A 0A 0A 0A

                          计算得出168430090

 

4.4 memcmp函数介绍

使用需引用头文件<string.h>或<memory.h>

void* memcmp (const void* dest,const void* dest1,size_t num);

 功能:比较dest和dest1指针开始的num个字节;

           第一个字符串大于第二个字符串,返回大于0的数字;

           第一个字符串等于第二个字符串,返回等于0的数字;

           第一个字符串小于第二个字符串,返回小于0的数字;

           比较过程和strcmp函数类似就不再做具体介绍了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值