函数原型:
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;
};
首先看一下函数原型
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;
}
注意最后 \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;
}
函数原型
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;
}
这个应该是最爱考的了,主要注意内存重叠的问题。
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移动一个字节。
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;
};
先看函数原型
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;
}