vlambda博客
学习文章列表

C语言再学习25——常用字符串函数归纳


1. memcpy


内存复制函数。


1.1 头文件


#include <string.h>


1.2 描述


void *memcpy(void *str1, const void *str2, size_t n) ;


从存储区 str2 复制 n 个字符到存储区 str1。


1.3 参数


str1: 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针;


str2: 指向要复制的数据源,类型强制转换为 void* 指针;


n: 要被复制的字节数。


1.4 返回值


该函数返回一个指向目标存储区 str1 的指针。


1.5 注意


(1)复制的内容不同。strcpy 只能复制字符串,而 memcpy 可以复制任意内容,例如字符数组、整型、结构体、类等;


(2)复制的方法不同。strcpy 不需要指定长度,它遇到被复制字符的串结束符 "\0" 才结束,所以容易溢出。memcpy 则是根据其第 3 个参数决定复制的长度;


(3)用途不同。通常在复制字符串时用 strcpy,而需要复制其他类型数据时则一般用 memcpy;


(4)str1指针要分配足够的空间,也即大于等于 n 字节的空间。如果没有分配空间,会出现断错误,造成空间溢出;


(5)str1 和 str2 所指的内存空间不能重叠(如果发生了重叠,使用 memmove() 会更加安全);


(6)memcpy  是按照字节进行拷贝。多字节数据的拷贝如下:


测试:


void memcpy_test(void)
{
    char src_buf[5] = {12345};
    char dst_buf[10] = {0};
    int test_buf1[5] = {998522987346711027};
    int test_buf2[5] = {0};

    memcpy(dst_buf, src_buf, sizeof(src_buf));
    for (int i = 0; i < sizeof(src_buf); i++)
    {
        printf("dst_buf: %d \r\n", dst_buf[i]);
    }

    memcpy(test_buf2, test_buf1, sizeof(test_buf1));    //sizeof(test_buf1) = 20字节
    for (int i = 0; i < 5; i++)
    {
        printf("test_buf2: %d \r\n", test_buf2[i]);
    }
}


结果输出:


C语言再学习25——常用字符串函数归纳

1.6 原型实现


void *Memcpy(void *dest, const void *src, unsigned int count)
{
    char *pdest = (char *)dest;
    char *psrc = (char *)src;

    if (pdest == NULL || psrc == NULL)
    {
        return NULL;
    }

    if (pdest == psrc)
    {
        return;
    }

    if (pdest > psrc)
    {
        while (count--)
        {
            *(pdest + count) = *(psrc + count);
        }
    }
    else
    {
        while (count--)
        {
            *pdest++ = *psrc++;
        }
    }
    return pdest;
}


2. memset


将某一块内存中的内容全部设置为指定的值,它是对较大的结构体或数组进行清零操作的一种快捷方法。


2.1 头文件


#include <string.h>


2.2 描述


void *memset(void *str, int c, size_t n) ;


复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。


2.3 参数


str: 指向要填充的内存块;


c: 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式;


n: 要被设置为该值的字节数。


2.4 返回值


该函数返回一个指向存储区 str 的指针。


2.5 注意


(1)memset 函数按字节对内存块进行初始化,所以不能用它将 int 数组初始化为 0 和 -1 之外的其他值(除非该值高字节和低字节相同);


(2)memset(void *str, int c, size_t n) 中 c 实际范围应该在 0——255,因为该函数只能取 c 的后八位赋值给你所输入的范围的每个字节。无论 c 多大只有后八位二进制有效,而后八位二进制的范围在(0~255)。而对字符数组操作时则取后八位赋值给字符数组,其八位值作为 ASCII 码。


测试:


void memset_test(void)
{
    char test_buf1[5];
    int test_buf2[5];

    memset(test_buf1, 1sizeof(test_buf1));
    memset(test_buf2, 1sizeof(test_buf2));
    for (int i = 0; i < sizeof(test_buf1); i++)
    {
        printf("tset_buf1 is %x \r\n", test_buf1[i]);
    }
    for (int i = 0; i < 5; i++)
    {
        printf("tset_buf2 is %x \r\n", test_buf2[i]);
    }
}


结果输出:


C语言再学习25——常用字符串函数归纳

2.6 原型实现


void *MyMemset(void *dest, int n, unsigned int len)
{
    if (dest == NULL)
        return NULL;
    char *pdest = (char *)dest;
    while (len--)
    {
        *pdest++ = n;
    }

    return dest;
}


3. memcmp


把存储区 str1 和存储区 str2 的前 n 个字节进行比较,按字节比较。


3.1 头文件


#include <string.h>


3.2 描述


int memcmp(const void *str1, const void *str2, size_t n) ;


存储区 str1 和存储区 str2 的前 n 个字节进行比较。


3.3 参数


str1: 指向内存块的指针;


str2: 指向内存块的指针;


n: 要被比较的字节数。


3.4 返回值


如果返回值 < 0,则表示 str1 小于 str2;


如果返回值 > 0,则表示 str2 小于 str1;


如果返回值 = 0,则表示 str1 等于 str2。


3.5 注意


(1)该函数是按字节比较的,比较 str1  和 str2 的第一个字节的 ascII 码值。


测试:


void memcmp_test(void)
{
    char str1[] = "abcd";
    char str2[] = "abcd";
    int ret = 0;

    ret = My_Memcmp(str1, str2, 4);
    printf("ret val is %d \r\n", ret);

    memcpy(str1, "abce"4);
    ret = My_Memcmp(str1, str2, 4);
    printf("ret val is %d \r\n", ret);

    memcpy(str1, "abcc"4);
    ret = My_Memcmp(str1, str2, 4);
    printf("ret val is %d \r\n", ret);
}


结果输出:


C语言再学习25——常用字符串函数归纳

3.6 原型实现


int My_Memcmp(void *str1, void *str2, int count)
{
    char *ptr1 = (char *)str1;
    char *ptr2 = (char *)str2;

    if (!count)
    {
        return 0;
    }

    while (count--)
    {
        if (*ptr1 == *ptr2)
        {
            ptr1 = ptr1 + 1;
            ptr2 = ptr2 + 1;
        }
        else
        {
            return *ptr1 - *ptr2;
        }
    }
    return *ptr1 - *ptr2;
}


4. strlen


strlen 所作的是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符 '\0' 为止,然后返回字符计数器值(长度不包含 '\0 ')。


4.1 头文件


#include <string.h>


4.2 描述


size_t strlen(const char *str) ;


计算字符串 str 的长度,直到空结束字符,但不包括空结束字符。


4.3 参数


str: 要计算长度的字符串。


4.4 返回值


该函数返回字符串的长度。


4.5 注意


(1)注意 strlen 和 sizeof 的区别。


测试:


void strlen_test(void)
{
    char *ptr = "asdfghjl";

    printf("strlen length is %d \r\n"strlen(ptr));
}


结果输出:


C语言再学习25——常用字符串函数归纳

输出字符串长度不包括 '\0'。


4.6 原型实现


unsigned int My_Strlen(const char *str)
{
    int str_len = 0;

    while (*str++ != '\0')
    {
        str_len++;
    }
    return str_len;
}


5. strcpy



5.1 头文件


#include <string.h>


5.2 描述


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


把 src 所指向的字符串复制到 dest。


5.3 参数


dest: 指向用于存储复制内容的目标数组。;


src: 要复制的字符串。


5.4 返回值


该函数返回一个指向最终的目标字符串 dest 的指针。


5.5 注意


(1)若目标数组 dest 不够大,而源字符串的长度又太长,可能会造成缓冲溢出的情况;


(2)src 和 dest 所指内存区域不可以重叠。


测试:


void strcpy_test(void)
{
    char test_buf1[6] = "ABCDE";
    char test_buf2[100] = {0};

    strcpy(test_buf2, test_buf1);
    printf("strcpy test %s \r\n", test_buf2);
}


5.6 原型实现


char *My_Strcpy(char *dest, const char *src)
{
    char *tmp = (char *)dest;

    if ((dest == NULL) || (src == NULL))
    {
        return 0;
    }

    while (*src != '\0')
    {
        *tmp++ = *src++;
    }
    *tmp = '\0';

    return tmp;
}


6. strcmp


比较两个字符串并根据比较结果返回整数。基本形式为 strcmp(str1, str2),若 str1 = str2,则返回零;若 str1 < str2,则返回负数;若 str1 > str2,则返回正数。


6.1 头文件


#include <string.h>


6.2 描述


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


把 str1 所指向的字符串和 str2 所指向的字符串进行比较。


6.3 参数


str1:  要进行比较的第一个字符串;



str2: 要进行比较的第二个字符串。


6.4 返回值


如果返回值小于 0,则表示 str1 小于 str2;


如果返回值大于 0,则表示 str1 大于 str2;


如果返回值等于 0,则表示 str1 等于 str2。


6.5 注意


(1)两个字符串自左向右逐个字符相比(按 ASCII 值大小相比较),直到出现不同的字符或遇 '\0' 为止;


(2)只能比较字符串,即可用于比较两个字符串常量或比较数组,不能比较数字等其他形式的参数。


测试:


void strcmp_test(void)
{
    int ret = 0;
//    char test_buf1[6] = "ABCBE";
//    char test_buf2[3] = "AB";
    char test_buf1[6] = {123456};
    char test_buf2[6] = {123756};

    ret = My_Strcmp(test_buf1, test_buf2);
    printf("ret val is %d \r\n", ret);
}


6.6 原型实现


int My_Strcmp(const char *str1, const char *str2)
{
    if (str1 == NULL || str2 == NULL)
    {
        return NULL;
    }

    while (*str1 == *str2)
    {
        str1++;
        str2++;

        if (*str1 == '\0' || *str2 == '\0')
        {
            break;
        }
    }

    return *str1 - *str2;
}


7. sprintf


字符串格式化命令。函数声明为 int sprintf(char *string, char *format [,argument,…]);,主要功能是把格式化的数据写入某个字符串中,即发送格式化输出到 string 所指向的字符串。


7.1 头文件


#include <stdio.h>


7.2 描述


int sprintf(char *str, const char *format, ...);


发送格式化输出到 str 所指向的字符串。


7.3 参数


str: 指向一个字符数组的指针,该数组存储了 C 字符串;


format : 字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags] [width] [.precision] [length]specifier,具体介绍如下:


flags(标识):


C语言再学习25——常用字符串函数归纳

width(宽度):


C语言再学习25——常用字符串函数归纳

.precision(精度):


C语言再学习25——常用字符串函数归纳

length(长度):


C语言再学习25——常用字符串函数归纳

specifier(说明符):



附加参数 -- 根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。


7.4 返回值


如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。


7.5 注意


(1)格式化数字字符串 sprintf 最常见的应用之一是把整数打印到字符串中;


(2)sprintf 的返回值是字符数组中字符的个数,即字符串的长度,不用在调用 strlen(str) 求字符串的长度;


测试:


void sprintf_test(void)
{
    char buf[100] = {0};
    double data = 3.141593;
    uint16_t len = 0;
    uint8_t test_buff[5] = {5522667799};

    len = sprintf((char *)buf, "%f", data);
    printf("----------------------------------------------------------------- \r\n");
    printf("buf is %s \r\n", buf);
    printf("sprintf return len is %d \r\n", len);

    len = 0;

    for (uint16_t i = 0; i < sizeof(test_buff); i++)
    {
        len += sprintf((char *)buf + i * 2"%d", test_buff[i]);    //数组数据转换为字符串
    }
    printf("test_buff val is %s \r\n", buf);
    printf("sprintf return len is %d \r\n", len);
    printf("----------------------------------------------------------------- \r\n");
}


结果输出: