Прямое преобразование char * в std :: string внутри fscanf - PullRequest
0 голосов
/ 27 ноября 2018

При использовании fscanf для чтения строки и сохранения ее в строковой переменной, fscanf ожидает char* в качестве параметра, следующего за строкой формата, .ie, так и должно быть (насколькоЯ знаю):

char str[<apppropriate length here>];
std::fscanf(filepointer,"%s\n",str);

Если у меня std::string str вместо char str[], я получаю предупреждение -Wformat (очевидно), и программа вылетает с Segnetation fault (я не знаю, почемупока, но я не удивлен).Помимо исправления segfault, я бы также делал это правильно, то есть, не получая -Wformat предупреждений.

Есть ли способ сделать преобразование char* в std::string "встроенным", т. Е. В списке параметров fscanf, или мне придется создать временную переменную char* для храненияданные и преобразовать его в std::string впоследствии (как описано, например, здесь , и я не вижу способа применить этот метод в моем случае).

Ответы [ 4 ]

0 голосов
/ 27 ноября 2018

Поскольку C ++ 17 , вы можете:

std::string str(<apppropriate 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 ++, и вы избежите всего этого.

0 голосов
/ 27 ноября 2018

Если вы используете C ++, вам не следует использовать функции в стиле C или C.Особенно такие функции, как std::fscanf, которые делают незащищенные записи.Вот как правильно читать данные из файла в std::string в C ++: Читать файл построчно, используя ifstream в C ++

0 голосов
/ 27 ноября 2018

Можно использовать 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';
}
0 голосов
/ 27 ноября 2018

Как вы могли бы прочитать в справочнике , оно должно быть:

char str[<apppropriate length here>];
fscanf(filepointer, "%s\n", str);

, поскольку str - это массив .Подробнее в Что такое распадающийся массив?

Там c_str() и data(), которые могут дать вам строку Cstd::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

Live Demo

Но вам действительно следует использовать потоки C ++, например std::cin вместо функций C IO.

Пример:

std::string str;
std::cin >> str;
...