<C语言> 字符串内存函数

C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串或者字符数组中。

字符串常量 适用于那些对它不做修改的字符串函数.

注意:字符串函数都需要包含头文件<string.h>

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

1.1 strlen

strlen()函数用于计算字符串的长度,即字符串中字符的数量,不包括字符串结尾的空字符('')。字符串在C语言中是以字符数组的形式表示的,而字符串的结尾总是以空字符('')来标识字符串的结束。

strlen()函数的函数原型如下:

size_t strlen(const char *str);

其中,const char *str是一个指向字符数组的指针,表示要计算长度的字符串。size_t是C标准库中定义的无符号整数类型,用于表示数组的大小。

strlen()函数的工作方式是从传入的字符串的开头开始遍历,直到遇到字符串结尾的空字符('')为止,并返回遍历过程中经过的字符数量作为字符串的长度。

下面是一个使用strlen()函数的例子:

#include <stdio.h>
#include <string.h>
int main() {
    //a b c d e f 
    char arr1[] = "abcdef";
    char arr2[] = { 'a','b','c','d' };  //err  随机的数字
    printf("%dn", strlen(arr1));//6
    printf("%dn", strlen(arr2));//随机的数字

    return 0;
}

arr2没有以''结尾,strlen()函数会一直遍历直到遇到内存中的第一个空字符为止

注意:

#include <stdio.h>
#include <string.h>
int main() {
    if (strlen("abc") - strlen("abcdef") > 0)//strlen返回的是无符号整型,不会出现负数
        printf(">");
    else
        printf("<");
    return 0;
}

strlen()函数返回的是size_t类型,它是无符号整数类型。因此,不会出现负数。所以输出结果为>

模拟实现strlen

#include <assert.h>
#include <stdio.h>
#include <string.h>
size_t my_strlen(const char *str) {
    assert(str);//str!=NULL
    const char *start = str;
    const char *end = str;
    while (*end != '') {
        end++;
    }
    return end - start;
}


int main() {
    char arr[] = "abcdef";
    size_t len = my_strlen(arr);
    printf("%zun", len);
    return 0;
}

1.2 strcpy

strcpy()函数用于将一个字符串复制到另一个字符串数组中,包括字符串结尾的空字符('')。

strcpy()函数的函数原型如下:

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

其中,char *dest是目标字符串数组的指针,用于存储复制后的字符串;const char *src是源字符串的指针,表示要复制的字符串。

strcpy()函数的工作方式是从源字符串的开头开始,逐个复制字符到目标字符串,直到遇到源字符串的结尾空字符('')为止,同时在目标字符串末尾添加一个空字符('')来标识复制结束。

需要注意的是,目标字符串数组必须具有足够的空间来存储源字符串,否则可能导致缓冲区溢出,造成程序崩溃或安全漏洞。因此,在使用strcpy()函数时,应该确保目标字符串的长度足够大。

#include <stdio.h>
#include <string.h>
int main() {
    char arr[10] = "xxxxxxxxxx";
    //char arr[3]={ 0 };  //数组空间太小
    //char* p = "hello world"; //err 常量字符串地址
    const char *p = "hello world";
    strcpy(arr, p);    
    printf("%sn", arr);  //hello world
    return 0;
}

模拟实现strcpy

#include <assert.h>
#include <stdio.h>
#include <string.h>
char *my_strcpy(char *dest, const char *src) {
    assert(dest);//dest!=NULL
    assert(src);
    char *ret = dest;//dest会在下面循环时候改变 所以地址存放在ret中
    while (*dest++ = *src++) {
        //直到 赋值过去 表达式为假
        ;
    }

    return ret;
}

int main() {
    char arr1[20] = "abcdefefadw";
    char arr2[] = "hello world";
    printf("%sn", my_strcpy(arr1, arr2));
    return 0;
}

1.3 strcat

strcat()函数用于将源字符串追加到目标字符串的末尾,包括字符串结尾的空字符('')。

strcat()函数的函数原型如下:

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

其中,char *dest是目标字符串数组的指针,表示要将源字符串追加到的目标字符串;const char *src是源字符串的指针,表示要追加的字符串。

strcat()函数的工作方式是从目标字符串的结尾开始,逐个将源字符串中的字符复制到目标字符串末尾,直到遇到源字符串的结尾空字符('')。然后,在目标字符串的末尾添加一个空字符('')来标识新的字符串结尾。

