C++字符串拷贝操作报错原因解析:两段代码为何一错一正常
Let's dig into exactly what's going on here—this is a classic case of mixing C-style string habits with C++'s std::string class, which has its own rules for memory management.
The Problem with the "Error-Prone" Code
First, let's break down the key issues in the code using std::string:
#include <iostream> #include <string> #include <conio.h> #include <math.h> #include <iomanip> #include <string.h> using namespace std; int main() { string s1,s2; // s2 starts as EMPTY, no memory allocated yet int i; cout << "Enter the string to copy into another string : "; getline(cin,s1); for(i=0; s1[i]!='\0'; ++i) { s2[i]=s1[i]; // ❌ Undefined behavior! s2 has no space for this } s2[i]='\0'; // ❌ Invalid write, and unnecessary for std::string cout<<"\n\nCopied String S2 is : "<<s2; return 0; }
- Unallocated Memory for
s2: When you declarestring s2;, it initializes as an empty string with a size of 0. Usings2[i]to assign characters directly accesses memory that hasn't been reserved for the string—this is out-of-bounds memory access, which causes undefined behavior (crashes, garbage output, or random runtime errors). Unlike C-style char arrays,std::stringdoesn't pre-allocate space unless explicitly told to. - Unnecessary Null Terminator:
std::stringmanages its length internally; it doesn't rely on a'\0'to know where the string ends. Manually adding this character here is not just useless—it's another invalid memory write ifs2hasn't been resized to fit it.
Why the Second Code Works
Now let's look at the working code using C-style char arrays:
#include <iostream> #include <string> #include <conio.h> #include <math.h> #include <iomanip> #include <string.h> using namespace std; int main() { char s1[100], s2[100], i; // Both arrays have 100 chars of pre-allocated space cout << "Enter the string to copy into another string : "; cin>>s1; for(i=0; s1[i]!='\0'; ++i) { s2[i]=s1[i]; // ✅ Valid: s2 has pre-allocated space to hold these values } s2[i]='\0'; // ✅ Required for C-style strings to mark the end cout<<"\n\nCopied String S2 is : "<<s2; return 0; }
- Pre-Allocated Memory:
char s2[100];reserves 100 bytes of memory immediately. As long as your input string is shorter than 99 characters (leaving space for the null terminator), writing tos2[i]is safe and valid. - Valid Null Terminator: C-style strings depend on
'\0'to signal where the string ends, so adding this character is necessary to ensurecoutprints the string correctly instead of reading past the actual data.
Fixing the Error-Prone Code
If you want to use std::string (the recommended approach for most C++ code), here are a few clean, safe ways to handle the copy:
The Simplest Way: Direct Assignment
std::stringhas a built-in assignment operator that handles all memory management automatically:#include <iostream> #include <string> using namespace std; int main() { string s1,s2; cout << "Enter the string to copy into another string : "; getline(cin,s1); s2 = s1; // 🚀 Easy, safe, and idiomatic C++ cout<<"\n\nCopied String S2 is : "<<s2; return 0; }Manual Loop (For Learning Purposes)
If you want to copy characters one by one, first allocate space fors2:#include <iostream> #include <string> using namespace std; int main() { string s1,s2; cout << "Enter the string to copy into another string : "; getline(cin,s1); s2.resize(s1.size()); // Allocate space equal to s1's length for(int i=0; i<s1.size(); ++i) { s2[i] = s1[i]; } // No need for '\0'—std::string handles this internally cout<<"\n\nCopied String S2 is : "<<s2; return 0; }Use Standard Library Algorithm
You can also usestd::copyfrom the<algorithm>header:#include <iostream> #include <string> #include <algorithm> using namespace std; int main() { string s1,s2; cout << "Enter the string to copy into another string : "; getline(cin,s1); s2.reserve(s1.size()); // Reserve space to avoid unnecessary reallocations copy(s1.begin(), s1.end(), back_inserter(s2)); cout<<"\n\nCopied String S2 is : "<<s2; return 0; }
内容的提问来源于stack exchange,提问作者Omkar Arora

