C++中使用scanf读取std::string时程序结果不符合预期,是否是scanf的问题?
Hey there! You were spot-on about the issue being tied to using scanf with std::string — let's break down exactly what's wrong and how to fix your code.
scanf Doesn't Play Nice with std::string When you call s.c_str() on an empty std::string, it returns a read-only const char* pointing to an empty buffer (or unallocated memory, depending on the implementation). Using scanf("%s", s.c_str()) tries to write data into this read-only/underallocated space, which is undefined behavior. This can cause crashes, garbage output, or totally unpredictable results — exactly what you're seeing.
On top of that, std::string::find() returns a size_t (an unsigned integer type), not -1. Comparing -1 (a signed value) to an unsigned size_t will lead to weird logic errors even if you fix the input issue.
Fix 1: Use C++'s cin (The Cleanest Approach)
cin is designed to work seamlessly with std::string — it handles memory allocation automatically, so you don't have to worry about buffer sizes or read-only pointers. Here's your revised code:
#include <iostream> #include <string> using namespace std; int main(){ string s, t; cin >> s >> t; // Let cin handle the string reading size_t match_pos = s.find(t); while(match_pos != string::npos){ // Use string::npos instead of -1 s.erase(match_pos, t.length()); match_pos = s.find(t); } cout << s << endl; return 0; }
Note that string::npos is the official way to check if find() failed — it's a special value defined for exactly this purpose.
Fix 2: Stick with scanf (If You Really Need To)
If you have to use scanf for some reason, you need to pre-allocate space in the std::string first, then use a writable pointer to that space. C++11 and later guarantee that std::string stores characters in a contiguous buffer, so &s[0] gives you a valid writable pointer:
#include <cstdio> #include <string> #include <cstring> // For strlen() using namespace std; int main(){ // Pre-allocate enough space for your input (adjust the size as needed) string s(1024, '\0'); string t(1024, '\0'); scanf("%s", &s[0]); scanf("%s", &t[0]); // Trim the extra null characters from the end of the strings s.resize(strlen(s.c_str())); t.resize(strlen(t.c_str())); size_t match_pos = s.find(t); while(match_pos != string::npos){ s.erase(match_pos, t.length()); match_pos = s.find(t); } printf("%s\n", s.c_str()); return 0; }
This works, but it's more verbose and error-prone than using cin.
Bonus: A More Efficient Way to Remove Substrings
If you're working with very long strings, repeatedly calling erase() can be slow (it has to shift characters around in memory every time). Here's a faster approach using a temporary string to build the result in one pass:
#include <iostream> #include <string> using namespace std; int main(){ string s, t; cin >> s >> t; string result; const size_t t_len = t.length(); if(t_len == 0){ // Edge case: empty substring, return original string cout << s << endl; return 0; } size_t pos = 0; while(pos <= s.size() - t_len){ if(s.substr(pos, t_len) == t){ pos += t_len; // Skip over the matched substring } else { result += s[pos]; pos++; } } // Add any remaining characters that didn't match result += s.substr(pos); cout << result << endl; return 0; }
This avoids the repeated memory shifts from erase() and is much more efficient for large inputs.
内容的提问来源于stack exchange,提问作者Randy Gunawan

