C/C++ | 高频手撕整理(1) —— strstr,memcpy,memmove函数模拟实现

💓个人主页:mooridy
💓专栏地址:C语言
关注我🌹,和我一起学习更多计算机的知识
🔝🔝🔝

strstr函数模拟实现

在这里插入图片描述
函数返回字符串str2在字符串str1中第⼀次出现的位置,如果找不到,返回NULL.

//返回str2在str1中出现的位置,如果找不到,返回NULL
char* strstr(const char* str1, const char* str2) {
	//1.如果str2为空串
	if (!str2) {
		return str1;
	}
	
	char* cp=str1;用于遍历str1
	while (*cp) {
		char* p1 = cp;
		char* p2 = str2;//每次都要归位
		while (*p1 && *p2) {  //条件:两个都还没走到末尾
			if (*p1 == *p2) {
				p1++;
				p2++;
			}
			else {
				break;
			}
		}
        if (!*p2) { return cp; }
        else { cp++; }

	}
}


测试用例:

int main() {
    // 测试用例1:str2在str1中存在
    char str1[] = "hello world";
    char str2[] = "world";
    char* result1 = strstr(str1, str2);
    if (result1) {
        printf("测试用例1:找到了,位置为:%s\n", result1);
    }
    else {
        printf("测试用例1:未找到\n");
    }

    // 测试用例2:str2在str1中不存在
    char str3[] = "abcdefg";
    char str4[] = "xyz";
    char* result2 = strstr(str3, str4);
    if (result2) {
        printf("测试用例2:找到了,位置为:%s\n", result2);
    }
    else {
        printf("测试用例2:未找到\n");
    }

    // 测试用例3:str2为空串
    char str5[] = "test";
    char* str6 = "";
    char* result3 = strstr(str5, str6);
    if (result3) {
        printf("测试用例3:找到了,位置为:%s\n", result3);
    }
    else {
        printf("测试用例3:未找到\n");
    }

    // 测试用例4:str1为空串,str2不为空串
    char* str7 = "";
    char str8[] = "test";
    char* result4 = strstr(str7, str8);
    if (result4) {
        printf("测试用例4:找到了,位置为:%s\n", result4);
    }
    else {
        printf("测试用例4:未找到\n");
    }

    return 0;
}

在这里插入图片描述

memcpy函数模拟实现

在这里插入图片描述

设计成void指针的原因:void 是一种无类型指针,可以指向任何类型的数据。这样 memcpy 就能够用于不同类型数据的内存复制操作,无论是基本数据类型(如 int、char、float 等)还是自定义数据类型(如结构体、联合体等),都可以使用 memcpy 进行内存复制,而不需要为每种数据类型都编写一个专门的复制函数。

void* mymemcpy(void* dest, void* src,size_t num) {
	char* p1 = (char*)dest;
	char* p2 = (char*)src;
	void* ret = (char*)dest;
	while (num--) {
		*p1 = *p2;
		p1++;
		p2++;
	}
	return ret;
}

测试用例:

int main() {
    // 测试用例 1: 复制字符数组
    char src1[] = "Hello, World!";
    char dest1[20];
    mymemcpy(dest1, src1, strlen(src1) + 1);
    assert(strcmp(dest1, src1) == 0);
    printf("测试用例 1 通过: 复制字符数组成功,复制结果: %s\n", dest1);

    // 测试用例 2: 复制整数数组
    int src2[] = { 1, 2, 3, 4, 5 };
    int dest2[5];
    mymemcpy(dest2, src2, sizeof(src2));
    for (int i = 0; i < 5; i++) {
        assert(dest2[i] == src2[i]);
    }
    printf("测试用例 2 通过: 复制整数数组成功\n");

    // 测试用例 3: 复制单个字符
    char src3 = 'A';
    char dest3;
    mymemcpy(&dest3, &src3, sizeof(char));
    assert(dest3 == src3);
    printf("测试用例 3 通过: 复制单个字符成功,复制结果: %c\n", dest3);

    

    printf("所有测试用例通过!\n");
    return 0;
}

memmove函数模拟实现

在这里插入图片描述
和memcpy的差别就是memmove函数处理的源内存块和⽬标内存块是可以重叠的。
如果源空间和⽬标空间出现重叠,就得使⽤memmove函数处理。

思路精华:
当dest地址低于src地址时,指针从前往后;

当src地址低于dest地址时,指针从后往前。

详细请见:这篇博客

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <assert.h>
void* mymemmove(void* dest, void* src, size_t num) {
	//判断指针是否为空
	assert(dest);
	assert(src);
	void* ret = dest;
	char* p1 = (char*)dest;
	char* p2 = (char*)src;
	//dest在前src在后,从前往后
	if (dest < src) {
		while (num--) {
			*p1 = *p2;
			p1++;
			p2++;

		}
	}
	else {  //dest在后src在前,从后往前
		p1 = (char*)dest + num - 1;
		p2 = (char*)src + num - 1;
		while (num--) {
			*p1 = *p2;
			p1--;
			p2--;

		}
	}

	return ret;

}

测试用例

int main() {
	// 非重叠内存复制示例
	char non_overlap_src[] = "Hello, World!";
	char non_overlap_dest[20];

	// 使用 memmove 进行非重叠内存复制
	mymemmove(non_overlap_dest, non_overlap_src, strlen(non_overlap_src) + 1);
	printf("非重叠内存复制结果: %s\n", non_overlap_dest);

	// 重叠内存复制示例(dest 在前,src 在后)
	char overlap_str1[] = "abcdefg";
	// 将 "cde" 复制到字符串开头
	mymemmove(overlap_str1, overlap_str1 + 2, 3);
	printf("重叠内存复制(dest 在前,src 在后)结果: %s\n", overlap_str1);

	// 重叠内存复制示例(src 在前,dest 在后)
	char overlap_str2[] = "abcdefg";
	// 将前三个字符复制到偏移 2 的位置
	mymemmove(overlap_str2 + 2, overlap_str2, 3);
	printf("重叠内存复制(src 在前,dest 在后)结果: %s\n", overlap_str2);

	return 0;
}

在这里插入图片描述
To be continued~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值