char[] vs std::string: what a C string actually is
Short answer: a C-style string is just a char array with one extra byte at the end holding '\0'. That single convention is why strlen exists, why strcpy can overflow, and why std::string was invented.
The whole story in one picture
char s[6] = "hi"; // 6 slots, but only 3 are meaningful
index: 0 1 2 3 4 5
+-----+-----+-----+-----+-----+-----+
value: | 'h' | 'i' | '\0'| ? | ? | ? |
+-----+-----+-----+-----+-----+-----+
^
the terminator: how every C function knows where text ends
The last three slots are uninitialized garbage; the string ends where '\0' says it does. Nothing stores a length.
Creating and printing
#include <iostream>
using namespace std;
int main() {
char s[20] = "hi";
s[0] = 'H'; // index into it like any array
cout << s << endl; // Hi
char empty[20]; // uninitialized: no terminator yet!
empty[0] = 'o';
empty[1] = 'k';
empty[2] = '\0'; // now it is a valid string
cout << empty << endl;
return 0;
}
Forgetting the terminator is the number-one C-string bug: printing an array without one walks past your data until it happens to hit a zero byte.
strlen, strcpy — and why they exist
#include <iostream>
#include <cstring>
using namespace std;
int main() {
char src[20] = "copy me";
char dst[20];
strcpy(dst, src); // copy, including the '\0'
cout << dst << endl;
cout << "length = " << strlen(dst) << endl; // 7, terminator not counted
cout << "sizeof dst = " << sizeof(dst) << endl; // 20: array size, not text length
return 0;
}
The pair strlen (7) and sizeof (20) is a favorite interview trap: one measures text, the other the box.
Why strcpy is dangerous
char small[5];
char big[] = "this is much longer than five";
strcpy(small, big); // writes past the end — undefined behavior
strcpy copies until it sees '\0' and does not know your array's size. That is a buffer overflow, and it is how a huge share of security bugs were born. The guarded version is strncpy (or better: don't use C strings).
What std::string changes
#include <string>
std::string s = "hi";
s[0] = 'H'; // still indexable
s += " there"; // grows — no size to manage
std::cout << s.size(); // always knows its own length
std::cout << s.substr(0, 2); // operations instead of convention
std::string owns its memory, grows automatically, and carries its length. No terminator to forget, no overflow from a fixed buffer, no strlen call to find the end.
Side-by-side
char[] (C string) | std::string | |
|---|---|---|
| Length | found by scanning for '\0' | stored, .size() |
| Size | fixed at declaration | grows and shrinks |
| Copy | strcpy (can overflow) | = (safe) |
| Concatenate | strcat (can overflow) | += |
| Compare | strcmp (not ==) | == works |
| Read a line | cin.getline(s, n) | getline(cin, s) |
The trap that bites beginners
#include <iostream>
using namespace std;
int main() {
char a[10] = "abc";
char b[10] = "abc";
// This compares *addresses*, not text. Always false (or worse)!
cout << "a == b ? " << (a == b) << endl;
// Character-by-character comparison is what you actually mean:
bool same = true;
for (int i = 0; a[i] != '\0' || b[i] != '\0'; i++) {
if (a[i] != b[i]) { same = false; break; }
}
cout << "same text? " << same << endl;
return 0;
}
With std::string, a == b does the right thing. With arrays, == compares the array's address to itself — almost always the wrong question.
Reading input with spaces
#include <iostream>
using namespace std;
int main() {
char line[50];
cin.getline(line, 50); // whole line, spaces included
cout << "[" << line << "]" << endl;
return 0;
}
Remember cin >> s stops at the first space. getline takes the rest of the line — and beware the leftover newline if you mixed the two (see cin vs getline).
Which should you use?
- Learning or competitive problems: many judges and old textbooks use C strings. Know them — and know their limits.
- Any real C++ code:
std::string. It is safer, it grows, and it reads better. - Interfacing with C libraries:
std::string::c_str()when a function demandsconst char*.
Practice it
- Reverse a String — index backwards with
strlen. - Count the Vowels — walk the array until
'\0'. - Palindrome Number — the numeric cousin of string reversal.
Related: data types (why char is a small number), cin vs getline, vector vs array.