0%

面试知识点详细解读之memcpy、memset、strcpy、strcmp、strlen、string的实现

  1. memcpy
  2. memset
  3. strcpy
  4. strcmp
  5. strlen
  6. 自己动手实现一个string

memcpymemset实现

memcpy实现
  • 此实现并没有考虑dstsrc的内存重叠问题
1
2
3
4
5
6
7
8
9
10
11
12
13
// 使用 const 修饰 src
void* memcpy(void* dst, const void* src, size_t n) {
// 验证 dst 和 src 的合法性
assert(dst != NULL);
assert(src != NULL);
void* ret = dst;
while(n--) {
*(char*)dst = *(char*)src;
dst = (char*)dst + 1;
src = (char*)src + 1;
}
return ret;
}
memset实现
1
2
3
4
5
6
7
8
9
void* memset(void* dst, int ch, size_t n) {
assert(dst != NULL);
void* ret = dst;
while(n--) {
*(char*)dst = (char)ch;
dst = (char*)dst + 1;
}
return ret; // 返回原 dst 指针
}

strcpystrcmpstrlen实现

strcpy实现
  • 此实现并没有考虑dstsrc的内存重叠问题
1
2
3
4
5
6
7
8
9
// 使用 const 修饰 src
char* strcpy(char* dst, const char* src) {
// 验证 dst 和 src 的合法性
assert(dst != NULL);
assert(src != NULL);
char* ret = dst;
while((*dst++ = *src++) != '\0');
return ret; // 返回原 dst 指针
}
strcmp实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 注意将两个指针都用 const 修饰
int strcmp(const char* rhs, const char* lhs) {
// 判空测试
assert(rhs != NULL);
assert(lhs != NULL);

// 注意这里必须是 unsigned char
// 表示的范围为 0 ~ 255
// 如果是 char 的话, 范围是 -128 ~ 127, 这个范围用来比较字符串是不对的
unsigned char c1, c2;
while(1) {
c1 = *rhs++;
c2 = *lhs++;
if(c1 != c2) {
return c1 < c2 ? -1 : 1;
}
if(c1 == 0) {
break;
}
}
return 0;
}
strlen实现
1
2
3
4
5
6
7
8
size_t strlen(const char* str) {
if(str == NULL) {
return 0;
}
const char* pc = str;
while(*pc++ != '\0');
return pc - str - 1;
}

关于标准库中的实现:通过减少数据从内存存取到寄存器的次数来提高效率,使用的手段是先字节对齐,然后每次读取一个4/8字节的多字节数据,对多字节数据遍历是否存在\0

自己动手实现一个string

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include <iostream>
#include <utility>
#include <cstring>

class String {
private:
char *_data;
size_t _size;
void init(const char *c_str) {
_data = new char[_size + 1];
strcpy(_data, c_str);
}

public:
String() : _data(nullptr), _size(0) {}

String(const char *c_str) : _size(strlen(c_str)) {
if(c_str) {
init(c_str);
}
else {
_data = nullptr;
}
}

String(const String &str) : _size(str._size) {
if(str._data) {
init(str._data);
}
else {
_data = nullptr;
}
}

String(String &&str) noexcept : _data(str._data), _size(str._size) {
str._data = nullptr;
str._size = 0;
}

~String() {
if(_data) {
delete _data;
}
}

String &operator=(const char *c_str) {
// 使用 copy and swap 技术, 可以处理自我赋值情况
String temp(c_str);
swap(temp);
return *this;
}

String &operator=(const String &str) {
return *this = str._data;
}

String &operator=(String &&str) noexcept {
// 检测自我赋值情况
if(this == &str) {
return *this;
}
if(_data) {
delete _data;
}
_data = nullptr;
_size = 0;
swap(str);

return *this;
}

size_t size() const {
return _size;
}

char *c_str() {
return _data;
}

const char *c_str() const {
return _data;
}

void swap(String &str) {
using std::swap;
swap(_data, str._data);
swap(_size, str._size);
}

bool operator==(const char *c_str) {
if(strcmp(_data, c_str) == 0) {
return true;
}
return false;
}

bool operator==(const String &str) {
return *this == str._data;
}

char &operator[](size_t i) {
return _data[i];
}

const char &operator[](size_t i) const {
return _data[i];
}
};

std::ostream &operator<<(std::ostream &os, const String str) {
return os << str.c_str();
}