C++字符串与C语言中的字符串处理函数
一.C++中的字符串类
下面是简单的一种实现:
#ifndef STRING_H_INCLUDED
#define STRING_H_INCLUDED
class String
{
public:
String (const char* cstr = 0);
String (const String&);
String& operator = (const String&);
~String();
char* get_c_str() const { return m_data; }
private:
char* m_data;
};
#include <cstring>
inline
String::String (const char* cstr)
{
if (cstr) {
m_data = new char[strlen(cstr) + 1];
strcpy (m_data, cstr);
}
else {
m_data = new char[1];
*m_data = '\0';
}
}
inline
String::String (const String& str)
{
m_data = new char[strlen(str.m_data) + 1];
strcpy (m_data, str.m_data);
}
inline String&
String::operator = (const String& str)
{
if(this == &str)
return *this;
delete [] m_data;
m_data = new char[strlen(str.m_data) + 1];
strcpy (m_data, str.m_data);
return *this;
}
inline
String::~String()
{
delete [] m_data;
}
#include <iostream>
using namespace std;
ostream& operator << (ostream& os, const String& str)
{
os << str.get_c_str();
return os;
}
#endif // STRING_H_INCLUDED
特别注意:string类是由一系列字符组成,但是必须以\0
结尾**。
依次来分析这个类的实现:
- 成员变量就是一个char*
。
- 构造函数,传入const char*
,如果传入的是空指针,特别注意开辟一个新的内存来放置\0
;如果非空,先用new开辟一块内存,内存大小要等于strlen()+1
,1也是用来放置\0
的,最后使用strcpy()
进行拷贝,下一节我们也探讨了这个函数的实现。
- 拷贝构造函数:和构造函数类似。
- 拷贝赋值运算符:要注意证同测试,先释放原先的内存,再声明一块内存,最后使用strcpy()
进行拷贝。
- 析构函数:比较显然。
- 为了保持一致,重载了运算符<<
。
二.C语言中的常见字符串处理函数以及内存拷贝函数
首先头文件必须包含以下
#include <assert.h> //for assert
#include <cstddef> //for size_t
1. 计算字符串的长度:
这个函数比较简单,只要遇到\0
退出即可
//计算字符串的长度:strlen
std::size_t myStrlen(const char* str){
assert(str != NULL);
std::size_t length = 0;
while(*str++ != '\0')
++length;
return length;
}
2. 字符串的拷贝:
拷贝源(第二个参数)是const char*
,注意拷贝目的地(第一个参数)需要使用临时变量保存一下,最后只需要循环执行(*dest++ = *src++) != '\0'
即。
//实现字符串的拷贝:strcpy
char* myStrcpy(char* dest, const char* src){
//dest: 指向要写入的字符数组的指针
//src: 指向复制来源的空终止字节字符串的指针
//若dest数组不够大则行为未定义;若字符串重叠则行为未定义。
assert(dest != NULL && src != NULL);
char *temp = dest;
while((*dest++ = *src++) != '\0');
return temp;
}
Strncpy
则将src前count个字符拷贝给dest,如果Count大于src的长度(strlen),则剩余部分补\0
。
char* myStrncpy(char* dest, const char* src, std::size_t count){
assert(dest != NULL && src != NULL);
char *temp = dest;
int offset = 0;
if(myStrlen(src) < count){
offset = count - myStrlen(src);
count = myStrlen(src);
}
while(count--)
*dest++ = *src++;
while(offset--)
*dest++ = '\0';
return temp;
}
3.字符串的拼接:
先跑到dest的末尾\0
,再依次拷贝src。
//实现字符串的拼接:strcat
char *myStrcat( char *dest, const char *src ){
//dest 指向要后附到的空终止字节字符串的指针
//src 指向作为复制来源的空终止字节字符串的指针
//若字符串重叠则行为未定义。
assert(dest != NULL && src != NULL);
char* temp = dest;
while(*dest)
++dest;
while(*dest++ = *src++);
return temp;
}
myStrncat
:将则将src前count个字符拼接到dest后面,方法类似,注意最后要补\0
。
char *myStrncat( char *dest, const char *src, std::size_t count ){
assert(dest != NULL && src != NULL);
char* temp = dest;
while(*dest)
++dest;
while(count-- && (*dest++ = *src++));
*dest = '\0';
return temp;
}
4.字符串的比较:
注意返回值:*lhs - *rhs
,最后一个不相同的字符的ASCII之差。
//实现字符串的比较:strcmp
int myStrcmp(const char* lhs, const char* rhs){
//lhs, rhs 指向待比较的空终止字节字符串的指针
assert(lhs != NULL && rhs != NULL);
while(*lhs == *rhs){
if(*lhs == '\0')
return 0;
++lhs;
++rhs;
}
return *lhs - *rhs;
}
5.memset()函数:
//将dest前面count个字符置为字符c.返回dest的值.
void *myMemset(void *dest, int c, size_t count) {
assert(dest != NULL);
void *s = dest;
while (count--) {
*(char *)s = (char) c;
s = (char *)s + 1;
}
return dest;
}
6.memcpy()函数:
注意,如果src和dest重叠的情况,则会出错
//从src复制count字节的字符到dest. 与memmove功能一样, 只是不能处理src和dest出现重叠.返回dest的值
void *myMemcpy(void *dest, const void *src, size_t count) {
assert(dest != NULL && src != NULL);
void *s = dest;
while (count--) {
*(char *)s = *(char *)src;
s = (char *)s + 1;
src = (const char *)src + 1;
}
return dest;
}
7.memmove()函数:
可以正确处理src和dest重叠的情况
//从src复制count字节的字符到dest. 如果src和dest出现重叠, 函数会自动处理.返回dest的值.
void *myMemmove(void *dest, const void *src, size_t count) {
assert(dest != NULL && src != NULL);
void *s = dest;
if (s <= src || (char *)s >= (char *)src + count) {
//未重叠的部分,和memcpy一样的行为
while (count--) {
*(char *)s = *(char *)src;
s = (char *)s + 1;
src = (const char *)src + 1;
}
}
else {
//内存出现重叠之后,从后往前copy;
s = (char *)s + count - 1;
src = (char *)src + count - 1;
while (count--) {
*(char *)s = *(char *)src;
s = (char *)s - 1;
src = (char *)src - 1;
}
}
return dest;
}