C语言字符函数和字符串函数以及内存函数的讲解(汇总)

目录

 前言

一、字符分类函数

1.常用的字符分类函数及其功能:

2.这些函数的返回值规则:

3.使用示例:

二、字符转换函数

1.C语⾔提供了2个字符转换函数:

三、strlen函数

1.介绍

2.模拟实现:

四、strcpy函数

1.介绍

2.模拟实现:

五、strcat函数

1.介绍

2.模拟实现:

六、strcmp函数

1.介绍

2.strcmp函数的模拟实现:指针法:

 七、strncpy函数

1.介绍

2.模拟实现:

 八、strncat函数

1.介绍

2.模拟实现:

 九、strncmp函数

1.介绍

2.模拟实现:

十、strstr函数

1.介绍

2.模拟实现:

函数 mystrstr 解析

功能:在 str1 中查找 str2,若找到返回子串起始地址,否则返回 NULL。

实现逻辑:

 十一、strtok 函数

介绍

 十二、 memcpy函数

1.介绍

2.模拟实现:

  十三、memmove函数

1.介绍

2.模拟实现:

 十四、memset函数

1.介绍

2.模拟实现:

 十五、memcmp函数

1.介绍

2.模拟实现:

总结

 前言

在编程时,我们经常要处理字符和字符串,为了⽅便操作字符和字符串,C语⾔标准库中提供了 ⼀系列库函数,接下来我们就学习⼀下这些函数。

本文章将讲解内容如下:

1. 字符分类函数
2. 字符转换函数
3. strlen的使用和模拟实现
4. strcpy的使用和模拟实现
5. strcat的使用和模拟实现
6. strcmp的使用和模拟实现
7. strncpy函数的使用
8. strncat函数的使用
9. strncmp函数的使用
10. strstr的使用和模拟实现
11. strtok函数的使用
12. strerror函数的使用

本篇文章也会讲解C语⾔内存函数知识的相关内容:

本篇文章涉及的C语⾔内存函数有:

1.memcpy函数

2.memmove函数

3.memset函数

4.memcmp函数

一、字符分类函数

C语⾔中有⼀系列的函数是专⻔做字符分类的,也就是⼀个字符是属于什么类型的字符的。 这些函数的使⽤都需要包含⼀个头⽂件是 ctype.h。

#include<ctype.h>

1.常用的字符分类函数及其功能:

以下是常用的字符分类函数及其功能:

  1. 判断字母和数字

    • int isalnum(int c):检查字符是否为字母(a-z, A-Z)或数字(0-9)
    • int isalpha(int c):检查字符是否为字母(a-z, A-Z)
    • int isdigit(int c):检查字符是否为数字(0-9)
  2. 判断大小写字母

    • int islower(int c):检查字符是否为小写字母(a-z)
    • int isupper(int c):检查字符是否为大写字母(A-Z)
  3. 判断空白字符

    • int isspace(int c):检查字符是否为空白字符(空格、制表符\t、换行符\n等)
  4. 判断其他属性

    • int iscntrl(int c):检查字符是否为控制字符(如\n\t等)
    • int isgraph(int c):检查字符是否为可打印且非空格字符
    • int isprint(int c):检查字符是否为可打印字符(包括空格)
    • int ispunct(int c):检查字符是否为标点符号
    • int isxdigit(int c):检查字符是否为十六进制数字(0-9, a-f, A-F)

2.这些函数的返回值规则:

如果条件满足,即函数对应的要求成立,返回非0值,不符合,返回0.

3.使用示例:

这些函数的使⽤⽅法⾮常类似:

int islower ( int c );

通过此函数,判断参数c是否为小写字母,如果条件满足,即函数对应的要求成立,返回非0值,不符合,返回0.

习题例子:

写⼀个代码,将字符串中的⼩写字⺟转⼤写,其他字符不变。

#include<stdio.h>
#include<ctype.h>
int main()
{
    char p[]="ABCdef";
    int i=0;
    char c;
    while(p[i]!='\0')
    {
        c=p[i];
        if(islower(p[i]))
           {
               c-=32;
               p[i]=c;
           }
            i++;
    }
    printf("%s",p);
}

如果记不住这些函数也没太大影响,如上方的islower,我们可以用   if(p[i]>='a'&&p[i]<='z') 来代替,同理,其他函数均可这样做。

二、字符转换函数

