运用指针模拟实现一些代码以及memcpy函数与memmove函数的区别

学习以下代码的准备工作:

  1. 了解简单的指针知识
  2. 了解assert()函数
    原型在assert.h中,作用是如果其值为假(即为0),则终止程序
  3. 了解关键字const 、extern的基本用法
    const:修饰变量,让变量具有只读属性,保护变量使其不能直接被改变
    extern:声明外部函数、变量
  4. 了解两个指针相减的实质
    是两个指针之间经历的元素个数

  5. 了解基本的内存操作

以下代码都在VS2013环境中执行:

1.模拟实现strcat

  1. c函数原型:extern char* strcat(char *dest, const char *src)

  2. 函数功能:strcat是连接字符串的函数。把src所指向的字符串添加到dest结尾处(覆盖dest结尾处的’\0’)并添加’\0’

  3. 注意:两个参数所指向的内存区域不可以重叠,dest参数所指向的内存地址必须能容纳两个字符串连接后的大小。

  4. 模拟代码如下:

#include<stdio.h>
#include<assert.h>
char* my_strcat(char *dest, const char *src)
{
    char *ret = dest;
    assert(dest);
    assert(src);
    while (*(++dest))
    {
        ;
    }
    while((*dest++ = *src++));
    return ret;

}
int main()
{
    char s1[10] = { 0 };
    const char s2[10] = { 0 };
    printf("Enter a str1:");
    scanf("%s", s1);
    printf("Enter a str2:");
    scanf("%s", s2);
    my_strcat(s1, s2);
    printf("%s", s1);
    system("pause");
    return 0;
}

运行结果

引用块内容

2.模拟实现strcpy

  1. c函数原型:char* strcpy(char *dest, const char *src)

    扫描二维码关注公众号,回复: 2654202 查看本文章
  2. 函数功能:strcat是复制字符串的函数。把从src地址开始且含有’\0’的字符串复制到以dest开始的地址空间内

  3. 注意:两个参数所指向的内存区域不可以重叠,dest参数所指向的内存地址必须能容纳scr的字符串
  4. 模拟代码如下:
#include<stdio.h>
#include<assert.h>
char* my_strcpy(char *dest, const char *src)
{
    char *ret = dest;
    assert(dest);
    assert(src);
    while (*dest++ = *src++);
    return ret;

}
int main()
{
    char s1[10] = { 0 };
    const char s2[10] = { 0 };
    printf("Enter a str1:");
    scanf("%s", s1);
    printf("Enter a str2:");
    scanf("%s", s2);
    my_strcpy(s1, s2);
    printf("%s", s1);
    system("pause");
    return 0;
}

运行结果如下:

引用块内容

3. 模拟实现strstr

  1. c函数原型:extern char* strstr(const char *str1, const char *str2)

  2. 函数功能:搜索str2在str1中的第一次出现,若找到返回字符串的其余部分(从匹配点开始),如果没有找到所搜索的字符串,则返回NULL

  3. 模拟代码如下:
#include<stdio.h>
#include<assert.h>
char* my_strstr(const char *dest, const char *src)
{

    char *s1 = 0;
    char *s2 = 0;
    assert(dest);
    assert(src);
    while (*dest)
    {
        s1 = dest;
        s2 = src;
        while ((*s1 == *s2) && (*s2) && (*s1))
        {
            s1++;
            s2++;
        }
        if (*s2 == '\0')
            return dest;
        dest++;

    }
    return NULL;
}
int main()
{
    const char s1[10] = { 0 };
    const char s2[10] = { 0 };
    printf("Enter a str1:");
    scanf("%s", s1);
    printf("Enter a str2:");
    scanf("%s", s2);
    if (my_strstr(s1, s2) != NULL)
    {

        printf("%s\n", my_strstr(s1, s2));
    }
    else
        printf("没有找到!\n");
    system("pause");
    return 0;
}

运行结果如下:

引用块内容

4.模拟实现strchr

  1. c函数原型:extern char* strchr(const char *s, char c)
  2. 函数功能:查找字符串s中首次出现字符c的位置
  3. 注意:返回首次出现c的位置的指针,返回的地址是字符串在内存中随机分配的地址再加上你所搜索的字符串在字符串中的位置,如果s中不存在c则返回NULL
  4. 模拟代码如下
#include<stdio.h>
#include<assert.h>
char* my_strchr(const char *dest, char c)
{


    assert(dest);
    assert(c);
    while (*dest)
    {
        if (*dest == c)
            return dest;
        dest++;
    }
    return NULL;
}
int main()
{
    const char s1[10] = { 0 };
    const char *s2=0;
    printf("Enter a str1:");
    scanf("%s", s1);
    printf("Enter a str2:");
    fflush(stdin);
    scanf("%c", &s2);
    if (my_strchr(s1, s2) != NULL)
    {
        printf("%d\n", my_strchr(s1, s2) - s1 + 1);//两个指针相减的实质是两个指针之间经历的元素个数
    }
    else
        printf("没有找到!\n");
    system("pause");
    return 0;
}

运行结果:

引用块内容

5. 模拟实现strcmp

  1. c函数原型:extern char* strcpy(const char *s1, const char *s2)

  2. 函数功能:比较两个字符串的大小

  3. 规则:当s1小于s2,返回负数;当s1==s2,返回0;当s1大于s2,返回正数。即:两个字符串自左向右逐个字符相比(按ASCII值大小比较),直到出现不同的字符或遇到’\0’为止
  4. 注意:这里只能比较字符串
  5. 模拟代码如下:
#include<stdio.h>
#include<assert.h>
int  my_strcmp(const char *dest, const char *src)
{

    assert(dest);
    assert(src);
    while ((*dest) && (*src))
    {

        if (*dest != *src)
        {
            return *dest - *src;
        }
        else
        {
            dest++;
            src++;
        }
    }
    if ((*dest == '\0') && (*src == '\0'))
        return 0;
    if (*dest == '\0')
        return -1;
    if (*src == '\0')
        return 1;
}

int main()
{
    const char s1[10] = { 0 };
    const char s2[10] = { 0 };
    printf("Enter a str1:");
    scanf("%s", s1);
    printf("Enter a str2:");
    scanf("%s", s2);
    if (my_strcmp(s1, s2) == 0)
        printf("相等!\n");
    if (my_strcmp(s1, s2) > 0)
        printf("s1>s2\n");
    if (my_strcmp(s1, s2) < 0)
        printf("s1<s2\n");
    system("pause");
    return 0;
}

运行结果:

引用块内容

6. 模拟实现memcpy

  1. c函数原型:void *my_memcpy(void *dest, const void *src,int count)
  2. 函数功能:各种类型数据的复制,由src所指内存区域复制count个字节到dest所指向内存区域
  3. 规则:两个参数所指向的内存区域不可以重叠,dest参数所指向的内存地址必须能容纳scr的内存空间
  4. 模拟代码如下:
#include<stdio.h>
#include<assert.h>
void *my_memcpy(void *dest, const void *src,int count)
{
    assert(dest);
    assert(src);
    char *dest1 = (char*)dest;
    char *src1 = (char*)src;
        while (count>0)
        {
            *dest1 = *src1;
            dest1++;
            src1++;
            count--;
        }
        return dest;
}
int main()
{
    const int s1[10] = { 0 };
    const int s2[10] = { 1,2,3,4,5,6 };
    int i = 0;
    int count = sizeof(s2);
    my_memcpy(s1, s2,count);
    for (i = 0; i < sizeof(s2) / sizeof(s2[0]);i++)
    printf("%d ", s2[i]);
    system("pause");
    return 0;
}

运行结果:

引用块内容

7.模拟实现memmove

  1. c函数原型:void *my_memcpy(void *dest, const void *src,int count)
  2. 函数功能:各种类型数据的复制,由src所指内存区域复制count个字节到dest所指向内存区域
  3. 注意:这个函数是memcpy函数的升级版,不用担心两个参数所指向的内存区域重叠问题
  4. 模拟代码如下:
#include<stdio.h>
#include<assert.h>
void *memmove(void *dest, const void *src,int count)
{
    assert(dest);
    assert(src);
    char *dest1 = (char*)dest;
    char *src1 = (char*)src;
    char *p = dest1+count;
    char *q = src1 + count;
    if ((dest1 - src1)<count)
    {
        while (p>=dest1)
        {
            *p = *q;
            p--;
            q--;
        }
    }
    else
        while (count>0)
        {
            *dest1 = *src1;
            dest1++;
            src1++;
            count--;
        }
        return dest;
}
int main ( )
{
    const int s[10] = { 1,2,3,4,5,6 };
    int *s2 = s;
    int *s1 = s + 2;
    int i = 0;
    int count = sizeof(s);
    my_memmove(s1, s2,count);
    for (i = 0; i < sizeof(s)/sizeof(s[0]);i++)
    printf("%d ", s1[i]);
    system("pause");
    return 0;
}

运行结果:

引用块内容

8. memmove和memcpy的区别

如图,一般dest和scr在空间中分配内存有四种情况

引用块内容
在memcpy函数中,是将scr中的数据从低地址到高地址一个字节一个字节的考到dest中,前三种情况都不会出现scr中还未复制到dest中的数据被覆盖的情况,但第四种情况,当(dest - src)小于要拷的数据的个数的时候,在memcpy函数中则会出错,如下面一段代码:

#include<stdio.h>
#include<assert.h>
void *my_memcpy(void *dest, const void *src,int count)
{
    assert(dest);
    assert(src);
    char *dest1 = (char*)dest;
    char *src1 = (char*)src;
        while (count>0)
        {
            *dest1 = *src1;
            dest1++;
            src1++;
            count--;
        }
        return dest;
}
int main ( )
{
    const int s[10] = { 1,2,3,4,5,6 };
    int *s2 = s;
    int *s1 = s + 2;
    int i = 0;
    int count = sizeof(s);
    my_memcpy(s1, s2,count);
    for (i = 0; i < sizeof(s)/sizeof(s[0]);i++)
    printf("%d ", s1[i]);
    system("pause");
    return 0;
}

这里写图片描述
所以我们要从scr中的最后一个字符开始拷贝到dest中,即在memmove函数中分情况处理就好了,如下面一段代码:

void *memmove(void *dest, const void *src,int count)
{
    assert(dest);
    assert(src);
    char *dest1 = (char*)dest;
    char *src1 = (char*)src;
    char *p = dest1+count;
    char *q = src1 + count;
    if ((dest1 - src1)<count)
    {
        while (p>=dest1)
        {
            *p = *q;
            p--;
            q--;
        }
    }
    else
        while (count>0)
        {
            *dest1 = *src1;
            dest1++;
            src1++;
            count--;
        }
        return dest;
}

猜你喜欢

转载自blog.csdn.net/HL_HLHL/article/details/79048130