Read into Std::String Using Scanf

Read into std::string using scanf

There is no situation under which gets() is to be used! It is always wrong to use gets() and it is removed from C11 and being removed from C++14.

scanf() doens't support any C++ classes. However, you can store the result from scanf() into a std::string:

Editor's note: The following code is wrong, as explained in the comments. See the answers by Patato, tom, and Daniel Trugman for correct approaches.

std::string str(100, ' ');
if (1 == scanf("%*s", &str[0], str.size())) {
// ...
}

I'm not entirely sure about the way to specify that buffer length in scanf() and in which order the parameters go (there is a chance that the parameters &str[0] and str.size() need to be reversed and I may be missing a . in the format string). Note that the resulting std::string will contain a terminating null character and it won't have changed its size.

Of course, I would just use if (std::cin >> str) { ... } but that's a different question.

How to scan a string using scanf with C++

What you're showing (scanf("%s",&string);) doesn't work (and never could, by e.g. giving different format specifiers)!

scanf() used with the %s format specifier requires a corresponding char* pointer referencing a raw char[] array to receive the read data in the parameter list. The std::string pointer you're passing in your example, doesn't provide automatic casting to the referred std::string instances internally managed char[] buffer that way though.

You could try to use &string.front() instead, but I wouldn't really recommend that, unless you're very sure what you're doing.

For c++ you should better use std::cin and

std::istream& operator>>(std::istream&, const std::string&)
instead:

std::cout << "Put in string value:" << std::endl;
std::string input;
std::cin >> input;

(xcode isn't relevant for your question BTW!)

How can I read a string with scanf() in C++?

Using the C scanf() function requires using C strings. This example uses a temporary C string tmp, then copies the data into the destination std::string.

char tmp[101];
scanf("%100s", tmp);
s[i][j] = tmp;

Why can't I read the input string using this scanf function?

scanf - is a C function. It knows nothing about C++ class std::string. Its format specifier %s is used to enter data in a character array.

You mixed two languages: C and C++. It is a bad style of programming. Instead of the loop

while ( scanf ("%d %s",&n, input ) != EOF ) 
{

string sub = input.substr(0,n);
cout<< sub;
}

use the following loop

while ( std::cin >> n >> input ) 
{

string sub = input.substr(0,n);
cout<< sub;
}

Directly convert char* to std::string inside fscanf

As you could have read in the reference, it should be:

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

since str is an array. Read more in What is array to pointer decay?

There c_str() and data(), which can give you the C string of an std::string. However, thsese functions return a constant pointer, thus it cannot be used in fscanf() (which is a function coming from C, thus it handles C strings).

Note: In C++17, data() has an overload that returns a non-constant pointer, thus could be used for inline usage, like this:

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

But you should really be using C++ streams, like std::cin instead of C IO functions.

Example:

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

How to translate scanf exact matching into modern c++ stringstream reading

I've run into this requirement as well, and wrote a little extractor for streams that lets you match literals. The code looks like this:

#include <iostream>
#include <cctype>

std::istream& operator>>(std::istream& is, char const* s) {

if (s == nullptr)
return;

if (is.flags() & std::ios::skipws) {
while (std::isspace(is.peek()))
is.ignore(1);

while (std::isspace((unsigned char)* s))
++s;
}

while (*s && is.peek() == *s) {
is.ignore(1);
++s;
}
if (*s)
is.setstate(std::ios::failbit);
return is;
}

In your case, you'd use it something like this:

if (!(ss >> "vn" >> x >> y >> z))
break;

As you can see from the code, it pays attention to the skipws state, so it'll skip leading white space if and only if you have skipws set. So if you need to match a pattern that includes a precise number of leading spaces, you want to turn skipws off, and include those spaces in your pattern.

Difference between std::cin and scanf() applied to string

scanf knows nothing about std::string. If you want to read into the underlying character array you must write scanf("%s", s.data());. But do make sure that the string's underlying buffer is large enough by using std::string::resize(number)!

Generally: don't use scanf with std::string.

Another alternative if you want to use scanf and std::string

int main()
{
char myText[64];
scanf("%s", myText);

std::string newString(myText);
std::cout << newString << '\n';

return 0;
}

Construct the string after reading.

Now for the way directly on the string:

int main()
{
std::string newString;
newString.resize(100); // Or whatever size
scanf("%s", newString.data());

std::cout << newString << '\n';

return 0;
}

Although this will of course only read until the next space. So if you want to read a whole line, you would be better off with:

std::string s;
std::getline(std::cin, s);

How to read an input from a file one at a time similar to reading input from console using cin/scanf in c++?

As a first approximation, I'd make the most minimal changes necessary to the code that makes you happy:

std::ifstream infile("filename");

for(int i = 0; i <CLASS_SIZE; i++)
{
for(int j = 0; j <10 ; j++)
{
// scanf("%d", &grade);
infile >> grade;
studentsInClass[i].setGrade(j,grade);
}
}

Given that you know the exact number of grades for each student, you gain little (if anything) from using getline. That would be useful primarily if the input was line-oriented. For example, consider an input file like this:

91 92 85 58 87 75 89 97 79 65 88 
72 81 94 90 61 72 75 68 77
75 49 87 79 65 64 62 51 44 70

As it stands, you still apparently want this read as 3 students with 10 grades apiece, so the last grade on the first line (the 88) belongs to the second student, not the first.

Using getline and then parsing each line individually would make sense if you wanted this input data interpreted as the first student having 11 grades, and the second student 9 grades (and the third 10 grades).


That covers the question you asked, but I'm still not particularly happy about the code. Personally, I'd prefer to write a student class that knew how to read its own data from a stream:

class student { 
std::vector<int> grades;
public:

// other stuff, of course.

friend std::istream &operator>>(std::istream &is, student &s) {
int grade;
for (int i=0; i<10; i++) {
is >> grade;
s.grades.push_back(grade);
}
return is;
}
};

Then when we want to read data for multiple students, we'd do something like this:

std::vector<students> the_class;
std::ifstream infile("grades.txt");

for (int i=0; i<CLASS_SIZE; i++) {
student s;

// use `operator>>` above to read all 10 grades for one student.
infile >> s;
the_class.push_back(s);
}


Related Topics



Leave a reply



Submit