簡體   English   中英

在 fscanf 中直接將 char* 轉換為 std::string

[英]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::stringstd::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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM