From 847ec0fb156a9352051c2dd43ae62878f81ae65c Mon Sep 17 00:00:00 2001 From: lensferno Date: Thu, 7 Apr 2022 15:24:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E9=AA=8C3=EF=BC=9A=E4=BD=9C=E4=B8=9A?= =?UTF-8?q?=E9=AD=94=E6=94=B9=E7=89=88=20=E7=9B=AE=E5=89=8D=E9=97=AE?= =?UTF-8?q?=E9=A2=98=EF=BC=9A=E6=9F=90=E5=A4=84=E5=AD=98=E5=9C=A8data?= =?UTF-8?q?=E8=B6=8A=E7=95=8C=E9=97=AE=E9=A2=98=EF=BC=8Cdelete[]=E6=97=B6?= =?UTF-8?q?=E4=BC=9A=E5=8F=91=E7=94=9FHEAP=20CORRUPTION=20DETECTED?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- work20220407/CMakeLists.txt | 6 + work20220407/main.cpp | 26 ++++ work20220407/string/String.cpp | 232 +++++++++++++++++++++++++++++++++ work20220407/string/String.h | 71 ++++++++++ 4 files changed, 335 insertions(+) create mode 100644 work20220407/CMakeLists.txt create mode 100644 work20220407/main.cpp create mode 100644 work20220407/string/String.cpp create mode 100644 work20220407/string/String.h diff --git a/work20220407/CMakeLists.txt b/work20220407/CMakeLists.txt new file mode 100644 index 0000000..8324f3e --- /dev/null +++ b/work20220407/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.21) +project(work20220407) + +set(CMAKE_CXX_STANDARD 14) + +add_executable(work20220407 main.cpp string/String.cpp string/String.h) diff --git a/work20220407/main.cpp b/work20220407/main.cpp new file mode 100644 index 0000000..6c593d0 --- /dev/null +++ b/work20220407/main.cpp @@ -0,0 +1,26 @@ +#include +#include "string/String.h" + + +using namespace std; + +int main() { + String s1("Help!"),s2("Good!"),s3(s2),s4,s5; + cout<<"s1="<length = length; +} + +String::~String() { + delete[] data; + data = nullptr; +} + +String::String(const String &source) : String(source.data, source.length) {} + +/** + * 重载等号,其实现抽象为equals函数 + * @param source + * @return + */ +bool String::operator==(const String &source) const { + return equals(source.data, source.length); +} + +bool String::operator==(const char *source) const { + return equals(source, (int) strlen(source)); +} + +/** + * 借鉴了Java中String类的equal()方法的实现思路。 + * 首先判断data是否为nullptr,同为null则true,否则就是false + * 再比较两字符串长度,如果长度不一样不用说,直接返回false; + * 相同的话再比较两字符串数据指针指向地址是否一样,一样就代表指向的是同一块内存,直接返回true + * 两者都不同才进行逐字比较 + */ +bool String::equals(const char *source, int sourceLength) const { + // 首先判断两CString对象data成员是否为空指针 + if (source == nullptr || this->data == nullptr) { + return source == nullptr && this->data == nullptr; + } + + // 字符串长度不等,字符串肯定是不等 + if (length != sourceLength) { + return false; + } else { + // 长度相等且data指向相同肯定等 + if (source == this->data) { + return true; + } + } + + // 以上情况都不符合时才进行逐字比较 + // 能执行到此处两者长度肯定相等,因此访问数组不会越界 + for (int i = 0; i < length; ++i) { + if (data[i] != source[i]) { + return false; + } + } + return true; +} + +String &String::operator=(const String &source) { + if (this == &source) { + return *this; + } + + copyData(source.data, source.length); + + return *this; +} + +String &String::operator=(const char *source) { + copyData(source, (int) strlen(source)); + + return *this; +} + +void String::copyData(const char *source, int sourceLength) { + // 等号右侧空指针的话直接data赋为空指针 + if (source == nullptr) { + delete[] data; + this->data = nullptr; + length = 0; + allocSize = 0; + } + + // 如果源字符串长度超过了本对象已分配的字符数组大小则重新分配长度合适的字符数组 + if (allocSize < sourceLength) { + allocSize = sourceLength + 1; + + delete[] data; + data = new char[allocSize]; + } + + strcpy(data, source); + length = sourceLength; +} + +String &String::operator+=(const String &source) { + addString(source.data, source.length); + + return *this; +} + +String &String::operator+=(const char *source) { + addString(source, (int) strlen(source)); + + return *this; +} + +void String::addString(const char *source, int sourceLength) { + // nullptr不做处理 + if (source == nullptr) { + return; + } + + // 本对象nullptr的话就直接新分配 + if (data == nullptr) { + allocSize = sourceLength + 2 + 1; + this->data = new char[allocSize](); + + length = sourceLength; + } else { + length = (int) strlen(data); + } + + // 如果拼接后字符长度超过已分配的内存大小,则重新分配data内存大小 + if (allocSize < (length + sourceLength + 2)) { + // 保存拼接前的原数据,以便重新分配足够的内存 + char *old = new char[length + 1](); + strcpy(old, data); + + // 重新分配内存,防止拼接后溢出,2为两个横杠大小 + length += sourceLength + 2; + allocSize = length + 1; + + delete[] data; + this->data = new char[allocSize](); + + strcpy(data, old); + } + + strcat(data, source); +} + +/** + * 按照字典顺序对比 + */ +bool String::operator>(const String &compareString) const { + // 首先判断两CString对象data成员是否为空指针,空直接返回false + if (compareString.data == nullptr || this->data == nullptr) { + return false; + } + + // 两对象data成员首指向相同则对比谁长 + if (compareString.data == this->data) { + return length > compareString.length; + } + + // 以上情况都不符合时才进行比较 + return strcoll(this->data, compareString.data) > 0; +} + +std::ostream &operator<<(std::ostream &outputStream, const String &source) { + return outputStream << source.data; +} + +std::istream &operator>>(std::istream &inputStream, String &source) { + // 使用istream.get(char*, int)可以限制读入的长度,防止输入超长的字符串导致溢出,但是空格也会被读入 + // 手动分割太麻烦,因此只好先用这种方法了 + inputStream >> source.data; + source.length = (int) strlen(source.data); + + return inputStream; +} + +char String::operator[](int i) { + return (i < length && i >= 0) ? data[i] : '\0'; +} + +/** + * 加号运算重载,注意,每次加号运算都会产生一个新的对象 + */ +String &String::operator+(const char *source) { + int sourceLength = (int) strlen(source); + + String target(this->length + sourceLength + 1); + target = this->data; + target += source; + + return target; +} + +String &String::operator+(const String &source) { + String target(this->length + source.length); + target = this->data; + target += source; + + return target; +} + +int String::Length() const { + return length; +} diff --git a/work20220407/string/String.h b/work20220407/string/String.h new file mode 100644 index 0000000..4bd7ed4 --- /dev/null +++ b/work20220407/string/String.h @@ -0,0 +1,71 @@ +// +// Created by lenfrex on 2022/4/4. +// + +#ifndef WORK20220401_STRING_H +#define WORK20220401_STRING_H + +#include +#include +#include "utility" + +using namespace std::rel_ops; + +class String { +private: + // 字符数组做字符串 + char *data = nullptr; + + // 字符串实际长度 + int length = 0; + + // 已分配的字符数量 + int allocSize = 0; + + void copyData(const char *source, int sourceLength); + + bool equals(const char *source, int sourceLength) const; + + void addString(const char *source, int sourceLength); +public: + explicit String(int size); + + String(const char *data, int length); + + explicit String(const char *source); + + String(const String &source); + + String(); + + ~String(); + + bool operator==(const String &source) const; + + bool operator==(const char *source) const; + + bool operator>(const String &compareString) const; + + String &operator+=(const String &source); + + String &operator+=(const char *source); + + String &operator=(const String &source); + + String &operator=(const char *source); + + String &operator+(const char *source); + + String &operator+(const String &source); + + friend std::ostream &operator<<(std::ostream &outputStream, const String &source); + + friend std::istream &operator>>(std::istream &outputStream, String &source); + + char operator[](int i); + + int Length() const; + +}; + +#endif //WORK20220401_STRING_H \ No newline at end of file