- 牛刀小试
917. 仅仅反转字母 - 力扣(LeetCode)
class Solution { public: bool isLetter(char ch) { if(ch >= 'a' && ch <= 'z') return true; if(ch >= 'A' && ch <= 'Z') return true; return false; } string reverseOnlyLetters(string S) { if(S.empty()) return S; size_t begin = 0, end = S.size()-1; while(begin < end) { while(begin < end && !isLetter(S[begin])) ++begin; while(begin < end && !isLetter(S[end])) --end; swap(S[begin], S[end]); ++begin; --end; } return S; } };387. 字符串中的第一个唯一字符 - 力扣(LeetCode)
class Solution { public: int firstUniqChar(string s) { // 统计每个字符出现的次数 int count[256] = {0}; int size = s.size(); for(int i = 0; i < size; ++i) count[s[i]] += 1; // 按照字符次序从前往后找只出现一次的字符 for(int i = 0; i < size; ++i) if(1 == count[s[i]]) return i; return -1; } };字符串最后一个单词的长度_牛客题霸_牛客网
#include<iostream> #include<string> using namespace std; int main() { string line; // 不要使用cin>>line,因为会它遇到空格就结束了 // while(cin>>line) while(getline(cin, line)) { size_t pos = line.rfind(' '); cout<<line.size()-pos-1<<endl; } return 0; }125. 验证回文串 - 力扣(LeetCode)
class Solution { public: bool isLetterOrNumber(char ch) { return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); } bool isPalindrome(string s) { // 先小写字母转换成大写,再进行判断 for(auto& ch : s) { if(ch >= 'a' && ch <= 'z') ch -= 32; } int begin = 0, end = s.size()-1; while(begin < end) { while(begin < end && !isLetterOrNumber(s[begin])) ++begin; while(begin < end && !isLetterOrNumber(s[end])) --end; if(s[begin] != s[end]) { return false; } else { ++begin; --end; } } return true; } };415. 字符串相加 - 力扣(LeetCode)
class Solution { public: string addstrings(string num1, string num2) { // 从后往前相加,相加的结果到字符串可以使用insert头插 // 或者+=尾插以后再reverse过来 int end1 = num1.size()-1; int end2 = num2.size()-1; int value1 = 0, value2 = 0, next = 0; string addret; while(end1 >= 0 || end2 >= 0) { if(end1 >= 0) value1 = num1[end1--]-'0'; else value1 = 0; if(end2 >= 0) value2 = num2[end2--]-'0'; else value2 = 0; int valueret = value1 + value2 + next; if(valueret > 9) { next = 1; valueret -= 10; } else { next = 0; } //addret.insert(addret.begin(), valueret+'0'); addret += (valueret+'0'); } if(next == 1) { //addret.insert(addret.begin(), '1'); addret += '1'; } reverse(addret.begin(), addret.end()); return addret; } };手撕String
string.h
#pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include<assert.h> #include<iostream> using namespace std; namespace bit { class string { public: typedef char* iterator; typedef const char* const_iterator; iterator begin() { return _str; } iterator end() { return _str + _size; } const_iterator begin() const { return _str; } const_iterator end() const { return _str + _size; } const char* c_str() const { return _str; } size_t size() const { return _size; } string(const char* str = ""); string(const string& s); string& operator=(string s); ~string(); const char& operator[](size_t pos) const; char& operator[](size_t pos); void reserve(size_t n); void push_back(char ch); void append(const char* str); string& operator+=(char ch); string& operator+=(const char* str); void insert(size_t pos, char ch); void insert(size_t pos, const char* str); void erase(size_t pos, size_t len = npos); void swap(string& s); size_t find(char ch, size_t pos = 0); size_t find(const char* str, size_t pos = 0); string substr(size_t pos = 0, size_t len = npos); void clear(); private: size_t _capacity = 0; size_t _size = 0; char* _str = nullptr; const static size_t npos = -1; }; istream& operator>>(istream& in, string& s); ostream& operator<<(ostream& out, const string& s); }string.cpp
#include"string.h" //#include"string.h" //#ifndef __STRING_H__ //#define __STRING_H__ ////... //#endif // !__STRING_H__ // //#ifndef __STRING_H__ //#define __STRING_H__ ////... //#endif // !__STRING_H__ namespace bit { string::string(const char* str) { _size = strlen(str); _capacity = _size; _str = new char[_capacity + 1]; strcpy(_str, str); } /* 传统写法 string::string(const string& s) { _str = new char[s.capacity + 1]; strcpy(_str, s._str); _size = s._size; _capacity = s._capacity; } */ //现代写法 string::string(const string& s) { string tmp(s._str); swap(tmp); } /* string& operator=(const string& s) { if (this != &s) { char* tmp = new char[s._capacity + 1]; strcpy(tmp, s._str); delete[] _str; _str = tmp; _size = s._size; _capacity = s._capacity; } return *this; } */ string& string::operator=(string s) { swap(s); return *this; } string::~string() { delete[] _str; _str = nullptr; _size = 0; _capacity = 0; } const char& string::operator[](size_t pos) const { assert(pos <= _size); return _str[pos]; } char& string::operator[](size_t pos) { assert(pos <= _size); return _str[pos]; } void string::reserve(size_t n) { if (n > _capacity) { char* tmp = new char[n + 1]; strcpy(tmp, _str); delete[] _str; _str = tmp; _capacity = n; } } void string::push_back(char ch) { if (_size == _capacity) { size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2; reserve(newCapacity); } _str[_size] = ch; _size++; _str[_size] = '\0'; } void string::append(const char* str) { size_t len = strlen(str); if (_size + len > _capacity) { reserve(_size + len); } strcpy(_str + _size, str); _size += len; } string& string::operator+=(char ch) { push_back(ch); return *this; } string& string::operator+=(const char* str) { append(str); return *this; } void string::insert(size_t pos, char ch) { assert(pos <= _size); if (_size == _capacity) { size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2; reserve(newCapacity); } /*int end = _size; while (end >= (int)pos) { _str[end + 1] = _str[end]; --end; }*/ size_t end = _size + 1; while (end > pos) { _str[end] = _str[end - 1]; --end; } _str[pos] = ch; _size++; } void string::insert(size_t pos, const char* str) { assert(pos <= _size); size_t len = strlen(str); if (_size + len > _capacity) { reserve(_size + len); } int end = _size; while (end >= (int)pos) { _str[end + len] = _str[end]; --end; } strncpy(_str + pos, str, len); _size += len; } void string::erase(size_t pos, size_t len) { assert(pos < _size); if (len == npos || pos + len >= _size) { _str[pos] = '\0'; _size = pos; } else { strcpy(_str + pos, _str + pos + len); _size -= len; } } void string::swap(string& s) { std::swap(_str, s._str); std::swap(_size, s._size); std::swap(_capacity, s._capacity); } size_t string::find(char ch, size_t pos) { for (size_t i = pos; i < _size; i++) { if (_str[i] == ch) { return i; } } return npos; } size_t string::find(const char* str, size_t pos) { const char* ptr = strstr(_str + pos, str); if (ptr == nullptr) { return npos; } else { return ptr - _str; } } string string::substr(size_t pos, size_t len) { assert(pos < _size); size_t end = pos + len; if (len == npos || pos + len >= _size) { end = _size; } string str; str.reserve(end - pos); for (size_t i = pos; i < end; i++) { str += _str[i]; } return str; } void string::clear() { _size = 0; _str[0] = '\0'; } ostream& operator<<(ostream& out, const string& s) { for (auto ch : s) { out << ch; } return out; } istream& operator>>(istream& in, string& s) { s.clear(); char buff[128]; char ch = in.get(); int i = 0; while (ch != ' ' && ch != '\n') { buff[i++] = ch; if (i == 127) { buff[i] = '\0'; s += buff; i = 0; } ch = in.get(); } if (i > 0) { buff[i] = '\0'; s += buff; } return in; } }test.cpp
#include<string> #include"string.h" namespace bit { void print_str(const string& s) { for (size_t i = 0; i < s.size(); i++) { //s[i]++; cout << s[i] << " "; } cout << endl; string::const_iterator it = s.begin(); while (it != s.end()) { // *it = 'x'; cout << *it << " "; ++it; } cout << endl; } void test_string1() { string s1("hello world"); cout << s1.c_str() << endl; string s2; cout << s2.c_str() << endl; for (size_t i = 0; i < s1.size(); i++) { s1[i]++; } cout << s1.c_str() << endl; string::iterator it = s1.begin(); while (it != s1.end()) { cout << *it << " "; ++it; } cout << endl; // 傻瓜式的替换成迭代器 for (auto ch : s1) { cout << ch << " "; } cout << endl; print_str(s1); } void test_string2() { string s1("hello world"); cout << s1.c_str() << endl; s1 += ' '; s1 += "xxxxxx"; cout << s1.c_str() << endl; s1.insert(5, 'y'); s1.insert(5, 'y'); s1.insert(5, 'y'); cout << s1.c_str() << endl; s1.insert(0, 'y'); cout << s1.c_str() << endl; s1.insert(0, "zzzzzzz"); cout << s1.c_str() << endl; } void test_string3() { string s1("hello world"); cout << s1.c_str() << endl; s1.erase(5, 4); cout << s1.c_str() << endl; s1.erase(5, 100); cout << s1.c_str() << endl; s1.erase(2); cout << s1.c_str() << endl; } void test_string4() { string s1("hello world"); string s2("xxxx"); std::swap(s1, s2); s1.swap(s2); string str("https://legacy.cplusplus.com/reference/string/string/substr/"); string sub1, sub2, sub3; size_t pos1 = str.find(':'); sub1 = str.substr(0, pos1 - 0); cout << sub1.c_str() << endl; size_t pos2 = str.find('/', pos1 + 3); sub2 = str.substr(pos1 + 3, pos2 - (pos1 + 3)); cout << sub2.c_str() << endl; sub3 = str.substr(pos2 + 1); cout << sub3.c_str() << endl; } void test_string5() { string s1("hello world"); string s2(s1); string s3("xxxx"); s1 = s3; } void test_string6() { string s1("hello world"); string s2(s1); string s3("xxxx"); s1 = s3; cout << s1.c_str() << endl; cout << s1 << endl; cin >> s1; cout << s1 << endl; /*char ch1, ch2; cin >> ch1 >> ch2;*/ cin >> s2; cout << s2 << endl; } void test_string7() { string s1("hello world"); cout << s1.c_str() << endl; cout << s1 << endl; s1.clear(); cout << s1.c_str() << endl; cout << s1 << endl; } void test_string8() { string s1("hello world"); string s2(s1); cout << s1 << endl; cout << s2 << endl; string s3("xxxxxxxxxxxxxxxx"); s1 = s3; cout << s1 << endl; cout << s3 << endl; } } int main() { return 0; }to_string;stoi
int main() { //bit::test_string8(); // atoi itoa std::string str1 = std::to_string(123); std::string str2 = std::to_string(123.222); cout << str1 << endl; cout << str2 << endl; int i = stoi(str1); cout << i << endl; return 0; }编码:
int main() { // 编码 // ascall char a1[] = "apple!"; char a2[] = "显示"; cout << sizeof(a1) << endl; cout << sizeof(a2) << endl; a2[3]++; a2[3]++; a2[3]++; a2[3]++; return 0; }经典的string类问题
// 为了和标准库区分,此处使用String class String { public: /*String() :_str(new char[1]) {*_str = '\0';} */ //String(const char* str = "\0") 错误示范 //String(const char* str = nullptr) 错误示范 String(const char* str = "") { // 构造String类对象时,如果传递nullptr指针,可以认为程序非 if (nullptr == str) { assert(false); return; } _str = new char[strlen(str) + 1]; strcpy(_str, str); } ~String() { if (_str) { delete[] _str; _str = nullptr; } } private: char* _str; }; // 测试 void TestString() { String s1("hello bit!!!"); String s2(s1); }上述String类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝。
浅拷贝
浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规。
可以采用深拷贝解决浅拷贝问题,即:每个对象都有一份独立的资源,不要和其他对象共享。
深拷贝
如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。
传统版写法的String类
class String { public: String(const char* str = "") { // 构造String类对象时,如果传递nullptr指针,可以认为程序非 if (nullptr == str) { assert(false); return; } _str = new char[strlen(str) + 1]; strcpy(_str, str); } String(const String& s) : _str(new char[strlen(s._str) + 1]) { strcpy(_str, s._str); } String& operator=(const String& s) { if (this != &s) { char* pStr = new char[strlen(s._str) + 1]; strcpy(pStr, s._str); delete[] _str; _str = pStr; } return *this; } ~String() { if (_str) { delete[] _str; _str = nullptr; } } private: char* _str; };现代版写法的String类
class String { public: String(const char* str = "") { if (nullptr == str) { assert(false); return; } _str = new char[strlen(str) + 1]; strcpy(_str, str); } String(const String& s) : _str(nullptr) { String strTmp(s._str); swap(_str, strTmp._str); } String& operator=(String s) { swap(_str, s._str); return *this; } /* String& operator=(const String& s) { if(this != &s) { String strTmp(s); swap(_str, strTmp._str); } return *this; } */ ~String() { if (_str) { delete[] _str; _str = nullptr; } } private: char* _str; };写时拷贝
写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。
引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象时资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有其他对象在使用该资源。
浅拷贝的问题
- 析构两次 引用计数
拷贝结束后引用次数-1,为0时析构 - 一个修改会影响另一个 写时拷贝
有时拷贝后不会写,就赚了