需要注意的是,目标字符串数组必须具有足够的空间来存储源字符串追加后的结果,否则可能导致缓冲区溢出,造成程序崩溃或安全漏洞。因此,在使用strcat()函数时,应该确保目标字符串的长度足够大。

下面是一个使用strcat()函数的简单例子:

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

int main() {
    char dest[20] = "Hello, ";
    const char *src = "World!";

    strcat(dest, src);

    printf("Concatenated string: %sn", dest);   //Concatenated string: Hello, World!

    return 0;
}

模拟实现strcat

#include <assert.h>
#include <stdio.h>
#include <string.h>
char *my_strcat(char *dest, const char *src) {
    //1.找目标空间的
    char *cur = dest;
    while (*dest != '') {
        dest++;
    }
    //2.拷贝源头数据到之后的空间
    while (*dest++ = *src++) {
        ;
    }

    return cur;
}

int main() {
    char arr1[20] = "hello xxxxx";
    char arr2[] = "world";
    printf("%sn", my_strcat(arr1, arr2));
    return 0;
}

1.4 strcmp

strcmp()函数用于比较两个字符串,并根据字符串的大小关系返回一个整数值。

strcmp()函数的函数原型如下:

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

其中,const char *str1const char *str2是两个要比较的字符串的指针。

strcmp()函数的返回值有以下三种情况:

  • 如果str1str2相等,返回值为0。
  • 如果str1小于str2,返回值为一个负整数(通常为-1)。
  • 如果str1大于str2,返回值为一个正整数(通常为1)。

strcmp()函数会按照字典顺序逐个比较字符串中的字符,直到遇到不同的字符或遇到两个字符串的结尾空字符('')为止。比较是按照字符的ASCII码值进行的,因此,字符串中字符的大小关系是按照它们在ASCII码表中的顺序来决定的。

下面是一个使用strcmp()函数的简单例子:

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

int main() {
    const char *str1 = "apple";
    const char *str2 = "banana";

    int result = strcmp(str1, str2);

    if (result < 0) {
        printf("%s is less than %sn", str1, str2);
    } else if (result > 0) {
        printf("%s is greater than %sn", str1, str2);
    } else {
        printf("%s is equal to %sn", str1, str2);
    }

    return 0;
}
//输出结果:apple is less than banana

strcmp()函数将字符串"apple"与字符串"banana"进行比较,因为'a'的ASCII码值比'b'小,所以"apple"被认为是小于"banana"。函数返回一个负整数(-1),表示str1小于str2

模拟实现strcmp

#include <stdio.h>
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)
	{
		if (*str1 == '')
		{
			return 0;
		}
		str1++;
		str2++;
	}
	return *str1 - *str2;   //比较的是ascall码值
}

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "zabcdef";
	int ret = my_strcmp(arr1, arr2);
	if (ret < 0)
		printf("arr1<arr2n");
	else if (ret > 0)
		printf("arr1>arr2n");
	else
		printf("arr1==arr2n");
	return 0;
}

//输出结果:arr1<arr2

2.长度受限制的字符串函数

2.1 strncpy

strncpy()函数用于将源字符串的一部分复制到目标字符串中

strncpy()函数的函数原型如下:

char *strncpy(char *dest, const char *src, size_t n);

其中,char *dest是目标字符串数组的指针,表示要复制到的目标字符串;const char *src是源字符串的指针,表示要复制的字符串;size_t n表示要复制的最大字符数。

strncpy()函数的工作方式是从源字符串的开头开始,逐个将字符复制到目标字符串中,直到复制了n个字符或者遇到源字符串的结尾空字符('')为止。如果源字符串的长度小于n,那么目标字符串将在最后添加额外的空字符('')来填满n个字符。

需要注意的是,strncpy()函数不保证目标字符串以空字符结尾,如果复制的字符数达到了n,而源字符串还未结束,目标字符串将不会以空字符结尾。因此,在使用strncpy()函数时,应该注意目标字符串是否以空字符结尾。

下面是一个使用strncpy()函数的简单例子:

#include <stdio.h>
#include <string.h>
int main() {
    char arr1[20] = "abcdef";
    char arr2[] = "xxxx";
    strncpy(arr1, arr2, 2);//xxcdef  只拷贝2个字符
    //strncpy(arr1, arr2, 8);  //xxxx
    printf("%sn", arr1);
    return 0;
}

2.2 strncat

strncat()函数用于将源字符串的前若干个字符追加到目标字符串的末尾

strncat()函数的函数原型如下:

char *strncat(char *dest, const char *src, size_t n);

其中,char *dest是目标字符串数组的指针,表示要将源字符串追加到的目标字符串;const char *src是源字符串的指针,表示要追加的字符串;size_t n表示要追加的最大字符数。

下面是两个使用strncat()函数的简单例子:

#include <stdio.h>
#include <string.h>
int main() {
    char arr1[20] = "abcdef";
    char arr2[] = "xyz";
    strncat(arr1, arr2, 2);//2表示追加2个字符
    printf("%sn", arr1);  //abcdefxy
    return 0;
}
#include <stdio.h>
#include <string.h>
int main() {
    char arr1[20] = "abc";
    char arr2[] = "xyz";
    strncat(arr1, arr1, 3);//2表示追加2个字符
    printf("%sn", arr1);  //abcabc
    return 0;
}

2.3 strncmp

strncmp()函数用于比较两个字符串的前若干个字符,根据字符串的大小关系返回一个整数值。

strncmp()函数的函数原型如下:

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

其中,const char *str1const char *str2是两个要比较的字符串的指针,size_t n表示要比较的字符数。

下面是一个使用strncmp()函数的简单例子:

#include <stdio.h>
#include <string.h>
int main() {
    int ret = strncmp("abcdef", "abc", 3);//3表示比较前三个
    printf("%dn", ret);                  //0

    ret = strncmp("abcdef", "abc", 4);
    printf("%dn", ret);//1
    return 0;
}

3.字符串查找函数

3.1 strstr

strstr 是 C 语言中用于在字符串中查找子字符串的函数。

它的函数原型为:

char *strstr(const char *str1, const char *str2);
  • str1:要搜索的主字符串。
  • str2:要查找的子字符串。

函数返回一个指向第一次在 str1 中找到 str2 的指针,如果未找到,则返回 NULL

下面对 strstr 函数的使用进行详细解释:

示例 1:

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

int main() {
    char str1[] = "Hello, world!";
    char str2[] = "world";

    char *result = strstr(str1, str2);

    if (result != NULL) {
        printf("'%s' is found in '%s'n", str2, str1);
        printf("Found at position: %ldn", result - str1);
    } else {
        printf("'%s' is not found in '%s'n", str2, str1);
    }

    return 0;
}

输出:

'world' is found in 'Hello, world!'
Found at position: 7

示例 2:

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

int main() {
    char str1[] = "I love programming!";
    char str2[] = "Python";

    char *result = strstr(str1, str2);

    if (result != NULL) {
        printf("'%s' is found in '%s'n", str2, str1);
        printf("Found at position: %ldn", result - str1);
    } else {
        printf("'%s' is not found in '%s'n", str2, str1);
    }

    return 0;
}

输出:

'Python' is not found in 'I love programming!'

模拟实现strstr

#include <stdio.h>
char *my_strstr(const char *str1, const char *str2) {
    if (*str2 == '') {
        return (char *)str1; // 如果 str2 是空字符串,直接返回 str1 的地址
    }

    while (*str1) {
        const char *temp_str1 = str1;
        const char *temp_str2 = str2;

        // 在 str1 中查找与 str2 相同的子字符串
        while (*temp_str1 && *temp_str2 && (*temp_str1 == *temp_str2)) {
            temp_str1++;
            temp_str2++;
        }

        // 如果找到了完全匹配的子字符串,则返回 str1 的地址
        if (*temp_str2 == '') {
            return (char *)str1;
        }

        // 否则,继续在 str1 中寻找下一个可能的匹配位置
        str1++;
    }

    return NULL; // 没有找到匹配的子字符串,返回 NULL
}

int main() {
    char str1[] = "Hello, world!";
    char str2[] = "world";

    char *result = my_strstr(str1, str2);

    if (result != NULL) {
        printf("'%s' is found in '%s'n", str2, str1);
        printf("Found at position: %ldn", result - str1);
    } else {
        printf("'%s' is not found in '%s'n", str2, str1);
    }

    return 0;
}
//'world' is found in 'Hello, world!'

4.字符串拆分函数

4.1 strtok

strtok 是 C 语言中用于将字符串拆分成子字符串的函数。

其函数原型如下:

char *strtok(char *str, const char *delimiters);
  • str:要拆分的字符串,第一次调用时传入要拆分的字符串,在后续调用中设置为 NULL。
  • delimiters:作为分隔符的字符串,用于确定拆分子字符串的位置。

函数返回一个指向拆分后的子字符串的指针。在第一次调用时,函数返回第一个拆分的子字符串,后续调用返回后续的子字符串,直到没有更多的子字符串可供拆分,此时返回 NULL。

示例:

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

int main() {
    char str[] = "apple,banana,orange,grape";

    // 拆分字符串
    char *token = strtok(str, ",");

    while (token != NULL) {
        printf("%sn", token);
        token = strtok(NULL, ",");
    }

    return 0;
}

模拟实现strtok

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

char *my_strtok(char *str, const char *delimiters) {
    static char *nextToken = NULL; // 用于保存下一个 token 的位置

    if (str != NULL) {
        nextToken = str; // str!=NULL,表示第一次调用,设置初始位置
    }

    if (nextToken == NULL || *nextToken == '') {
        return NULL; // 没有更多的 token 可供拆分
    }

    // 跳过开始的分隔符字符
    while (*nextToken && strchr(delimiters, *nextToken)) {
        nextToken++;
    }

    if (*nextToken == '') {
        return NULL; // 已到达字符串末尾
    }

    // 找到 token 的起始位置
    char *currentToken = nextToken;

    // 继续查找下一个分隔符位置,将其替换为 NULL 字符
    while (*nextToken && !strchr(delimiters, *nextToken)) {
        nextToken++;
    }

    if (*nextToken) {
        *nextToken = ''; // 替换为 NULL 字符
        nextToken++; // 下一个 token 的起始位置
    }

    return currentToken; // 返回当前拆分的 token
}

int main() {
    char str[] = "apple,banana,orange,grape";
    char delimiters[] = ",";

    char *token = my_strtok(str, delimiters);

    while (token != NULL) {
        printf("%sn", token);
        token = my_strtok(NULL, delimiters);
    }

    return 0;
}

5.错误信息报告函数

5.1 strerror

strerror 用于将错误码(整数)转换为对应的错误消息字符串。该函数通常用于处理与系统调用和库函数相关的错误,将错误码转换为人类可读的错误消息,方便程序员或用户理解和处理错误。

函数原型如下:

char *strerror(int errnum);
  • errnum:要转换的错误码。

函数返回一个指向错误消息字符串的指针。该字符串通常是静态分配的,不应该被修改。因此,最好将返回的字符串复制到另一个缓冲区中,以免被覆盖。

示例:

#include <errno.h>
#include <stdio.h>
#include <string.h>
int main() {
    //strerror的错误码
    //c语言中库函数报错的时候的错误码
    printf("%sn", strerror(0));//No error
    printf("%sn", strerror(1));//Operation not permitted
    printf("%sn", strerror(2));//No such file or directory
    printf("%sn", strerror(3));//No such process
    printf("%sn", strerror(4));//Interrupted function call
    return 0;
}
#include <errno.h>
#include <stdio.h>
#include <string.h>
int main() {
    //错误码记录到错误码的变量中
    //errno -  #include<errno.h>  C语言提供的全局的错误变量
    FILE *pf = fopen("test.txt", "r");
    if (pf == NULL) {
        perror("fopen");   //perror = printf+strerror    打印fopen: No such file or directory
        //打印的依然是error变量中错误码对应的错误信息
        printf("%sn", strerror(errno));//返回了2错误码
        return 1;
    }
    //读文件
    fclose(pf);
    pf = NULL;
    return 0;
}

6.字符操作函数

6.1 字符输入输出函数

getchar和putchar

在 C 语言中,有几个常用的字符输入输出函数,用于读取和输出单个字符。

以下是其中几个常用的字符输入输出函数:

1.getcharputchar 函数:

int getchar(void);
int putchar(int c);
  • getchar 函数用于从标准输入(通常是键盘)读取单个字符,并返回读取的字符的 ASCII 值(作为整数)。
  • putchar 函数用于向标准输出(通常是屏幕)输出单个字符。它的参数是一个整数(字符的 ASCII 值)。

这两个函数可以用来逐个读取和输出字符。例如,可以使用 getchar 来读取用户的输入字符,然后使用putchar 将字符输出到屏幕上。

2.getcputc 函数:

int getc(FILE *stream);
int putc(int c, FILE *stream);
  • getc 函数从指定的文件流 stream 中读取一个字符,并返回读取的字符的 ASCII 值(作为整数)。
  • putc 函数将指定的字符 c 写入到文件流 stream 中。它的参数是一个整数(字符的 ASCII 值)。

这两个函数与 getcharputchar 函数类似,但可以用于从指定文件流中读取或输出字符。

需要注意的是,字符输入输出函数通常在遇到换行符或文件结尾时终止输入。在使用这些函数时,要确保输入输出的字符数量和顺序符合预期,避免因缓冲区问题导致意外行为。

示例:

#include <stdio.h>

int main() {
    int ch;

    printf("Enter a character: ");
    ch = getchar();
    printf("You entered: ");
    putchar(ch);
    printf("n");

    return 0;
}

6.2 字符分类函数

在 C 语言中,有一组字符分类函数,用于确定字符的属性。这些函数是 ctype.h 头文件中的标准库函数,提供了一系列用于字符分类的工具。

函数 条件
iscntrl 任何控制字符
isspace 空白字符:空格‘ ’,换页‘f’,换行’n’,回车‘r’,制表符’t’或者垂直制表符’v’
isdigital 十进制数字 0~9
isxdigital 十六进制数字,包括所有十进制数字,小写字母af,大写字母AF
islower 小写字母a~z
isupper 大写字母A~Z
isalpha 字母az或AZ
isalnum 字母或者数字,az,AZ,0~9
ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph 任何图形字符
isprint 任何可打印字符,包括图形字符和空白字符

6.3 字符大小写转换函数

1.tolower 函数:

int tolower(int c);
  • 用于将大写字母转换为相应的小写字母。如果 c 是大写字母,则返回其对应的小写字母;否则,返回原字符 c

2.toupper 函数:

int toupper(int c);
  • 用于将小写字母转换为相应的大写字母。如果 c 是小写字母,则返回其对应的大写字母;否则,返回原字符 c

实例1:

int main(){
    char ch = 'w';
    printf("%cn", toupper(ch)); // toupeer 转换成大写字母 - W
    char ch2 = 'A';
    printf("%cn", tolower(ch2)); // tolower 转换成小写字母 - a
    return 0;
}

实例2:

#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main() {
    char arr[] = "Are you ok?";
    char *p = arr;
    while (*p) {
        if (islower(*p))//islower 判断是否是小写字母
        {
            *p = toupper(*p);
        }
        p++;
    }
    printf("%sn", arr);// ARE YOU OK?
    return 0;
}

7.内存函数

7.1 memcpy

memcpy 是用于将内存块的内容从一个位置复制到另一个位置。

其函数原型如下:

void *memcpy(void *dest, const void *src, size_t n);
  • dest:目标内存块的起始地址,表示复制后的数据将存储在这个地址开始的内存块中。
  • src:源内存块的起始地址,表示要复制的数据来源于这个地址开始的内存块。
  • n:要复制的字节数,即要复制的内存块的大小。

函数返回值为 void * 类型,实际上是指向目标内存块的指针,即 dest 的值。

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);// 20表示字节 拷贝5个整型数据

    for (int i = 0; i < sizeof(arr2) / sizeof(int); i++) {
        printf("%d ", arr2[i]);//1 2 3 4 5 0 0 0 0 0
    }
    printf("n");

    float arr3[] = {1.0f, 2.0f, 3.0f, 4.0f};
    float arr4[] = {0.0};
    memcpy(arr4, arr3, 8);// 8表示拷贝2个浮点型数据

    for (int i = 0; i < sizeof(arr4) / sizeof(float); i++) {
        printf("%f ", arr4[i]);    //1.000000 
    }
    return 0;
}

模拟实现memcpy

#include <assert.h>
#include <stdio.h>
void *my_memcpy(void *dest, void *src, size_t num)//需要传void* 的地址   num的单位是字节
{
    assert(dest && src);
    void *ret = dest;
    while (num--)//交换num次字节的内容 一次交换一次字节
    {
        *(char *) dest = *(char *) src;
        dest = (char *) dest + 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};
    my_memcpy(arr2, arr1, 20);
    int i = 0;
    for (i = 0; i < 10; i++) {
        printf("%d ", arr2[i]);   //1 2 3 4 5 0 0 0 0 0

    }

    printf("n");

    float arr3[] = {1.0f, 2.0f, 3.0f, 4.0f};
    float arr4[10] = {0.0};
    my_memcpy(arr4, arr3, 8);
    for (i = 0; i < 10; i++) {
        printf("%f ", arr4[i]);    //1.000000 2.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 
    }
    return 0;
}

7.2 memmove

memmove函数与memcpy函数类似,都用于内存拷贝,但它可以处理源内存区域和目标内存区域的重叠情况。memmove函数的函数原型如下:

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

