基础知识总结-常用字符串函数实现

strcpy

功 能: 将参数src字符串拷贝至参数dest所指的地址

用 法: char *strcpy(char *dest, const char *src)

返回值: 返回参数dest的字符串起始地址

说 明: 如果参数dest所指的内存空间不够大,可能会造成缓冲溢出的错误情况,在编写程序时需特别留意,或者用strncpy()来取代

1
2
3
4
5
6
7
8
char *strcpy(char *dest, const char *src)
{
assert(dest != NULL && src != NULL);
char *result = dest;
while ((*dest++ = *src++) != '\0')
;
return result;
}

strncpy

功 能: 将字符串src前n个字符拷贝到字符串dest

用 法: char *strncpy(char *dest, const char *src, size_t n)

返回值: 返回参数dest的字符串起始地址

说 明: 不像strcpy(),strncpy()不会向dest追加结束标记’\0’;src和dest所指的内存区域不能重叠,且dest必须有足够的空间放置n个字符。

1
2
3
4
5
6
7
8
char *strncpy(char *dest, const char *src, size_t n)
{
assert(dest != NULL && src != NULL);
char *result = dest;
while (n-- && (*dest++ = *src++) != '\0')
;
return result;
}

strcat

功 能: 字符串拼接函数

用 法: char *strcat(char *dest, const char *src)

返回值: 返回dest字符串起始地址

说 明: strcat() 会将参数src字符串复制到参数dest所指的字符串尾部;dest最后的结束字符’\0’会被覆盖掉,并在连接后的字符串的尾部再增加一个’\0’;dest与src所指的内存空间不能重叠,且dest要有足够的空间来容纳要复制的字符串;

1
2
3
4
5
6
7
8
9
10
char *strcat(char *dest, const char *src)
{
assert(dest != NULL && src != NULL);
char *result = dest;
while (*dest != '\0')
++dest;
while ((*dest++ = *src++) != '\0')
;
return result;
}

strncat

功 能: 将n个字符追加到字符串的结尾

用 法: char *strncat(char *dest, const char *src, size_t n)

返回值: 返回dest字符串起始地址

说 明: strncat()将会从字符串src的开头拷贝n个字符到dest字符串尾部,dest要有足够的空间来容纳要拷贝的字符串;如果n大于字符串src的长度,那么仅将src全部追加到dest的尾部;strncat()会将dest字符串最后的’\0’覆盖掉,字符追加完成后,再追加’\0’;

1
2
3
4
5
6
7
8
9
10
11
char *strncat(char *dest, const char *src, size_t n)
{
assert(dest != NULL && src != NULL);
char *result = dest;
while (*dest != '\0')
++dest;
while (n-- && (*dest++ = *src++) != '\0')
;
*dest = '\0';
return result;
}

strcmp

功 能: 字符串比较

用 法: int strcmp(const char *s1, const char *s2)

返回值: 根据ASCII码比较,若参数s1和s2字符串相同则返回0,s1若大于s2则返回大于0的值,s1若小于s2则返回小于0的值

说 明: 它是区分大小写比较的,如果希望不区分大小写进行字符串比较,可以使用stricmp函数

1
2
3
4
5
6
7
8
9
10
int strcmp(const char *s1, const char *s2)
{
assert(s1 != NULL && s2 != NULL);
while (s1 && s2 && (s1 == s2))
{
++s1;
++s2;
}
return (*s1 - *s2);
}

strlen

功 能: 计算指定的字符串s的长度,不包括结束字符’\0’

用 法: size_t strlen(const char *s)

返回值: 返回字符串s的字符数

说 明: strlen() 函数计算的是字符串的实际长度,遇到第一个’\0’结束;如果你只定义没有给它赋初值,这个结果是不定的,它会从首地址一直找下去,直到遇到’\0’停止;sizeof返回的是变量声明后所占的内存数,不是实际长度,此外sizeof不是函数,仅仅是一个操作符,strlen()是函数;

1
2
3
4
5
6
7
8
size_t strlen(const char *s)
{
assert(s != NULL);
size_t len = 0;
while (*s++ != '\0')
++len;
return len;
}

strstr

功 能: 检索子串在字符串中首次出现的位置

用 法: char *strstr( char *str, char * substr )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
char *strstr(char *str, char *substr)
{
assert(str != NULL && substr != NULL);
char *s = str;
char *t = substr;
for (; *str != '\0'; str++)
{
for (s = str, t = substr; *t != '\0' && *s == *t; ++s, ++t)
;
if (*t == '\0')
return (char *)str;
}
return NULL;
}

strpbrk

功 能: 返回两个字符串中首个相同字符的位置

用 法: char *strpbrk(const char *s1, const char *s2)

返回值: 如果s1、s2含有相同的字符,那么返回指向s1中第一个相同字符的指针,否则返回NULL

说 明: strpbrk()不会对结束符’\0’进行检索

1
2
3
4
5
6
7
8
9
10
11
12
char *strpbrk(const char *s1, const char *s2)
{
assert(s1 != NULL && s2 != NULL);
const char *s, *t;
for (s = s1; *s != '\0'; s++)
for (t = s2; *t != '\0'; t++)
{
if (*s == *t)
return (char *)s;
}
return NULL;
}