1.C语⾔提供了2个字符转换函数:

1. int tolower (int c)

2. int toupper(int c)

int tolower (int c)函数的作用为将大写字母转化成小写字母;

同理 int toupper(int c)函数的作用为将小写字母转化成大写字母;

上方习题中c-=32;我们可以用toupper(c)来实现;当然我们如果记不住字符转换函数的话,就记一下每个大写字母与其对应的小写字母之间差32个ASCLL值即可。

三、strlen函数

1.介绍

size_t strlen ( const char * str );

统计参数指向的字符串的⻓度。统计的是字符串中 '\0' 之前的字符的个数,如果该字符串没有‘\0’,该结果为随机值:

int main()
{
    char p[]="ABCdef";
    int i,j;
    char q[]={'a','b'};
    i=strlen(p);
    j=strlen(q);
    printf("%d  %d",i,j);
}

我们由此可知:p达到了预期的目标,但q没有。

2.模拟实现:

该函数可有多钟实现方式:
指针法:

int mystrlen(char *p)
{
    char *q=p;
    while(*q)
    {  q++;
    }
    return q-p;
}
int main()
{
    char p[]="ABCdef";
    int i,j;
    i=mystrlen(p);
    printf("%d",i);
}

统计个数求法:

int mystrlen(char *p)
{
    int i=0;
    while(*p)
    {
        p++;
        i++;
    }
    return i;
}
int main()
{
    char p[]="ABCdef";
    int i,j;
    i=mystrlen(p);
    printf("%d",i);
}

递归求法:

int mystrlen(const char * str)
{
    assert(str);
    if(*str == '\0') 
        return 0;
    else return 1 + mystrlen(str+1);
}
int main()
{
    char p[]="ABCdef";
    int i,j;
    i=mystrlen(p);
    printf("%d",i);
}

结果也一样正确。

四、strcpy函数

1.介绍

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

功能:字符串拷⻉,拷⻉到源头字符串中的 \0 为⽌,即将代码中source的字符全拷贝至 destination中。

destination :指针,指向⽬的地空间(目的字符串)

source :指针,指向源头数据(源头字符串)

返回值:strcpy 函数返回的⽬标空间的起始地址

int main()
{
    char arr1[10] = {0};
    char arr2[] = "hello";
    strcpy(arr1, arr2);
    printf("%s\n", arr1);
    return 0;
}

我们由此可知:该函数将arr2的内容拷贝到了arr1中。

注意:

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

2.该函数会将源字符串中的 '\0' 拷⻉到⽬标空间。

3.⽬标空间必须⾜够⼤,以确保能存放源字符串。

4.⽬标空间必须可修改,常量字符串进行拷贝是不行的。

2.模拟实现:

指针法:

char* mystrcpy(char *a1, char*a2)
{  char *ret=a1;
 while(*a2)
 {
     *a1=*a2;
     a1++,a2++;
 }
 *a1 = '\0';
 return ret;
}
int main()
{
    char arr1[10] = {0};
    char arr2[] = "hello";
    mystrcpy(arr1, arr2);
    printf("%s\n", arr1);
    return 0;
}

运行结果一样的。

五、strcat函数

1.介绍

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

功能:字符串追加,将源头字符串中的全部字符,即将代码中source的字符全追加至 destination结尾。

destination :指针,指向⽬的地空间

source :指针,指向源头数据

返回值strcat 函数返回的⽬标空间的起始地址

int main()
{
    char arr1[20] = "hello ";
    char arr2[] = "world";
    strcat(arr1, arr2);
    printf("%s\n", arr1);
    return 0;
}

我们由此可知:该函数将arr2的内容追加到了arr1中。

注意:

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

2.⽬标字符串中也得有 \0 ,否则没办法知道追加从哪⾥开始。

3.⽬标空间必须⾜够⼤,以确保能存放源字符串。

4.⽬标空间必须可修改,常量字符串进行拷贝是不行的。

这几条要求与strcpy要求类似。

2.模拟实现:

指针法:

char *mystrcat(char *a1,char *a2)
{
    char *p=a1;
    while(*a1)
    {
        a1++;
    }
    while(*a2)
    {
        *a1=*a2;
        a1++;
        a2++;
    }
    *a1='\0';
    return p;
}
int main()
{
    char arr1[20] = "hello ";
    char arr2[] = "world";
    mystrcat(arr1, arr2);
    printf("%s\n", arr1);
    return 0;
}

运行结果一样的。

六、strcmp函数

1.介绍

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

功能:用来比较str1 和str2 指向的字符串,从两个字符串的第⼀个字符开始⽐较,如果两个字符的ASCII码值相等,就比较下⼀个字符。直到遇到不相等的两个字符,或者字符串结束。

str1 :指针,指向要⽐较的第⼀个字符串。

str2 :指针,指向要⽐较的第⼆个字符串。

返回值:strcmp 函数返回的两个字符串比较的值。

返回值规定:

1.第⼀个字符串⼤于第⼆个字符串,则返回⼤于0的数字。

2.第⼀个字符串等于第⼆个字符串,则返回0。

3.第⼀个字符串⼩于第⼆个字符串,则返回⼩于0的数字。

代码示例:

int main()
{
    char arr1[] = "abcdef";
    char arr2[] = "abq";
    int ret = strcmp(arr1, arr2);
    printf("%d\n", ret);
    if(ret > 0)
        printf("arr1 > arr2\n");
    else if(ret == 0)
        printf("arr1 == arr2\n");
    else
        printf("arr1 < arr2\n");
    return 0;
}

对此代码解释:

strcmp比较大小为逐一比较,如果相等,则转向下一个字符。

2.strcmp函数的模拟实现:
指针法:

int mystrcmp(char *a,char *b)
{
    while(*a==*b)
    {
        if(*a=='\0')
        {
            return 0;
        }
        a++;
        b++;
    }
    return *a-*b;
}
int main()
{
    char arr1[] = "abcdef";
    char arr2[] = "abq";
    int ret = mystrcmp(arr1, arr2);
    printf("%d\n", ret);
    if(ret > 0)
        printf("arr1 > arr2\n");
    else if(ret == 0)
        printf("arr1 == arr2\n");
    else
        printf("arr1 < arr2\n");
    return 0;
}

对该方法介绍一下:

通过循环比较字符直到不同或遇到结束符 '\0',返回字符差值,这样的方式即可得到结果。

 七、strncpy函数

1.介绍

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

  strncpy函数strcpy函数功能相同,字符串拷⻉,即将代码中source的字符拷贝至 destination中,但strncpy函数多出了一个参数,新增的参数含义为最多拷贝num个字符。

即:

destination :指针,指向⽬的地空间(目的字符串)。

source :指针,指向源头数据(源头字符串)。

num :从source指向的字符串中最多拷⻉的字符个数。

返回值:strcpy 函数返回的⽬标空间的起始地址。

使用例:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main()
{
    char arr1[20] = { 0 };
    char arr2[] = "abcdefghi";
    char* str = strncpy(arr1, arr2, 5);
    printf("%s\n", arr1);
    printf("%s\n", str);
    return 0;
}

  strncpy函数strcpy函数功能相同,但也有区别的地方:

1.strcpy 函数拷⻉到\0 为⽌,如果⽬标空间不够的话,容易出现越界⾏为。
2.strncpy 函数指定了拷⻉的⻓度,源字符串不⼀定要有'\0', 同时在设计参数的时候,就会多⼀层思考:⽬标空间的⼤⼩是否够⽤。

注意:strncpy

  • 结束条件:复制 n 个字符  遇到source 的 '\0' 时停止(以先到者为准)。
  • 自动添加 '\0':否!仅当source  长度 < n 时,剩余部分用 '\0' 填充至 n 个字符;若 source 长度 ≥ n,则不添加 '\0'。注意strncpy 手动补 '\0'的情况

2.模拟实现:

  可用指针法:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
char* mystrncpy(char* a1, char* a2,int n)
{
    char* ret = a1;
    while ( n-- &&*a2)
    {
        *a1 = *a2;
        a1++, a2++;
    }
    while (n > 0)
    {
        a1++;
        *a1 = '\0';
        n--;
    }
    return ret;
}
int main()
{
    char arr1[20] = { 0 };
    char arr2[] = "abcdefghi";
    char* str = mystrncpy(arr1, arr2, 5);
    printf("%s\n", arr1);
    printf("%s\n", str);
    return 0;
}

  运行结果一样的。

 八、strncat函数

1.介绍

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

strncat函数strcat函数功能相同,功能:字符串追加,将源头字符串中的字符,即将代码中source的字符追加至 destination结尾,但最多追加num个字符。

