阅读背景:

几个常见的库函数strlen、strcmp、strcat、strcpy、strncpy、memset、memcpy、memmove

来源:互联网 

strlen()

1)计算给定字符串的长度,不包括’

strlen()

1)计算给定字符串的长度,不包括’\0’在内

unsigned int strlen(const char *s)
{
    assert(NULL != s);//如果条件不满足,则终止程序
    unsigned int length = 0;
    while (*s++ != '\0')
        ++length;
    return length;
}

strcmp()

1)比较两个字符串,若str1、str2字符串相等,则返回零;若str1大于str2,则返回正数;否则,则返回负数

int strcmp(const char *str1, const char *str2)
{
    assert(NULL != str1 && NULL != str2);
    while(*str1 && *str2 && *str1 == *str2)
    {
        ++str1;
        ++str2;
    }
    return *str1 - *str2;
    //若相等,则*str1 - *str2 = '\0' - '\0' = 0;否则,*str1 - *str2 != 0;因为前面的位都相等,所以只需要比较当前位来确定返回值
}

strcat()

1)将src所指向的字符串添加到dest结尾处(会覆盖dest结尾处的'\0'

2)src和dest所指内存区域不可以重叠且dest必须有足够的空间(sizeof(dest)-strlen(dest)必须>=strlen(src)+1)来容纳src的字符串

char* strcat(char* dest, const char* src)
{
    assert(NULL != dest && NULL != src);//如果条件不满足,则终止程序
    char* temp = dest;
    while ('\0' != *temp)//while循环出来temp指向原字符串的NULL空字符的位置
        ++temp;
    while (*src != '\0')
        *temp++ = *src++;
    return dest;
}

strcpy()

1)把字符串src(包括'\0')复制到dest

2)src和dest所指内存区域不可以重叠且dest必须有足够的空间(sizeof(dest)>=strlen(src)+1)来容纳src的字符串

3)返回值char*而不是void,实现了链式表达(就是让调用strcpy的时候可以方便一些,在调用的时候可以一连串(链式)写下来)

char* strcpy(char* dest, const char *src)
{
    assert(NULL != dest && NULL != src);
    char * temp = dest;
    while (*src != '\0')
        *temp++ = *src++;
    return dest;
}

strncpy()

1)将以字符串src所指向的地址开始的前n个字节复制到dest中,并返回dest

2)如果src的前n个字符不含NULL结束符,则dest不会以NULL字符结束

3)如果n>strlen(src)+1,则以'\0'填充dest,直到复制完n个字节

4)src和dest所指内存区域不可以重叠且dest必须有足够的空间(sizeof(dest)>=strlen(src)+1)来容纳src的字符串

5)dest和n应该满足:sizeof(dest)>=n

char* strncpy(char* dest, const char* src, unsigned int n)
{
    assert(NULL != dest && NULL != src);
    char* temp = dest;
    while (n > 0 && *src != '\0')
    {
        *temp++ = *src++;
        --n;
    }
    while (n > 0)
    {
        *temp++ = '\0';
        --n;
    }
    return dest;
}

memset()

1)将以s所指向的地址开始的前n个字节用ch替换,并返回s

2)常用于对较大的数组进行清零操作

void* memset(void* s, int ch, unsigned int n)
{
    assert(NULL != s);
    char* temp = s; //VS2017中这里会报错,gcc不会
    while (n > 0)
    {
        *temp++ = (char)ch; //将int转化为char,截去高24位,只保留低8位
        --n;
    }
    return s;
}

3)注意:不能把memset当作万能的初始化工具,应该只把memset当作清0的工具,因为memset是以字节(8bits)为单位进行赋值的

int main()
{
    int dest[2];//这里是int
    memset(dest, 1, sizeof(dest));
    for (int i = 0; i < sizeof(dest) / sizeof(int); ++i)
        printf("%d\n", dest[i]);

    return 0;
}
程序输出:
16843009
16843009

int main()
{
    int dest[2];//这里是int
    memset(dest, 0, sizeof(dest));
    for (int i = 0; i < sizeof(dest) / sizeof(int); ++i)
        printf("%d\n", dest[i]);

    return 0;
}
程序输出:
0
0

程序解读:

  1)1的二进制 : 00000000000000000000000000000001(32位),在memset源码中1将强制类型转换成char(1字节占8位)00000001(8位)

  2)memset函数传入的是sizeof(dest),也就是8(字节),所以n=8,进行8次while循环

  3)temp的类型是char*,所以会8位8位地去赋值

  4)所以while循环结束,从起始地址开始的值为:0000000100000001000000010000000100000001000000010000000100000001(64位)

  5)memset()调用结束后,dest的每个元素按照int类型读取(按32位读取),所以dest[0]=00000001000000010000000100000001(32位)=16843009,dest[1]=00000001000000010000000100000001(32位)=16843009

memcpy()

1)将以src所指向的地址开始的前n个字节到拷贝到dest

2)src和dest所指内存区域不可以重叠,否则拷贝出来的数据将是错误的

void* memcpy(void* dest, const void* src, unsigned int n)
{
    assert(NULL != dest && NULL != src);
    void* temp = dest;
    for (int i = 0; i < n; ++i)
        *((char*)temp + i) = *((char*)src + i); //1个字节1个字节地拷贝,未知类型,不能++
    return dest;
}

memmove()

1)memmove也是将以src所指向的地址开始的前n个字节到拷贝到dest,但是可以它可以处理src和dest所指内存区域存在重叠的情况(src<dest<src+n)

2)memmove这个函数名称中有"move"这个单词,但实际上并不是"移动"了。这个函数名称有它的历史原因:因为有了memcpy函数后,发现这个函数在使用时容易出现问题,于是又发明了一个能够处理重叠的memcpy函数,但为了保证兼容性依然保留了memcpy函数

void* memmove(void* dest, const void* src, unsigned int n)
{
    assert(NULL != dest && NULL != src);
    void* temp = dest;
    if (dest > src || dest < src + n)//内存重叠
    {
        for (int i = n - 1; i >= 0; --i)//从高地址向低地址拷贝
            *((char*)temp + i) = *((char*)src + i);
    }
    else//内存不重叠
    {
        for (int i = 0; i < n; ++i)
            *((char*)temp + i) = *((char*)src + i);
    }
    return dest;
}

 


’在内

unsigned unsigne



你的当前访问异常,请进行认证后继续阅读剩余内容。

分享到: