# i、文件流构建字符串
1 2 3
| std::ostringstream oss; oss << v.major << "." << v.minor << "." << v.patch; string str = oss.str();
|
# i、文件流分割字符串:
1 2 3 4 5 6 7
| string word; stringstream out(str); vector<string> words; while(out >> word){ words.push_back(word); }
|
关于流的更多细节,见:C++ 的流
# i、将整型 int 转化为字符串 string :
1 2
| str += to_string(cur->val);
|
# i、将字符串 string 转化为整型 int:
1 2 3
| stoi(str);
atoi(str.c_str());
|
# i、string 取子串:
1 2
| string cur = s.substr(vec[0], vec[1] - vec[0] + 1);
|
利用这个,我们可以灵活组织新的字符串而不影响原有字符串。场景举例:
当我们想要将某个字符串的后缀进行更换、但不希望影响原有字符串,则可以取子串后拼接:
1 2 3 4 5 6 7 8 9 10 11 12
| #include <iostream> #include <string>
int main() { std::string encryptedFile = "xxx.bin";
std::string decryptedFile = encryptedFile.substr(0, encryptedFile.length() - 4) + ".txt"; std::cout << decryptedFile << std::endl; return 0; }
|
# i、string 查找子串:
1 2 3 4
| string str = "Hello, World!"; if (str.find(subStr) != std::string::npos) { }
|
# i、string 查找前后缀:
1 2 3 4 5 6 7 8
| size_t lastSlashPos = exePath.rfind('/'); if(lastSlashPos != std::string::npos) { std::string prefixPath = exePath.substr(0, lastSlashPos); std::cout << "prefixPath = " << prefixPath << std::endl; std::string postfixPath = exePath.substr(lastSlashPos + 1); std::cout << "postfixPath = " << postfixPath << std::endl; }
|
# i、string 删除元素:
1 2 3 4 5
| string str = " hello world "; str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
|
# i、C++ 延时
1 2 3 4 5 6
| #include <iostream> #include <thread> #include <chrono>
std::this_thread::sleep_for(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
# i、partial_sum 求前缀和:
1 2 3 4
| #include <algorithm> std::vector<int> numbers = {1, 2, 3, 4, 5}; std::vector<int> prefixSum(numbers.size()+1); std::partial_sum(numbers.begin(), numbers.end(), prefixSum.begin()+1);
|
# i、Ctrl C 中断函数:
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
| #include <iostream> #include <csignal>
void ST_HandleSig(int signal) { std::cout << "Received signal: " << signal << std::endl; }
int main() { std::signal(SIGINT, ST_HandleSig);
while (true) { } return 0; }
|
# i、读取固定格式数据表
该语法糖可用于读写寄存器,利用 vector 和 tuple:
1 2 3 4 5 6 7 8 9
| std::vector<std::tuple<int, int>> reg_table = { {0x1006, 0x08}, {0x1007, 0x00}, {0x1040, 0x00}, };
for(auto item : reg_table) { std::cout << std::get<0>(item) << ":" << std::get<1>(item) << std::endl; }
|
这里当然也可以在 vector 内部嵌套使用 vector,形成二维数组,但没有 tuple 灵活:
对于这个特定的数据结构,使用 std::vector<std::vector<int>>
存储也是可以的,但使用 std::tuple
更能准确地反映每个元素包含三个不同类型的数据。在这种情况下,每个元素都包含一个地址(整数),一个值 1(整数),和一个值 2(整数)。使用 std::tuple
可以更清晰地表示这个数据结构的含义。
如果使用 std::vector<std::vector<int>>
,则需要确保每个内部 std::vector
都包含三个整数,并且在访问数据时需要小心确保每个内部 std::vector
的大小都是 3。这可能会导致代码更容易出错,并且不如 std::tuple
那样清晰。
综上所述,选择使用 std::tuple
可以提高代码的可读性和清晰度,以及更准确地表示每个元素的结构。
例如:
1 2 3 4 5 6 7 8 9
| std::vector<std::tuple<int, char, int>> reg_table = { {0x1006, 'a', 0x08}, {0x1007, 'g', 0x00}, {0x1040, 'h', 0x00}, };
for(auto item : reg_table) { std::cout << std::get<0>(item) << ":" << std::get<1>(item) << ":" << std::get<2>(item) << std::endl; }
|
对于这种情况,tuple 更方便灵活,可以使用不同的数据类型,而 vector 则会限制每个元素都归属于同一种类型。
对于 tuple 元素的访问,可以通过 get 函数(如上所示),也可以利用 C++17 的 结构化绑定 语法进行优化:
1 2 3 4 5 6 7 8
| std::tuple<int, double, std::string> myTuple(42, 3.14, "Hello");
auto [intValue, doubleValue, stringValue] = myTuple;
std::cout << "整数值: " << intValue << std::endl; std::cout << "双精度值: " << doubleValue << std::endl; std::cout << "字符串值: " << stringValue << std::endl;
|
于是前面的代码可以优化成:
1 2 3 4 5 6 7 8 9 10
| std::vector<std::tuple<int, char, int>> reg_table = { {0x1006, 'a', 0x08}, {0x1007, 'g', 0x00}, {0x1040, 'h', 0x00}, };
for(auto item : reg_table) { auto [addr, ch, val] = item; std::cout << addr << ":" << ch << ":" << val << std::endl; }
|
# i、剥取文件名
1 2 3 4 5 6 7 8 9 10 11 12 13
| std::string getFilename(const std::string inputFile) { std::string fileName = inputFile; size_t lastSlashPos = inputFile.rfind('/'); size_t lastBackslashPos = inputFile.rfind('\\'); size_t lastSeparatorPos = std::max((lastSlashPos == std::string::npos) ? 0 : lastSlashPos, (lastBackslashPos == std::string::npos) ? 0 : lastBackslashPos);
if (lastSeparatorPos != 0) { fileName = inputFile.substr(lastSeparatorPos + 1); std::cout << "File Name: " << fileName << std::endl; } return fileName; }
|
这里函数的输入是某个文件的路径,可能的形式为
/path/to/myfolder/file.txt
、
../../file.bin
、
file.txt
,该函数的作用则是剥取最后的文件名。(这里考虑了
\
和
/
两种文件分隔符形式,注意这里的
\\
为转义)。
# i、获取可执行程序的路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| auto getExePath = [](){ std::string exePath(100, ' '); if (readlink("/proc/self/exe", const_cast<char*>(exePath.c_str()), exePath.size()) != -1) { size_t lastSlashPos = exePath.rfind('/'); if(lastSlashPos != std::string::npos) { std::string prefixPath = exePath.substr(0, lastSlashPos); return prefixPath; } else { std::cout << "split prefixPath error" << std::endl; return std::string(); } } else { std::cout << "getExePath error" << std::endl; return std::string(); } };
|