它接受三个参数:

  • dest:指向目标内存区域的指针,也就是要将数据拷贝到的位置。
  • src:指向源内存区域的指针,也就是要从中复制数据的位置。
  • n:要复制的字节数。

memmove函数会确保即使源内存区域和目标内存区域有重叠,数据也会正确地被复制。这意味着它比memcpy更安全,因为memcpy在处理重叠内存区域时可能会导致未定义行为。

实例:

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

int main() {
    float arr3[] = {1.0f, 2.0f, 3.0f, 4.0f};
    float arr4[] = {0.0f, 0.0f, 0.0f, 0.0f};
    memmove(arr4, arr3, sizeof(float) * 4);

    for (int i = 0; i < 4; i++) {
        printf("%f ", arr4[i]); // 输出: 1.000000 2.000000 3.000000 4.000000
    }

    return 0;
}

注意:

memcpy只需要实现不重叠的拷贝就可以了 VS中的memcpy和mommove实现方式差不多 可以替代

memmove是需要实现重叠内存的拷贝

模拟实现memmove

#include <assert.h>
#include <stdio.h>
#include <string.h>
void *my_memmove(void *dest, void *src, size_t num)//需要传void* 的地址   num的单位是字节
{
    assert(dest && src);
    void *ret = dest;
    if (dest < src) {
        while (num--)//交换num次字节的内容 一次交换一次字节
        {
            *(char *) dest = *(char *) src;
            dest = (char *) dest + 1;
            src = (char *) src + 1;
        }
    } else {
        while (num--) {
            *((char *) dest + num) = *((char *) src + num);//后面的数据 换到前面的数
        }
    }

    return ret;
}

int main() {
    float arr3[] = {1.0f, 2.0f, 3.0f, 4.0f};
    float arr4[] = {0.0f, 0.0f, 0.0f, 0.0f};
    my_memmove(arr4, arr3, sizeof(float) * 4);

    for (int i = 0; i < 4; i++) {
        printf("%f ", arr4[i]);// 输出: 1.000000 2.000000 3.000000 4.000000
    }

    return 0;
}

7.3 memcmp

memcmp用于比较两个内存区域的内容是否相等。

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

memcmp函数接受三个参数:

  • ptr1:指向要比较的第一个内存区域的指针。
  • ptr2:指向要比较的第二个内存区域的指针。
  • num:要比较的字节数。

memcmp函数将会按字节逐个比较两个内存区域中的数据,直到比较完指定的字节数num或者遇到不相等的字节为止。如果两个内存区域的数据完全相等,则memcmp函数返回0。如果两个内存区域的数据不相等,则返回一个小于0的值或者大于0的值,其数值大小取决于第一个不相等的字节的差值。

下面是一个简单的例子:

#include <stdio.h>
#include <string.h>
int main(){
    int arr1[] = { 1,2,3,4,5 }; //01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00
    int arr2[] = { 1,2,3,0,0 }; //01 00 00 00 02 00 00 00 03 00 00 00 00 00 00 00
    int ret = memcmp(arr1, arr2, 12);    //前12字节的内存
    printf("%dn", ret); //0  

    ret = memcmp(arr1, arr2, 13);   //前13字节的内存
    printf("%dn", ret);  //1
    return 0;
}

模拟实现memcmp

int my_memcmp(const void* ptr1, const void* ptr2, size_t num) {
    const unsigned char* byte_ptr1 = (const unsigned char*)ptr1;
    const unsigned char* byte_ptr2 = (const unsigned char*)ptr2;

    for (size_t i = 0; i < num; i++) {
        if (byte_ptr1[i] < byte_ptr2[i]) {
            return -1;
        } else if (byte_ptr1[i] > byte_ptr2[i]) {
            return 1;
        }
    }

    return 0;
}

7.4 memset

memset函数用于将指定的内存区域设置为特定的值。

其函数原型如下:

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

memset函数接受三个参数:

  • ptr:指向要设置的内存区域的指针。
  • value:要设置的值,通常以整数形式传递,但实际上会被转换为unsigned char类型。
  • num:要设置的字节数。

memset函数会将指定内存区域的每个字节都设置为value指定的值,重复num次。它通常用于对数组或结构体进行初始化,也可用于将内存区域置零。

实例:

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

模拟实现memset

void* my_memset(void* ptr, int value, size_t num) {
    unsigned char* byte_ptr = (unsigned char*)ptr;
    unsigned char byte_value = (unsigned char)value;

    for (size_t i = 0; i < num; i++) {
        byte_ptr[i] = byte_value;
    }

    return ptr;
}