destination :指针,指向⽬的地空间

source :指针,指向源头数据

num :从source指向的字符串中最多追加的字符个数。

返回值strncat 函数返回的⽬标空间的起始地址

  使用例:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main()
{
    char arr1[20] = "hello ";
    char arr2[] = "world";
    char* str = strncat(arr1, arr2, 5);
    printf("%s\n", arr1);
    printf("%s\n", str);
}

  strncat函数strcat函数功能相同,但也有区别的地方:

1.strncat 多了⼀个参数,num;

2. strcat函数在追加的时候要将源字符串的所有内容,包含 \0 都追加过去,但是strncat 的num数指定了追加的⻓度,同时函数中源字符串中不⼀定要有‘\0’了,strncat函数更加灵活,也更加安全。

2.模拟实现:

  可用指针法:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
char* mystrncat(char* a1, char* a2,int num)
{
    char* p = a1;
    while (*a1)
    {
        a1++;
    }
    while (num--&&*a2)
    {
        *a1 = *a2;
        a1++;
        a2++;
    }
    *a1 = '\0';
    return p;
}
int main()
{
    char arr1[20] = "hello ";
    char arr2[] = "world";
    char* str = mystrncat(arr1, arr2, 5);
    printf("%s\n", arr1);
    printf("%s\n", str);
}

  运行结果一样的。

 九、strncmp函数

1.介绍

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

   strncmp函数strcmp函数功能相同,功能:用来比较str1 和str2 指向的字符串,从两个字符串的第⼀个字符开始⽐较,如果两个字符的ASCII码值相等,就比较下⼀个字符。直到遇到不相等的两个字符,或者字符串结束,但比较的字符对数要在num个字符以内。

str1 :指针,指向要⽐较的第⼀个字符串。

str2 :指针,指向要⽐较的第⼆个字符串。

num :最多⽐较的字符个数。

返回值:strncmp 函数返回的两个字符串比较的值。

返回值规定:

1.第⼀个字符串⼤于第⼆个字符串,则返回⼤于0的数字。

2.第⼀个字符串等于第⼆个字符串,则返回0。

3.第⼀个字符串⼩于第⼆个字符串,则返回⼩于0的数字。

4.如果到了num对且这num对字符均相等,则返回0,按相等来看。

  使用例:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main()
{
    char arr1[] = "abcdef";
    char arr2[] = "abcqw";
    int ret1 = strncmp(arr1, arr2, 3);
    printf("%d\n", ret1);
    int ret2 = strncmp(arr1, arr2, 4);
    printf("%d\n", ret2);
    return 0;
}

  strncmp函数strcpy函数功能相同,但也有区别的地方:

关键区别
1.比较长度限制:

  strcmp:无长度限制,会一直比较到字符串结束(存在越界风险,若字符串未正确以'\0'结尾)。
  strncmp:通过第三个参数n明确限制比较的最大字符数,更安全,可避免因字符串未结束导致的无限比较。
2.返回值逻辑:

  两者返回值规则相同:
  若s1 < s2:返回负数(通常是ASCII差值)
  若s1 == s2:返回0
  若s1 > s2:返回正数(通常是ASCII差值)
  但 strncmp 的“相等”可能仅指前n个字符相等,而非整个字符串相等。

2.模拟实现:

  可用指针法:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int mystrncmp(char* a, char* b,int num)
{
    while (num&&*a == *b)
    {
        if (*a == '\0')
        {
            return 0;
        }
        a++;
        b++;
        num--;
    }
    if (num == 0)
    {
        return 0;
    }
    return *a - *b;
}
int main()
{
    char arr1[] = "abcdef";
    char arr2[] = "abcqw";
    int ret1 = mystrncmp(arr1, arr2, 3);
    printf("%d\n", ret1);
    int ret2 = mystrncmp(arr1, arr2, 4);
    printf("%d\n", ret2);
    return 0;
}

  运行结果一样的。

十、strstr函数

1.介绍

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

1.介绍:strstr 函数,功能为查找 str2 指向的字符串在 str1 指向的字符串中第⼀次出现的位置。

2.简⽽⾔之:在⼀个字符串中查找⼦字符串。

3.strstr 的使⽤得包含 #include <string.h>头文件。

4.参数: str1 :指针,指向了被查找的字符串。

               str2 :指针,指向了要查找的字符串。

5.返回值:

• 如果str1指向的字符串中存在str2指向的字符串,那么返回第⼀次出现位置的指针。

• 如果str1指向的字符串中不存在str2指向的字符串,那么返回NULL。

使用例:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main()
{
    char str[] = "This is a simple string";
    char* p;
    p= strstr(str, "simple");
    if (p != NULL)
        printf("%s\n", p);
    else
        printf("查找的字符串不存在\n");
            return 0;
}

2.模拟实现:

  该函数的模拟实现较为复杂,需要建立三个指针,进行实现,分别为  1.指向被指向的字符串(被查找的字符串),该字符指针来代指该串、2.一个每次承接要查找的字符串的首地址,3.一个每次承接(1.)的指针的首地址。

  可能有些模糊,先看代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
char* mystrstr(char* str1,char* str2)
{
    char* s1 = str1;
    char* s2, * s3;
    while (*s1)
    {
        s2 = s1;
        s3 = str2;
        while (*s2 && *s3)
        {
            if ((*s2) != (*s3))
                break;
            s2++;
            s3++;
        }
        if (*s3 == '\0')
            return s1;
        s1++;
    }
    return NULL;
}
int main()
{
    char str[] = "This is a simple string";
    char* p;
    p= mystrstr(str, "simple");
    if (p != NULL)
        printf("%s\n", p);
    else
        printf("查找的字符串不存在\n");
            return 0;
}

函数 mystrstr 解析

功能:在 str1 中查找 str2,若找到返回子串起始地址,否则返回 NULL
实现逻辑
  1. 初始化指针

    • s1 指向 str1 的当前比较起始位置(从首字符开始)。
    • s2 和 s3 作为临时指针,分别用于遍历 str1 的子串和 str2 本身。
  2. 外层循环:遍历 str1 的每个字符(while (*s1)),作为子串匹配的起点。

  3. 内层循环:逐个字符比较 s1 起始的子串与 str2

    • 若 *s2 == *s3,则两者都后移一位(s2++s3++)。
    • 若不相等,跳出内层循环,s1 后移一位(尝试下一个起始位置)。
  4. 匹配成功条件:当 s3 遍历到 str2 的结束符 '\0'(即 *s3 == '\0'),说明 str2 已完全匹配,返回此时的 s1(子串起始地址)。

  5. 未找到情况:若 str1 遍历结束仍未匹配,返回 NULL

  这是对应实现的讲解,运行结果一样的。

 十一、strtok 函数

介绍

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

功能:

1.分割字符串:根据 delim 参数中指定的分隔符,将输⼊字符串 str 拆分成多个⼦字符串。

2.修改原始字符串: strtok 会直接在原始字符串中插⼊ '\0' 终⽌符,替换分隔符的位置,因 此原始字符串会被修改。

参数:

1. str :⾸次调⽤时传⼊待分割的字符串;后续调⽤传⼊NULL ,表⽰继续分割同⼀个字符串。

2. delim :包含所有可能分隔符的字符串(每个字符均视为独⽴的分隔符)。

返回值:

1.成功时返回指向当前⼦字符串的指针。

2.没有更多⼦字符串时返回NULL。

注意点:

使⽤步骤

1.⾸次调⽤:传⼊待分割字符串和分隔符。

2.后续调⽤:传⼊ NULL 和相同的分隔符,继续分割。

3.结束条件:当返回 NULL 时,表示分割完成。

  通过使用例,解释一下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main()
{
    char arr[] = "192.168.6.111";
    const char* sep = ".";
    const char* str = NULL;
    char  buf[30] = { 0 };
    strcpy(buf, arr); 
for (str = strtok(buf, sep); str != NULL; str = strtok(NULL, sep))
        {
            printf("%s\n", str);
        }
    return 0;
}

 strcpy(buf, arr);  是将arr的值拷贝到buf中,

for (str = strtok(buf, sep); str != NULL; str = strtok(NULL, sep))

这句意为:在buf串中寻找sep的串,声明时可知,sep的串: const char* sep = ".";

  • 首次调用:strtok(buf, sep),传入原始字符串 buf 和分隔符 sep,返回第一个子串地址。
  • 后续调用:strtok(NULL, sep),传入 NULL 表示继续处理上一次的字符串,返回下一个子串地址,直至返回 NULL(所有子串已拆分完毕)。

  但使用本函数时也有些需要注意的点:

