(c++)string的模擬實現

目錄

1.構造函數

2.析構函數

3.擴容

? ?1.reserve(擴容不初始化)

? ?2.resize(擴容加初始化)

4.push_back

5.append

6. += 運算符重載

? 1.+=一個字符

??2.+=一個字符串

7 []運算符重載

8.find

1.找一個字符?

2.找一個字符串

9.insert

?1.插入一個字符

?2.插入一個字符串

9.erase

10.substr

11.運算符重載比較大小

? ? ? ? ?1.<

? ? ? ? 2.==

????????3.<=

? ? ? ? 4.>

? ? ? ? 5.>=

? ? ? ? 6.!=

12.拷貝構造

13.賦值 =

14.<<

15.>>

16.迭代器

完整代碼實現


? ? ? 首先我們先定義頭文件String.h,和命名空間_string防止和庫中的string發生名字沖突

#include <iostream>
#include <cassert>
#include <string.h>
using namespace std;namespace _string {class string {public:static size_t npos;protected:char*  _str;size_t _size;size_t _capacity;}size_t string::npos = -1;
}

? ? ? ? 其是我們的string類里面就是一個順序表, 所以我們會定義一個數組_str,_size為實際字符所占的大小,_capacity為容量,如果達到了最大的容量我們就是_size == _capacity 我們就要進行擴容處理.

1.構造函數

string(const char* str = ""):_str(new char[strlen(str) + 1]),_size(strlen(str)),_capacity(strlen(str)){memcpy(_str, str, _size + 1);}

????????這里我們為什么要多開一個空間strlen(str) + 1呢?因為我們這里字符串后面會有'\0',我們要多開一個位置給'\0',但是為什么_size和_capacity為什么不用+1呢?因為我們的'\0' 不算大小,所以我們_size和_capacity不需要給多一個空間.

????????這里需要注意的是,我們開好空間的時候不要忘記去把str的內容拷貝的_str中,這里拷貝_size + 1是因為有'\0'也是需要拷貝的.

2.析構函數

~string() {if (_str) {delete[] _str;_size = _capacity = 0;}
}

????????這里析構函數我認為,如果_str為空才需要釋放空間,不為空不需要判斷,所以我們這里加上一個判斷,不為空的時候才可以去釋放空間。

3.擴容

? ? ??????1.reserve(擴容不初始化)

void reserve(size_t n) {if (n > _capacity) {char* tmp = new char[n + 1];memcpy(tmp, _str, _size + 1);delete[] _str;_str = tmp;_capacity = n;}
}

? ?擴容的時候需要進行判斷,如果n大于容量擴容才有意義,如果小于就沒有意義了

????????2.resize(擴容加初始化)

void resize(size_t n , char ch = '\0') {if (n < _size) {_size = n;_str[_size] = '\0';}else {reserve(n);while (_size != n) {_str[_size++] = '\0';}_str[_size] = '\0';}
}

? ? ? ? resize如果給的n容量會繼續縮小,所以當n < _size的時候我們直接把n位置變為'\0'就可以了

如果這里的n > _ size,就會出現兩種情況,一種是? _capacity > n > _size 還有一種是 n > _capacity

因為我們寫了擴容reserve,里面有判斷,所以我們之間繼續復用就可以了,最后再完成數據的拷貝就可以了.

4.push_back

void push_back(char ch) {if (_size == _capacity) {reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size++] = ch;_str[_size] = '\0';
}

5.append

void append(const char* str) {size_t len = strlen(str);if (_size + len > _capacity) {reserve(_size + len);}memcpy(_str+_size,str,len + 1);_size += len;
}

????????push_back和append都一樣,使用時應該要檢查容量是否足夠,不夠的時候再擴容,最后完成數據的拷貝就可以了.

6. += 運算符重載

? ? ? ? 1.+=一個字符

string& operator+=(char ch) {push_back(ch);return *this;
}

? ? ? ? 2.+=一個字符串

string& operator+=(const char* str) {append(str);return *this;
}

? ? ? 我們上面實現了push_back()和append()所以這里我們實現復用就可以了.

7 []運算符重載

//只讀
const char operator[](size_t pos) const {assert(pos < _size);return _str[pos];
}//讀寫
char operator[](size_t pos) {assert(pos < _size);return _str[pos];
}

? ? ? ? 我們在進行重載的時候應該注意,pos的范圍不能超過_size的大小.

8.find

1.找一個字符?

? ? ? ? ? ? 找一個字符返回當前位置

//默認從0位置開始size_t find(char ch, size_t pos = 0) {assert(pos < _size);for (size_t i = pos; i < _size; i++) {if (_str[i] == ch) {return i;}}return npos;
}

2.找一個字符串

? ? ? ? 找一個字符串返回第一個字符出現的位置.

size_t find(const char* str, size_t pos) {assert(pos < _size);char* ptr = strstr(_str, str);if (ptr) {return ptr - _str;}else {return npos;}
}

? ? ? ? 什么兩個如果都沒有找到的話,會返回npos,npos是string中靜態變量,為無符號數的最大值.

9.insert

????????1.插入一個字符

void insert(size_t pos , char ch) {assert(pos < _size);if (_size == _capacity) {reserve(_capacity == 0 ? 4 : _capacity*2);}//'\0'也要一起移動size_t end = _size;while (end >= pos &&  end != npos) {_str[end + 1] = _str[end];end--;}_str[pos] = ch;_size++;
}

????????2.插入一個字符串

void insert(size_t pos, const char* str) {size_t len = strlen(str);if (_size + len > _capacity) {reserve(_size + len);}	//移動數據size_t end = _size;while (end >= pos && end != npos) {_str[end + len] = _str[end];end--;}//拷貝數據for (size_t i = 0; i < len; i++) {_str[pos + i] = str[i];}_size += len;
}

????????我們兩個函數都需要注意的是移動數據的時候這里是end--,如果沒有npos != end,pos的位置是0,會造成死循環的問題,這是為什么?

????????沒有npos != end,如果pos的位置是0,那么循環的結束條件應該是end < 0,但是這里的end是無符號數,當end到達-1時相當于正數的最大值,不可能小于0. 所以我們這里應該要加上npos != end;

9.erase


void erase(size_t pos = 0 , size_t len = npos) {// '\0'也要移動所以可以等于 _size;assert(pos <= _size);if (pos + len >= _size || len == npos) {_str[_size] = '\0';_str[pos] = '\0';_size = pos;}else {size_t end = pos + len;while (end <= _size) {_str[pos++] = _str[end++];}_size -= len;}
}

? ? ? ? 從pos位置開始刪除,長度為len的字符. 如果pos + len >= _size 或者說 len說民刪除完后面的字符, 直接把pos換成'\0'就可以了.

? ? ? ? 如果pos + len < _size 就移動數據,為什么end <= _size ? 因為'\0'也要被移動.

10.substr

string substr(size_t pos = 0,size_t len = npos) {assert(pos < _size);//調整len的大小if (pos + len >= _size || len == npos) {len = _size - pos;}//預留好空間string tmp;tmp.reserve(len);for (size_t i = 0; i < len; i++){tmp += _str[pos + i];}tmp += '\0';return tmp;
}

? ? ? ? 不要忘記最后一個位置要加上'\0'

11.運算符重載比較大小

? ? ? ? ?1.<

? ? ? ? 我們要注意有三種特殊的情況

hello helloo true
hello hell false
hello hello false

????????我們給兩個長度len1,len2從0開始遍歷碰到第一個小于就返回true,大于返回false,要是等于就繼續len1和len2都要加加.

? ? ? ? 如果出了循環,我們看上面三種情況,只有len2 < str._size && len1 == _size 才能返回true

其他都是false,所以我們直接返回len2 < str._size && len1 == _size就可以了

bool operator<(const string& str) const {size_t len1 = 0, len2 = 0;while (len1 < _size && len2 < str._size) {if (_str[len1] < str._str[len2]) {return true;}else if (_str[len1] > str._str[len2]) {return false;}else {len1++;len2++;}}return len1 == _size && len2 < str._size;
}

? ? ? ? 2.==

bool operator==(const string& str) const {if (_size != str._size) {return false;}else {size_t len1 = 0, len2 = 0;while (len1 < _size && len2 < str._size) {if (_str[len1] < str._str[len2]) {return false;}else if (_str[len1] > str._str[len2]) {return false;}else {len1++;len2++;}}return true;}
}

? ? ? ?如果兩個字符串的長度不相等直接返回false就可以了,長度如果相等有不相等的兩個字符也是直接返回false,如果能出循環直接返回true;

