C语言——字符串 + 内存函数详解整理

目录

一.函数介绍

求字符串长度

strlen

长度不受限制的字符串函数

1. strcpy 

2. strcat 

3. strcmp

长度受限制的字符串函数

1. strncpy

2. strncat

3.strncmp

字符串查找

1. strstr

2. strtok 

错误信息报告

 strerror

 字符分类和转换函数

  ​编辑内存操作函数

1. memcpy

2. memmove

3. memset

4. memcmp

二. 上述常用库函数的模拟实现

1.模拟实现strlen

2. 模拟实现strcpy

 3. 模拟实现strcat

 4. 模拟实现strstr

5. 模拟实现strcmp

6. 模拟实现memcpy

7. 模拟实现memmove

 


一.函数介绍

求字符串长度

strlen

  size_t strlen ( const char * str );

  字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' )。

  参数指向的字符串必须要以 '\0' 结束。

  注意函数的返回值为size_t,是无符号的( 易错 ),如下示例:

长度不受限制的字符串函数

1. strcpy 

  char* strcpy(char * destination, const char * source );

  拷贝字符串

  将指向的 C 字符串拷贝到目标指向的数组中,包括终止字符 '\0'(并在该点停止),是一种覆盖。

  源字符串必须以 '\0' 结束,且目标空间必须可修改。
  为避免溢出destination 指向的数组的大小应足够长,以包含与 source 相同的 C 字符串(包括终止字符 '\0' )。

   返回指向目标数组的起始地址,即destination,如下示例:

2. strcat 

  char * strcat ( char * destination, const char * source );

  连接字符串

  字符串的拷贝追加到目标字符串。destination 中的终止字符 '\0' 被 source 的第一个字符覆盖,并且在 destination 中由两者串联形成的新字符串的末尾包含一个结束字符 '\0'。

  源字符串必须以 '\0' 结束。

  目标空间必须有足够的大,能容纳下源字符串的内容。

  目标空间必须可修改。 

   返回destination,如下示例:

  注意:目的地destination来源source不得重叠,否则会发生错误,如下示例:

  由于目的地和源串是同一块空间,那么目的地的终止字符'\0'被覆盖的同时,源串的终止字符也被修改了,导致了死循环,进而引发了数组的越界访问操作。

3. strcmp

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

  比较两个字符串

  将 C 字符串 str1 与 C 字符串 str2 进行比较。

  此函数从每个字符串的第一个字符开始比较,如果它们彼此相等,则继续以下对,直到字符不同或达到终止字符 '\0'。

  标准规定:

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

        第一个字符串 == 第二个字符串,则返回0

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

  如下示例:

长度受限制的字符串函数

1. strncpy

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

  从源字符串拷贝num个字符到目标空间。

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

  如下示例:

 

2. strncat

  char * strncat ( char * destination, const char * source, size_t num ); 

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

  如果 source 的长度大于 num,则不会在目标末尾隐式追加 终止字符 ‘\0'。因此,在这种情况下,destination 不应被视为以 '\0' 结尾的 C 字符串(这样读取它可能会溢出)。 

  如下示例:

3.strncmp

  int strncmp ( const char * str1, const char * str2, size_t num ); 

  比较num个字符,如下示例:

字符串查找

1. strstr

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

  查找子字符串

  返回指向 str1 中 str2 第一次出现的指针,如果 str2 不是 str1 的一部分,则返回 null 指针。

  匹配过程不包括终止字符 '\0',但到此为止。

  如下示例:

2. strtok 

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

  将字符串拆分为标记

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

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

  对此函数的一系列调用将 str 拆分为标记,标记是由分隔符中的任何字符分的连续字符序列。

  在第一次调用时,该函数需要一个 C 字符串作为 str 的参数,扫描第一个标记的起始位置。在后续调用中,该函数需要一个空指针NULL,并使用最后一个标记末尾的位置作为扫描的新起始位置。

  为了确定标记的开头和结尾,该函数首先从起始位置扫描分隔符中未包含的第一个字符(该字符将成为标记的开头)。然后从此标记的开头开始扫描分隔符中包含的第一个字符,该字符成为该标记的结尾。如果找到终止字符,扫描也会停止。

 标记的末尾自动替换为终止字符 '\0',并且标记的开头由函数返回。

  在对 strtok 的调用中找到 str 的终止字符后,对此函数的所有后续调用(将 null 指针作为第一个参数)将返回一个 null 指针。

  找到最后一个标记的点由要在下一次调用中使用的函数在内部保留(不需要特定的库实现来避免数据争用)。

  注: strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。

  来看具体示例:

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

int main ()
{
  char str[] ="- This, a sample string.";
  char tmp[50] = {0};
  strcpy(tmp, str);
  char * pch= strtok (tmp," ,.-");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ,.-");
  }
  return 0;
}

//输出:
This
a
sample
string

  建议粘贴以上代码,再结合文字叙述,自行调试观察。

错误信息报告

 strerror

  char * strerror ( int errnum ); 

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

  库函数在执行的时候,如果发生错误,就会将一个错误码存放在一个叫errno的变量中,这个变量是C语言提供的一个全局变量,包含在 errno.h 这个头文件中。 

  如下示例:

 字符分类和转换函数

  头文件:ctype.h

  内存操作函数

都是以字节为基本操作单位。

1. memcpy

  void * memcpy ( void * destination, const void * source, size_t num );

  指针和目标指针指向的对象的基础类型与此函数无关。

  函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。

  这个函数在遇到 '\0' 的时候并不会停下来。

  如果source和destination有任何的重叠,复制的结果都是未定义的。

  返回 destination

  如下示例:

2. memmove

  void* memmove(void* destination, const void* source, size_t num);

  移动内存块

  和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。

  如果源空间和目标空间出现重叠,就得使用memmove函数处理。

  返回destination.

  如下示例:

3. memset

void * memset ( void * ptr, int value, size_t num );

  填充内存块

  把指向ptr的连续num个字节设为特定值value。

  注意:value该值以 int 形式传递,但该函数使用此无符号 char 转换填充内存块,也就是说会发生截断。

  返回ptr。

  如下示例:

4. memcmp

  int memcmp ( const void * ptr1, const void * ptr2, size_t num );

  比较从ptr1和ptr2指针开始的num个字节。

  判断的返回值和strcmp一样。

  

二. 上述常用库函数的模拟实现

1.模拟实现strlen

//方式一:计数器
int my_strlen(const char * str)
{
 int count = 0;
 while(*str)
 {
 count++;
 str++;
 }
 return count;
}

//方式二:递归
int my_strlen(const char * str)
{
 if(*str == '\0')
 return 0;
 else
 return 1+my_strlen(str+1);
}

//方式三:指针 - 指针
int my_strlen(char *s)
{
       char *p = s;
       while(*p != ‘\0’ )
              p++;
       return p-s;
}

2. 模拟实现strcpy

char *my_strcpy(char *dest, const char*src)
{ 
 char *ret = dest;
 assert(dest != NULL);
 assert(src != NULL);
 
 while((*dest++ = *src++))
 {
    ;
 }
 return ret;
}

 3. 模拟实现strcat

char *my_strcat(char *dest, const char*src)
{
     char *ret = dest;
     assert(dest != NULL);
     assert(src != NULL);
     while(*dest)
         {
             dest++;
         }
     while((*dest++ = *src++))
         {
             ;
         }
     return ret;
}

 4. 模拟实现strstr

char *  strstr (const char * str1, const char * str2)
{
        char *cp = (char *) str1;
        char *s1, *s2;
        if ( !*str2 )
            return((char *)str1);
        while (*cp)
       {
                s1 = cp;
                s2 = (char *) str2;
                while ( *s1 && *s2 && !(*s1-*s2) )
                        s1++, s2++;
                if (!*s2)    return(cp);
                cp++;
       }
        return NULL;
}

5. 模拟实现strcmp

int my_strcmp (const char * src, const char * dst)
{
        int ret = 0 ;
        assert(src != NULL);
        assert(dest != NULL);
        while( !(ret = *src - *dst) && *dst)
                ++src, ++dst;
        if ( ret < 0 )
                ret = -1 ;
        else if ( ret > 0 )
                ret = 1 ;
        return ret;
}

6. 模拟实现memcpy

void * memcpy ( void * dst, const void * src, size_t count)
{
        void * ret = dst;
        assert(dst);
        assert(src);

        while (count--) {
                *(char *)dst = *(char *)src;
                dst = (char *)dst + 1;
                src = (char *)src + 1;
       }
        return ret;
}

7. 模拟实现memmove

void * memmove ( void * dst, const void * src, size_t count)
{
        void * ret = dst;
        if (dst <= src || (char *)dst >= ((char *)src + count)) 
               {
  
                        while (count--) 
                            {
                                *(char *)dst = *(char *)src;
                                dst = (char *)dst + 1;
                                src = (char *)src + 1;
                            }
               }

        else  {

                        dst = (char *)dst + count - 1;
                        src = (char *)src + count - 1;
                        while (count--) {
                        *(char *)dst = *(char *)src;
                        dst = (char *)dst - 1;
                        src = (char *)src - 1;
               }
       }
        return ret;
}

  本次分享到这就结束了,如果对你有所帮助,就是对小编最大的鼓励,如果可以的话,点赞,关注加收藏并分享给你好友,一起学习进步吧!

  关注小编,持续更新!   

  • 18
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一般清意味……

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值