1.破坏性操作: strtok 会直接修改原始字符串,将其中的分隔符替换为 '\0' 。如果需要保留原 字符串,应先拷⻉⼀份原串。

2.连续分隔符:多个连续的分隔符会被视为单个分隔符,不会返回空字符串。

3.空指针处理:如果输⼊的str为NULL且没有前序调⽤,⾏为未定义。

接下来十二及以后是关于内存函数的相关知识:

 十二、 memcpy函数

1.介绍

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

  memcpy函数strcpy函数功能相似,不同的是memcpy 是完成内存块拷⻉的,不关注内存中存放的数据是什么,即将函数 memcpy 从source 的位置开始向后复制 num 个字节的数据到 destination 指向的内存位置。

注意:source 和 destination 有任何的重叠,复制的结果都是未定义的,更易懂的角度来说:

例:

int arr[5] = {1, 2, 3, 4, 5};
memcpy(arr+1, arr, 3*sizeof(int)); // 错误:目标区域 (arr+1) 与源区域 (arr) 重叠

memcpy不允许同名数组的复制。

destination :指针,指向⽬标空间,将拷⻉的数据存放在这⾥(归宿)。

source :指针,指向源空间,要拷⻉的数据从这⾥来(来源)。

num :从source要拷⻉的数据占据的字节数。

返回值:memcpy 函数返回的⽬标空间的起始地址。

使用例:

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

例子讲解:

本代码中,是将 arr1 的前20字节数据复制到 arr2 中,然后打印 arr2 的所有元素。

  • memcpy(arr2, arr1, 20) 表示复制 20字节 数据。由于每个 int 占4字节,因此实际复制 20 / 4 = 5 个元素。
  • 从 arr1 的起始地址复制5个元素:1, 2, 3, 4, 5
  • arr2 初始化为全0,因此未被复制的后5个元素保持为0。

所以可知打印时后5个值为0.

2.模拟实现:

#include <stdio.h>
#include <string.h>
void * mymemcpy ( void * dst, const void * src, int n )
{  void *ret=dst;
     while(n--)
{
    *(char*)dst=*(char*)src;
    dst=(char*)dst+1;
    src=(char*)src+1;
}
    return ret;
}
int main()
{
    int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
    int arr2[10] = { 0 };
    mymemcpy(arr2, arr1, 20);
    int i = 0;
    for (i = 0; i < 10; i++)
    {
        printf("%d ", arr2[i]);
    }
    return 0;
}

对该实现的讲解:

首先模拟实现要满足原函数的参数,返回值等,所以要满足void * memcpy ( void * destination, const void * source, size_t num );的型状。

因为返回值:memcpy 函数返回的⽬标空间的起始地址。

所以用void *ret=dst;语句来接⽬标空间的起始地址。

memcpy 是完成内存块拷⻉的,不关注内存中存放的数据是什么,拷贝的是num个字节,但不同类对应着不同的字节数,所以存在拷贝不完全的情况,而char类型1个字节数,可以完成1个1个复制拷贝的情况,所以   *(char*)dst=*(char*)src; 拷贝完一个字符,就该向下拷贝,但二者均为void *类,所以应该通过强转之后移动地址,所以会有  dst=(char*)dst+1;
    src=(char*)src+1; 语句,在结尾,完成返回值:memcpy 函数返回的⽬标空间的起始地址。 return ret;

  运行结果一样的,看实现代码,我们可以发现,memcpy不能实现同名数组的复制,如果我们想实现,则可以靠二、memmove函数

  十三、memmove函数

1.介绍

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

memmove函数也是完成内存块拷⻉的。

他与 memcpy函数功能一样,是完成内存块拷⻉的,不关注内存中存放的数据是什么,即将函数 memcpy 从source 的位置开始向后复制 num 个字节的数据到 destination 指向的内存位置。不过mommove可以正确处理目标空间与源空间重叠的情况。

源内存块和⽬标内存块是可以重叠的。

二者的参数相同,意义也一样的:

destination :指针,指向⽬标空间,将拷⻉的数据存放在这⾥(归宿)。

source :指针,指向源空间,要拷⻉的数据从这⾥来(来源)。

num :从source要拷⻉的数据占据的字节数。

返回值:memmove 函数返回的⽬标空间的起始地址。

  使用例:

#include <stdio.h>
#include <string.h>
int main()
{
    int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
    memmove(arr1 + 2, arr1, 20);
    int i = 0;
    for (i = 0; i < 10; i++)
    {
        printf("%d ", arr1[i]);
    }
    return 0;
}

讲解:

与在memcpy中的使用方法一样,不同的是该例为同名数组的拷贝,即将该数组的前5个值拷贝从(arr1 + 2)即arr[2]开始。

2.模拟实现:

#include <stdio.h>
#include <string.h>
void * mymemmove ( void * dst, const void * src, int n )
{
    void *ret=dst;
    if(dst<src)
    {
        while(n--)
        {
            *(char*)dst=*(char*)src;
            dst=(char*)dst+1;
            src=(char*)src+1;
        }
    }
    else
    {
        while(n--)
            *((char*)dst+n)=*((char*)src+n);
    }
    return ret;
}
int main()
{
    int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
    mymemmove(arr1 + 2, arr1, 20);
    int i = 0;
    for (i = 0; i < 10; i++)
    {
        printf("%d ", arr1[i]);
    }
    return 0;
}

  运行结果一样,接下来对该实现讲解一下:

核心逻辑分析

mymemmove 通过判断目标地址(dst)和源地址(src)的位置关系,选择不同复制方向:

  • 当 dst < src(目标在源左侧):从低地址到高地址复制(避免覆盖未复制的源数据)。(对应图中的一情况)
  • 当 dst >= src(目标在源右侧或重叠):从高地址到低地址复制(从 n-1 反向遍历)。(对应图中的二情况)

输入参数

  • arr1 初始值:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  • mymemmove(arr1 + 2, arr1, 20)
    • dst = arr1 + 2(目标起始地址:第3个元素)
    • src = arr1(源起始地址:第1个元素)
    • n = 20(复制20字节,int 占4字节 → 共复制 5个元素

关键判断

dst (arr1+2) > src (arr1) → 进入 else 分支(从高地址到低地址复制)。

在 else中拷贝。

    while(n--)
            *((char*)dst+n)=*((char*)src+n);

最后: return ret;完成返回值: memmove函数返回的⽬标空间的起始地址。

 十四、memset函数

1.介绍

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

1.memset 函数是设置内存块的内容的,将内存中指定⻓度的空间设置为特定的内容。 2.memset 的使⽤需要包含<string.h>。

参数讲解:

1.ptr :指针,指向要设置的内存空间,也就是存放了要设置的内存空间的起始地址。

2.value :要设置的值,函数将会把value值转换成unsigned char的数据进⾏设置的。也就是以字节为单位来设置内存块的。

3.num :要设置的内存⻓度,单位是字节。

4.返回值:返回的是要设置的内存空间的起始地址。

  使用例:

#include <stdio.h>
#include <string.h>
int main ()
{
    char str[] = "hello world";
    memset (str,'x',6);
    printf(str);
    return 0;
}

对于该例的解释:

  1. 初始字符串char str[] = "hello world" 定义了一个字符数组,存储字符串 "hello world"(共11个字符 + 1个结束符 \0,总长度12字节)。

  2. memset 操作

    • 作用:将 str 起始的 6个字节 全部设置为字符 'x'
    • 原字符串前6个字符是 "hello "(注意第6个字符是空格),替换后变为 "xxxxxx"
  3. 剩余字符不变

    • memset 仅修改前6字节,原字符串从第7字节开始的内容("world\0")保持不变。
    • 拼接后结果为 "xxxxxxrld\0"(第7个字符是 'r',因此输出 xxxxxxrld)。

所以是这样的结果。

注意:当有⼀块内存空间需要设置内容的时候,就可以使⽤memset函数,值得注意的是memset函数对内存 单元的设置是以字节为单位的。

2.模拟实现:

#include <stdio.h>
#include <string.h>
void * mymemset ( void * p, int value,int n)
{  void *ret=p;
    while(n--)
    {
        *(char*)p=value;
        p=(char*)p+1;
    }
return ret;
}
int main ()
{
    char str[] = "hello world";
    mymemset (str,'x',6);
    printf(str);
    return 0;
}

讲解:

  • mymemset执行流程
    • 保存原始指针ret = p,用于最终返回。
    • 循环6次(n--从6到0),每次将p指向的字节设为'x',并将p按字节递增((char*)p + 1)。
    • 原字符串前6字节("hello ")被替换为"xxxxxx",后续字符"world\0"保持不变,拼接后结果为"xxxxxxrld\0"
  • printf输出:打印字符串至结束符\0,结果为 xxxxxxrld

 十五、memcmp函数

1.介绍

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

功能:

1.⽐较指定的两块内存块的内容,⽐较从ptr1和ptr2指针指向的位置开始,向后的num个字节 2.memcmp 的使⽤需要包含

ptr1 :指针,指向⼀块待⽐较的内存块

ptr2 :指针,指向另外⼀块待⽐较的内存块

num :指定的⽐较⻓度,单位是字节

  使用例:

#include <stdio.h>
#include <string.h>
int main()
{
    char s1[] = "abcdefg";
    char s2[] = "abcdEFG";
    int n;
    n = memcmp(s1, s2, sizeof(s1));
    if (n > 0)
        printf("'%s'>'%s'.\n", s1, s2);
    else if (n < 0)
        printf("'%s' <'%s'.\n",s1,s2);
    else
        printf("'%s'  =='%s'  .\n", s1, s2);
    return 0;
}

讲解:

  • 输出内容'abcdefg' < 'abcdEFG'.
  • 关键原因memcmp字节逐一比较(区分大小写),在第5个字符处:
    • s1[4] = 'e'(ASCII值101)
    • s2[4] = 'E'(ASCII值69)
      因 101 > 69memcmp返回正数,n>0, 执行: if (n > 0)       printf("'%s'>'%s'.\n", s1, s2);

注意:1.memcmp 函数是通过返回值告知⼤⼩关系的。

           2.如果要⽐较2块内存单元的数据的⼤⼩,可以使⽤该函数,这个函数的特点就是可以指定⽐较长度。

2.模拟实现:

#include <stdio.h>
#include <string.h>
int mymemcmp ( const void * p1, const void * p2, int n )
{
    const char* s1 = (const char*)p1;
    const char* s2 = (const char*)p2;
    while (n-- > 0)
    {
        if (*s1 != *s2)
        {
            return *s1 - *s2;
        }
        s1++;
        s2++;
    }
    return 0;
}
int main()
{
    char s1[] = "abcdefg";
    char s2[] = "abcdEFG";
    int n;
    n = mymemcmp(s1, s2, sizeof(s1));
    if (n > 0)
        printf("'%s'>'%s'.\n", s1, s2);
    else if (n < 0)
        printf("'%s' <'%s'.\n",s1,s2);
    else
        printf("'%s'  =='%s'  .\n", s1, s2);
    return 0;
}

结果一样,接下来,我将为大家讲解一下:

因为参数为void*类型,如果使用,需要     *(char*)p1  这种的强转,代码中每次比较和移动指针时都进行(char*)强制转换,可通过临时变量优化,const char* s1 = (const char*)p1;
    const char* s2 = (const char*)p2;通过char*类型,便于比大小和向下移动。

    while (n-- > 0)
    {
        if (*s1 != *s2)
        {
            return *s1 - *s2;
        }
        s1++;
        s2++;
    }
    return 0;

  • 循环条件n-- > 0 表示从第 1 个字节开始,逐个比较 n 个字节(每轮循环后 n 减 1,直到 n=0 退出)。
  • 逻辑
    • 每次循环读取 s1 和 s2 指向的当前字节(*s1/*s2)。
    • 若字节不同,直接返回两字节的 ASCII 码差值(例如 'e' - 'E' = 101 - 69 = 32,结果为正数)。
    • 若字节相同,指针后移(s1++/s2++),继续比较下一个字节。
    • 若循环结束后所有 n 字节均相同(未触发 return *s1 - *s2),则显式返回 0。

总结

以上就是今天要讲的内容,

本文章讲解内容如下:

1. 字符分类函数
2. 字符转换函数
3. strlen的使用和模拟实现
4. strcpy的使用和模拟实现
5. strcat的使用和模拟实现
6. strcmp的使用和模拟实现
7. strncpy函数的使用
8. strncat函数的使用
9. strncmp函数的使用
10. strstr的使用和模拟实现

以及C语⾔内存函数知识的相关内容:

本篇文章涉及的C语⾔内存函数有:

1.memcpy函数

2.memmove函数

3.memset函数

4.memcmp函数

知识的相关内容,为篇文章知识的内容,希望大家能喜欢我的文章,谢谢各位。

评论 24
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值