[英]Directly convert char* to std::string inside fscanf
當使用fscanf
讀取字符串並將其存儲到字符串變量中時, fscanf
期望char*
作為格式字符串后面的參數,即,這就是它應該的樣子(據我所知):
char str[<appropriate length here>];
std::fscanf(filepointer,"%s\n",str);
如果我有std::string str
而不是char str[]
我會收到-Wformat
警告(顯然),並且程序因Segnetation fault
崩潰(我還不知道為什么,但我並不感到驚訝)。 除了修復段錯誤之外,我還會正確執行此操作,即不會收到-Wformat
警告。
有沒有辦法做char*
到std::string
轉換“內聯”,即,在參數表內fscanf
或者我會創建一個臨時char*
變量來存儲數據,並將其轉換為std::string
之后的std::string
(如所述,例如, here ,我沒有看到將這種方法應用於我的案例的方法)。
正如您在參考文獻中所讀到的那樣,它應該是:
char str[<appropriate length here>];
fscanf(filepointer, "%s\n", str);
因為str
是一個數組。 閱讀什么是數組到指針衰減?
有c_str()
和data()
,它們可以為您提供std::string
的 C std::string
。 但是,這些函數返回一個常量指針,因此不能在fscanf()
(這是一個來自 C 的函數,因此它處理 C 字符串)。
注意:在C++17 中, data()
有一個返回非常量指針的重載,因此可以用於內聯使用,如下所示:
std::string str(10, '\0'); // a string of size 10, null terminated
fscanf(filepointer, "%9s\n", str.data());
str.resize(strlen(str.data())); // so that 'str.size()' is correct
但是你真的應該使用 C++ 流,比如std::cin
而不是 C IO 函數。
例子:
std::string str;
std::cin >> str;
如果您使用的是 C++,則不應使用 C 或 C 風格的函數。 特別是像std::fscanf
這樣的函數,它執行不受保護的寫入。 以下是如何在 C++ 中正確地從文件讀取數據到std::string
在 C++ 中使用 ifstream 逐行讀取文件
可以像這樣使用std::string
和std::scanf()
:
#include <cstdlib> // EXIT_FAILURE
#include <cstdio> // std::scanf()
#include <cstring> // std::strlen()
#include <string>
#include <iostream>
int main()
{
std::string foo(40, '\0'); // fill the string with 40 0s
// for pre C++11 please make it 41
int length = 0;
if (std::scanf("%39s%n", &foo[0], &length) != 1) {
std::cerr << "Input error :(\n\n";
return EXIT_FAILURE;
}
foo.resize(length); // let foo know its own length ^^
std::cout << foo.length() << " chars: " << foo << '\n';
}
從C++17 開始,您可以:
std::string str(<appropriate length here>, 0);
fscanf(filepointer, "%s\n", str.data());
str.resize(strlen(str.c_str()));
但你不應該。
首先,它沒有做你想讓它做的事情。 如果你有一個像"Tom Jerry\\n"
這樣的輸入行,它只會讀取"Tom"
,更糟糕的是,下次你從文件中讀取時它會嘗試讀取"Jerry"
。 你真的應該使用fgets()
, std::istream::getline()
,或者更好的是, std::getline(file, str)
。
其次, '\\0'
或char()
是 C++ 字符串中的有效字符。 如果你看過"Tom\\0Jerry\\n"
,實際的字符串代碼將設法讀取包含"Tom\\0Jerry"
,這可能是一個有效的結果,但隨后將其剪切到"Tom"
,因為這的resize(strlen(str.c_str()))
。 您可以通過創造性地使用%n
格式說明符來緩解它,但首先為什么要使您的生活復雜化?
第三,C++ 字符串輸入例程可以在必要時調整字符串的大小。 在 C 函數中,您需要指定字符串大小限制,這通常是任意的。 如果您對格式說明符草率(如您的示例),這可能會導致緩沖區溢出,但如果您沒有正確處理截斷輸入的特殊情況,也會導致邏輯錯誤。
因此,只需將std::getline(file, str)
與 C++ 流輸入一起使用,您就可以避免這一切。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.