strcat、strcpy、strncpy、memset、memcpy、itoa、atoi的使用和内部实现

1:strcat

函数原型:

char	*strcat(char *__s1, const char *__s2);

在使用上要注意 char* a 和 char a[] 的区别,如下方式是错误的:

int main{
	char* a = "abc";
	char b[] = "def";
	char* c = strcat(a,b);
}

因为 a 指向的字符串分配在字符常量区,是不可更改的,而strcat会将b拼接在a上,因此报错。
如下写就没问题

int main{
	char a[] = "abc";
	char* b = "def";
	char* c = strcat(a,b);
}

还要注意的一点就是

char a[] = "abc";

结尾会加 ‘\0’。
自己实现的版本:

char* my_strcat(char* str1, const char* str2){
    char* cur = str1;
    while (*cur != '\0') {
        cur++;
    }
    while (*str2 != '\0') {
        *(cur++) = *(str2++);
    }
    *(++cur) = '\0';
    return str1;
};

while中判断是否为空,消耗时间,因此可以如下优化:

char* my_strcat(char* str1, const char* str2){
    assert(str1);
    assert(str2);
    char* head = str1;
    while (*str1 != '\0') {
        str1++;
    }
    while ((*str1++ = *str2++));
    return head;
};
2: strcpy

首先看一下函数原型

char	*strcpy(char *__dst, const char *__src);

注意内存重叠问题:

char* my_strcpy(char* des, const char* src){
    assert(des);
    assert(src);
    int src_len = 0;
    const char* cur = src;
    char* res = des;
    while (*cur++ != '\0') {
        src_len++;
    }
    //由于要复制最后的 \0 因此循环次数是字符串长度+1
    if (des <= src || des >= src + src_len) {
        while (src_len-- >= 0) {
            *des++ = *src++;
        }
    }else{
    	//这里由于有最后的 \0 所以不需要减1
        des += src_len;
        src += src_len;
        while (src_len-->= 0) {
            *des-- = *src--;
        }
    }
    return res;
}
3: strncpy

注意最后 \0 封口。

char* my_strnpy(char* des, const char* src, size_t len){
    assert(des);
    assert(src);
    char* res = des;
    if (des <= src || des >= src + len) {
        while (len--) {
            *des++ = *src++;
        }
        *(++des) = '\0';
    }else{
        des += len;
        src += len - 1;
        *des-- = '\0';
        while (len--) {
            *des-- = *src--;
        }
    }
    return res;
}
4: memset

函数原型

void	*memset(void *__b, int __c, size_t __len);

这里要注意的是:
虽然第二个字节用的是int类型,但实际上,只有其低8位有用,真正的memset会截取低8位,然后扩展为32位,比如0x12345678会截取然后扩展为 0x78787878,然后使用rep stosd指令填充,这样比8位8位填充要快,但我们自己实现的时候,不考虑这一点。
自己实现的版本如下:

void* my_memset(void* src, int val, size_t len){
    assert(src);
    char true_val = val;
    char* cur = (char*)src;
    while (len--) {
        *cur++ = true_val;
    }
    return src;
}
5: memcpy

这个应该是最爱考的了,主要注意内存重叠的问题。

void* my_memcpy(void* des, const void* src, size_t len){
    assert(des);
    assert(src);
    void* head = des;
    char* des1 = (char*)des;
    char* src1 = (char*)src;
    if (des1 <= src1 || des1 >= src1+len) {
        while (len--) {
            *des1++ = *src1++;
        }
    }else{
        src1 += len-1;
        des1 += len-1;
        while (len--) {
            *des1-- = *src1--;
        }
    }
    return head;
}

void*

作为万能指针,可以用于接收任何类型的指针,但由于它没有具体类型,因此不能做数学运算,因为不知道加1是移动几个字节。因此使用的时候要转化为 char* 类型,每次加1移动一个字节。

6: itoa

linux平台没有itoa函数,所以直接就叫这个名字了。
另外,感觉这种方式实现效率有点低,不知道还有没有更好的实现方式,比如位运算什么的。

char* char_reverse(char* str, size_t len){
    char* begin = str;
    char* end = str+len-1;
    while (begin <= end) {
        swap(*begin++, *end--);
    }
    return str;
}

char* itoa(int val,char* des){
    assert(des);
    char* cur = des;
    size_t len = 0;
    bool is_neg = false;
    if (val < 0) {
        is_neg = true;
        val = -val;
    }
    while (val) {
        *cur++ = '0' + val % 10;
        len++;
        val = val / 10;
    }
    if (is_neg) {
        *cur++ = '-';
        len++;
    }
    *cur = '\0';
    char_reverse(des, len);
    return des;
};
atio

先看函数原型

int	atoi(const char *);

实现

int my_atoi(const char* input){
    int res = 0;
    int base = 1;
    int len = 0;
    bool is_neg = false;
    const char* cur = input;
    if (input[0] < '0' || input[0] > '9') {
        if (input[0] == '-') {
            is_neg = true;
            cur++;
        }else{
            assert(-1);
        }
    }
    while (*cur) {
        cur++;
        len++;
    }
    cur--;
    while (len--) {
        if (*cur < 0 || *cur > 9) {
            assert(-1);
        }
        res += (int)(*cur-- - '0') * base;
        base *= 10;
    }
    if (is_neg) {
        res = -res;
    }
    return res;
}

你可能感兴趣的:(算法和刷题)