? ? ? ? 我們上面實現了< 和 = 我們直接復用就可以了

????????3.<=

bool operator<=(const string& str) const {return *this < str || *this == str;
}

? ? ? ? 4.>

bool operator>(const string& str) const {return !(*this <= str);
}

? ? ? ? 5.>=

bool operator>=(const string& str) const {return !(*this < str);
}

? ? ? ? 6.!=

bool operator!=(const string& str) const {return !(*this == str);
}

12.拷貝構造

????????類里面默認生成的拷貝構造為淺拷貝,如果我們直接用默認生成的賦值,會造成析構函數釋放同一塊空間兩次的問題編譯器會就行報錯,所以我們需要實現深拷貝.

string(const string& str) {//要多給一個位置給'\0'char* _str = new char[str._capacity + 1];_size = str._size;_capacity = str._capacity;//'\0' 也要進行拷貝所以拷貝_size + 1memcpy(_str,str._str,str._size + 1);
}

13.賦值 =

? ? ? ? 和上面的拷貝構造一樣,必須要實現深拷貝否則編譯器會報錯.

void swap(string& str) {std::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);
}//str為臨時變量出了作用域就會銷毀
//交換后不用就行處理
string& operator=(string str) {swap(str);return *this;
}

? ? ? ? 這里有很多人不明白賦值這里參數為什么不傳引用?這里的string沒有引用是一個臨時變量,處理作用域就會銷毀.所以我們把*this 的值和str的值進行交換不會有任何的問題

? ? ? ? 這里的<< 和 >> 我們一般不喜歡寫在類里面,如果寫在類里面,第一個參數默認是this指針,那么我們調用的時候就需要反過來寫,不符合我們的習慣.

str >> cin? ?

str << cout?

14.<<

//按照_size的大小來進行打印
//不是碰到'\0'就停止
ostream& operator<<(ostream& _cout, const string& str) {for (size_t i = 0; i < str.size(); i++){_cout << str[i];}return _cout;
}

? ? ? ? 這里需要注意的是打印的是按照_size去打印,不是碰到'\0'就停下.

15.>>

//每次輸入之前都要清空
istream& operator>>(istream& _cin, string& str) {	//清空str.clear();char ch;//給一buff數組來減小拷貝來提高效率int i = 0;char buff[128] = { 0 };//讀取前置空格ch = _cin.get();while (ch == '\n' || ch == ' ')ch = _cin.get();while (ch != '\n' && ch != ' ') {buff[i++] = ch;if (i == 127) {//最后一個位置給'\0'buff[i] = '\0';str += buff;i = 0;}ch = _cin.get();}//如果i不等于0說明里面還有字符if (i != 0) {buff[i] = '\0';str += buff;}return _cin;
}

16.迭代器

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;
}

完整代碼實現

namespace _String {class string {friend ostream& operator<<(ostream& _cout, const string& str);friend istream& operator>>(istream& _cin, string& str);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;}string(const char* str = ""):_str(new char[strlen(str) + 1]), _size(strlen(str)), _capacity(strlen(str)){memcpy(_str, str, _size + 1);}~string() {if (_str) {delete[] _str;_size = _capacity = 0;}}string(const string& str) {//要多給一個位置給'\0'char* _str = new char[str._capacity + 1];_size = str._size;_capacity = str._capacity;//'\0' 也要進行拷貝所以拷貝_size + 1memcpy(_str,str._str,str._size + 1);}void swap(string& str) {std::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);}//str為臨時變量出了作用域就會銷毀//交換后不用就行處理string& operator=(string str) {swap(str);return *this;}//只讀const char operator[](size_t pos) const {assert(pos < _size);return _str[pos];}//讀寫char operator[](size_t pos) {assert(pos < _size);return _str[pos];}// hello helloo true// hello hell false;// hello hello falsebool operator<(const string& str) const {size_t len1 = 0, len2 = 0;while (len1 < _size && len2 < str._size) {if (_str[len1] < str._str[len2]) {return true;}else if (_str[len1] > str._str[len2]) {return false;}else {len1++;len2++;}}return len1 == _size && len2 < str._size;}bool operator==(const string& str) const {if (_size != str._size) {return false;}else {size_t len1 = 0, len2 = 0;while (len1 < _size && len2 < str._size) {if (_str[len1] < str._str[len2]) {return false;}else if (_str[len1] > str._str[len2]) {return false;}else {len1++;len2++;}}return true;}}bool operator<=(const string& str) const {return *this < str || *this == str;}bool operator>(const string& str) const {return !(*this <= str);}bool operator>=(const string& str) const {return !(*this < str);}bool operator!=(const string& str) const {return !(*this == str);}void reserve(size_t n) {if (n > _capacity) {char* tmp = new char[n + 1];memcpy(tmp, _str, _size + 1);delete[] _str;_str = tmp;_capacity = n;}}void resize(size_t n, char ch = '\0') {if (n < _size) {_str[_size] = '\0';_size = n;_str[_size] = '\0';}else {//會自己判斷不用加reserve(n);while (_size != n) {_str[_size++] = '\0';}_str[_size] = '\0';}}void push_back(char ch) {if (_size == _capacity) {reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size++] = ch;_str[_size] = '\0';}void insert(size_t pos , char ch) {assert(pos <= _size);if (_size == _capacity) {reserve(_capacity == 0 ? 4 : _capacity*2);}//'\0'也要一起移動size_t end = _size;while (end >= pos &&  end != npos) {_str[end + 1] = _str[end];end--;}_str[pos] = ch;_size++;}void insert(size_t pos, const char* str) {assert(pos <= _size);size_t len = strlen(str);if (_size + len > _capacity) {reserve(_size + len);}//移動數據size_t end = _size;while (end >= pos && end != npos) {_str[end + len] = _str[end];end--;}//拷貝數據for (size_t i = 0; i < len; i++) {_str[pos + i] = str[i];}_size += len;}void erase(size_t pos = 0 , size_t len = npos) {// '\0'也要移動所以可以等于 _size;assert(pos <= _size);if (pos + len >= _size || len == npos) {_str[_size] = '\0';_str[pos] = '\0';_size = pos;}else {size_t end = pos + len;while (end <= _size) {_str[pos++] = _str[end++];}_size -= len;}}//如果len == npos 說明從pos位置開始截完全部string substr(size_t pos = 0,size_t len = npos) {assert(pos < _size);//調整len的大小if (pos + len >= _size || len == npos) {len = _size - pos;}//預留好空間string tmp;tmp.reserve(len);for (size_t i = 0; i < len; i++){tmp += _str[pos + i];}tmp += '\0';return tmp;}//默認從0位置開始size_t find(char ch, size_t pos = 0) {assert(pos < _size);for (size_t i = pos; i < _size; i++) {if (_str[i] == ch) {return i;}}return npos;}//默認0位置開始size_t find(const char* str, size_t pos = 0) {assert(pos < _size);char* ptr = strstr(_str, str);if (ptr) {return ptr - _str;}else {return npos;}}void append(const char* str) {size_t len = strlen(str);if (_size + len > _capacity) {reserve(_size + len);}//'\0'也要就行拷貝memcpy(_str + _size, str, len + 1);_size += len;}string& operator+=(char ch) {push_back(ch);return *this;}string& operator+=(const char* str) {append(str);return *this;}const char* c_str() const {return _str;}size_t size() const {return _size;}void clear() {_str[0] = '\0';_size = 0;}static size_t npos;protected:char* _str;size_t _size;size_t _capacity;};size_t string::npos = -1;//按照_size的大小來進行打印//不是碰到'\0'就停止ostream& operator<<(ostream& _cout, const string& str) {for (size_t i = 0; i < str.size(); i++){_cout << str[i];}return _cout;}//每次輸入之前都要清空istream& operator>>(istream& _cin, string& str) {//清空str.clear();char ch;//給一buff數組來減小拷貝來提高效率int i = 0;char buff[128] = { 0 };//讀取前置空格ch = _cin.get();while (ch == '\n' || ch == ' ')ch = _cin.get();while (ch != '\n' && ch != ' ') {buff[i++] = ch;if (i == 127) {buff[i] = '\0';str += buff;i = 0;}ch = _cin.get();}//如果i不等于0說明里面還有字符if (i != 0) {buff[i] = '\0';str += buff;}return _cin;}
}

? ? ? ? 如果有錯誤,歡迎各位大佬指正.

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/85679.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/85679.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/85679.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

學習筆記(24): 機器學習之數據預處理Pandas和轉換成張量格式[2]

學習筆記(24): 機器學習之數據預處理Pandas和轉換成張量格式[2] 學習機器學習&#xff0c;需要學習如何預處理原始數據&#xff0c;這里用到pandas&#xff0c;將原始數據轉換為張量格式的數據。 學習筆記(23): 機器學習之數據預處理Pandas和轉換成張量格式[1]-CSDN博客 下面…

LeetCode 2297. 跳躍游戲 VIII(中等)

題目描述 給定一個長度為 n 的下標從 0 開始的整數數組 nums。初始位置為下標 0。當 i < j 時&#xff0c;你可以從下標 i 跳轉到下標 j: 對于在 i < k < j 范圍內的所有下標 k 有 nums[i] < nums[j] 和 nums[k] < nums[i] , 或者對于在 i < k < j 范圍…

【前端】緩存相關

本知識頁參考&#xff1a;https://zhuanlan.zhihu.com/p/586060532 1. 概述 1.1 應用場景 靜態資源 場景&#xff1a;圖片、CSS、JS 文件等靜態資源實現&#xff1a;使用 HTTP 緩存控制頭&#xff0c;或者利用 CDN 進行邊緣緩存 數據緩存 場景&#xff1a;請求的返回結果實現…

獵板硬金鍍層厚度:高頻通信領域的性能分水嶺

在 5G 基站、毫米波雷達等高頻場景中&#xff0c;硬金鍍層厚度的選擇直接決定了 PCB 的信號完整性與長期可靠性。獵板硬金工藝&#xff1a; 1.8μm 金層搭配羅杰斯 4350B 基材的解決方案&#xff0c;在 10GHz 頻段實現插入損耗&#xff1c;0.15dB/cm&#xff0c;較常規工藝降低…

第35次CCF計算機軟件能力認證-5-木板切割

原題鏈接&#xff1a; TUOJ 我自己寫的35分正確但嚴重超時的代碼 #include <bits/stdc.h> using namespace std; int main() {int n, m, k;cin >> n >> m >> k;vector<unordered_map<int, int>> mp(2);int y;for (int i 1; i < n; …

【藍橋杯】包子湊數

包子湊數 題目描述 小明幾乎每天早晨都會在一家包子鋪吃早餐。他發現這家包子鋪有 NN 種蒸籠&#xff0c;其中第 ii 種蒸籠恰好能放 AiAi? 個包子。每種蒸籠都有非常多籠&#xff0c;可以認為是無限籠。 每當有顧客想買 XX 個包子&#xff0c;賣包子的大叔就會迅速選出若干…

pikachu通關教程-目錄遍歷漏洞(../../)

目錄遍歷漏洞也可以叫做信息泄露漏洞、非授權文件包含漏洞等. 原理:目錄遍歷漏洞的原理比較簡單&#xff0c;就是程序在實現上沒有充分過濾用戶輸入的../之類的目錄跳轉符&#xff0c;導致惡意用戶可以通過提交目錄跳轉來遍歷服務器上的任意文件。 這里的目錄跳轉符可以是../…

[概率論基本概念4]什么是無偏估計

關鍵詞&#xff1a;Unbiased Estimation 一、說明 對于無偏和有偏估計&#xff0c;需要了解其敘事背景&#xff0c;是指整體和抽樣的關系&#xff0c;也就是說整體的敘事是從理論角度的&#xff0c;而估計器原理是從實踐角度說事&#xff1b;為了表明概率理論&#xff08;不可…

面試題——計算機網絡:HTTP和HTTPS的區別?

HTTP&#xff08;HyperText Transfer Protocol&#xff09;&#xff1a;作為互聯網上應用最廣泛的網絡通信協議&#xff0c;HTTP是基于TCP/IP協議族的應用層協議。它采用標準的請求-響應模式進行通信&#xff0c;通過簡潔的報文格式&#xff08;包含請求行、請求頭、請求體等&a…

uni-app學習筆記十九--pages.json全局樣式globalStyle設置

pages.json 頁面路由 pages.json 文件用來對 uni-app 進行全局配置&#xff0c;決定頁面文件的路徑、窗口樣式、原生的導航欄、底部的原生tabbar 等。 導航欄高度為 44px (不含狀態欄)&#xff0c;tabBar 高度為 50px (不含安全區)。 它類似微信小程序中app.json的頁面管理部…

SQL思路解析:窗口滑動的應用

目錄 &#x1f3af; 問題目標 第一步&#xff1a;從數據中我們能直接得到什么&#xff1f; 第二步&#xff1a;我們想要的“7天窗口”長什么樣&#xff1f; 第三步&#xff1a;SQL 怎么表達“某一天的前六天”&#xff1f; &#x1f50d;JOIN 比窗口函數更靈活 第四步&am…

解決MyBatis參數綁定中參數名不一致導致的錯誤問題

前言 作為一名Java開發者&#xff0c;我在實際項目中曾多次遇到MyBatis參數綁定的問題。其中最常見的一種情況是&#xff1a;在Mapper接口中定義的參數名與XML映射文件中的占位符名稱不一致&#xff0c;導致運行時拋出Parameter xxx not found類異常。這類問題看似簡單&#x…

黑馬程序員TypeScript課程筆記—類型兼容性篇

類型兼容性的說明 因為傳入的時候只有一個參數 對象之間的類型兼容性 接口之間的類型兼容性 函數之間的類型兼容性&#xff08;函數參數個數&#xff09; 和對象的兼容性正好相反 函數之間的類型兼容性&#xff08;函數參數類型&#xff09; 函數參數的兼容性就不要從接口角度…

智能電視的操作系統可能具備哪些優勢

豐富的應用資源&#xff1a; 操作系統內置了應用商店&#xff0c;提供了豐富的應用資源&#xff0c;涵蓋視頻、游戲、教育等多個領域&#xff0c;滿足不同用戶的多樣化需求。用戶可以輕松下載并安裝所需的應用&#xff0c;享受更多元化的娛樂和學習體驗。 流暢的操作體驗&…

Xget 正式發布:您的高性能、安全下載加速工具!

您可以通過 star 我固定的 GitHub 存儲庫來支持我&#xff0c;謝謝&#xff01;以下是我的一些 GitHub 存儲庫&#xff0c;很有可能對您有用&#xff1a; tzst Xget Prompt Library 原文 URL&#xff1a;https://blog.xi-xu.me/2025/06/02/xget-launch-high-performance-sec…

精美的軟件下載頁面HTML源碼:現代UI與動畫效果的完美結合

精美的軟件下載頁面HTML源碼&#xff1a;現代UI與動畫效果的完美結合 在數字化產品推廣中&#xff0c;一個設計精良的下載頁面不僅能提升品牌專業度&#xff0c;還能顯著提高用戶轉化率。本文介紹的精美軟件下載頁面HTML源碼&#xff0c;通過現代化UI設計與豐富的動畫效果&…

麒麟v10+信創x86處理器離線搭建k8s集群完整過程

前言 最近為某客戶搭建內網的信創環境下的x8s集群&#xff0c;走了一些彎路&#xff0c;客戶提供的環境完全與互聯網分離&#xff0c;通過yum、apt這些直接拉依賴就別想了&#xff0c;用的操作系統和cpu都是國產版本&#xff0c;好在仍然是x86的&#xff0c;不是其他架構&…

Pycharm的使用技巧總結

目錄 一、高效便捷的快捷鍵 二、界面漢化處理 1.設置 2.插件 3.漢化插件安裝 三、修改字體大小、顏色 1.選擇文件-設置 2.選擇編輯器-配色方案-python 3.修改注釋行顏色 4.修改編輯器字體顏色 一、高效便捷的快捷鍵 序號快捷鍵功能場景效果1Ctrl /快速注釋/取消注釋…

安全編碼規范與標準:對比與分析及應用案例

在軟件開發領域&#xff0c;尤其是涉及安全關鍵系統的開發中&#xff0c;遵循編碼規范和標準是確保軟件質量和安全性的重要手段。除了CERT C、CERT Java和MISRA外&#xff0c;還有其他多個與安全相關的編碼規范和標準&#xff0c;以下是一些主要標準的對比說明&#xff1a; 一…

FFmpeg學習筆記

1. 播放器的架構 2. 播放器的渲染流程 3. ffmpeg下載與安裝 3.0 查看PC是否已經安裝了ffmpeg ffmpeg 3.1 下載 wget https://ffmpeg.org/releases/ffmpeg-7.0.tar.gz 3.2 解壓 tar zxvf ffmpeg-7.0.tar.gz && cd ./ffmpeg-7.0 3.3 查看配置文件 ./configure …