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
andstd::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
Isn't the Const Modifier Here Unnecessary
How to Initialize Std::Vector Over Already Allocated Memory
Acquire/Release Semantics with Non-Temporal Stores on X64
Vector That Can Have 3 Different Data Types C++
Sfinae Works Differently in Cases of Type and Non-Type Template Parameters
Do Class Functions/Variables Have to Be Declared Before Being Used
Virtual Tables and Memory Layout in Multiple Virtual Inheritance
The Behaviour of Floating Point Division by Zero
Will C++ Exceptions Safely Propagate Through C Code
What Happens When You Close a C++ Console Application
Rationale of Enforcing Some Operators to Be Members
Overloaded Functions Are Hidden in Derived Class
Can Someone Please Explain the "Indices Trick"
Using Std::Bind with Member Function, Use Object Pointer or Not for This Argument