strtok

功 能 : 根据分界符将字符串分割成一个个片段

用 法 : char *strtok(char *s, const char *delim)

返回值 : 返回下一个分割后的字符串指针,如果已无从分割则返回NULL

说 明 : 当strtok()在参数s的字符串中发现到参数delim的分割字符时则会将该字符改为’\0’字符;在第一次调用时,strtok()必须赋予参数s字符串,往后的调用则将参数s设置成NULL;

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
char *strtok_r(char *s, const char *delim, char **save_ptr)
{
char *token;
if (s == NULL)
s = *save_ptr;
/* Scan leading delimiters. */
s += strspn(s, delim);
if (*s == '\0')
return NULL;
/* Find the end of the token. */
token = s;
s = strpbrk(token, delim);
if (s == NULL)
/* This token finishes the string. */
*save_ptr = strchr(token, '\0');
else
{
/* Terminate the token and make *SAVE_PTR point past it. */
*s = '\0';
*save_ptr = s + 1;
}
return token;
}

char *strtok(char *s, const char *delim)
{
static char *last;
return strtok_r(s, delim, &last);
}

memcpy

实现memcpy()函数及过程总结

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void *my_memcpy_byte(void *dst, const void *src, int n)
{
if (dst == NULL || src == NULL || n <= 0)
return NULL;

char *pdst = (char *)dst;
char *psrc = (char *)src;

if (pdst > psrc && pdst < psrc + n)
{
pdst = pdst + n - 1;
psrc = psrc + n - 1;
while (n--)
*pdst-- = *psrc--;
}
else
{
while (n--)
*pdst++ = *psrc++;
}
return dst;
}

memmove

仰视源码,实现memmove

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
void *memmove(void *dst, const void *src, size_t count)
{
assert(NULL != src && NULL != dst);
char *tmpdst = (char *)dst;
char *tmpsrc = (char *)src;

if (tmpdst <= tmpsrc || tmpdst >= tmpsrc + count)
{
while (count--)
{
*tmpdst++ = *tmpsrc++;
}
}
else
{
tmpdst = tmpdst + count - 1;
tmpsrc = tmpsrc + count - 1;
while (count--)
{
*tmpdst-- = *tmpsrc--;
}
}

return dst;
}

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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <iostream>
#include <cstring>
using namespace std;

class String
{
public:
// 默认构造函数
String(const char *str = NULL);
// 复制构造函数
String(const String &str);
// 析构函数
~String();
// 字符串连接
String operator+(const String &str);
// 字符串赋值
String &operator=(const String &str);
// 字符串赋值
String &operator=(const char *str);
// 判断是否字符串相等
bool operator==(const String &str);
// 获取字符串长度
int length();
// 重载输出
friend ostream &operator<<(ostream &o, const String &str);

private:
char *data;
int size;
};
// 构造函数
String::String(const char *str)
{
if (str == NULL)
{
data = new char[1];
data[0] = '\0';
size = 0;
} //if
else
{
size = strlen(str);
data = new char[size + 1];
strcpy(data, str);
} //else
}
// 复制构造函数
String::String(const String &str)
{
size = str.size;
data = new char[size + 1];
strcpy(data, str.data);
}
// 析构函数
String::~String()
{
delete[] data;
}
// 字符串连接
String String::operator+(const String &str)
{
String newStr;
//释放原有空间
delete[] newStr.data;
newStr.size = size + str.size;
newStr.data = new char[newStr.size + 1];
strcpy(newStr.data, data);
strcpy(newStr.data + size, str.data);
return newStr;
}
// 字符串赋值
String &String::operator=(const String &str)
{
if (data == str.data)
{
return *this;
} //if
delete[] data;
size = str.size;
data = new char[size + 1];
strcpy(data, str.data);
return *this;
}
// 字符串赋值
String &String::operator=(const char *str)
{
if (data == str)
{
return *this;
} //if
delete[] data;
size = strlen(str);
data = new char[size + 1];
strcpy(data, str);
return *this;
}
// 判断是否字符串相等
bool String::operator==(const String &str)
{
return strcmp(data, str.data) == 0;
}
// 获取字符串长度
int String::length()
{
return size;
}
// 重载输出
ostream &operator<<(ostream &o, const String &str)
{
o << str.data;
return o;
}

int main()
{
String str1("hello ");
String str2 = "world";
String str3 = str1 + str2;
cout << "str1->" << str1 << " size->" << str1.length() << endl;
cout << "str2->" << str2 << " size->" << str2.length() << endl;
cout << "str3->" << str3 << " size->" << str3.length() << endl;

String str4("helloworld");
if (str3 == str4)
{
cout << str3 << " 和 " << str4 << " 是一样的" << endl;
} //if
else
{
cout << str3 << " 和 " << str4 << " 是不一样的" << endl;
}

return 0;
}

// str1->hello size->6
// str2->world size->5
// str3->hello world size->11
// hello world 和 helloworld 是不一样的
您的支持将鼓励我继续创作!
0%