01 C++ vs C & Core Basics
Overview: The Shift from C to C++
While C++ began as “C with Classes”, it has evolved into a multi-paradigm language. Understanding C++ requires moving from C’s implicit conversions and loose scoping toward strict compile-time type safety and clear namespace boundaries.
1. The Entry Point: main and command-line arguments
In both C and C++, the execution of a program starts with the global function main.
int main(int argc, char** argv) {
return 0; // 0 indicates success status
}Under the Hood:
argc(Argument Count): An integer representing the number of items passed via the command line. It is always at least 1, as the first argument (argv[0]) is the executable name/path.argv(Argument Vector): A pointer to an array of null-terminated C-style strings (char*).- Memory Layout:
argv ---> [ argv[0] ] ---> "/path/to/exec\0" [ argv[1] ] ---> "arg1\0" [ argv[2] ] ---> "arg2\0" [ nullptr ] - Exit Status: The return value is passed back to the operating system shell. Returning
0signifies successful termination, whereas non-zero values (like1or-1) indicate specific error states.
2. Character Literal Type Difference: sizeof('c')
A classic trivia question with profound design implications:
- In C:
sizeof('c') == sizeof(int)(typically 4 bytes). - In C++:
sizeof('c') == sizeof(char)(exactly 1 byte).
Why the difference?
- C History: In early C (K&R), character literals were treated as integers. Functions without prototypes automatically promoted
charparameters tointduring stack frame setup. - C++ Overload Resolution: C++ supports function overloading. If
'c'were anint, callingprint('c')would ambiguously matchprint(int)instead ofprint(char). C++ enforced character literals to be truechartypes to guarantee correct overloaded function matching at compile time.
3. Strict Function Prototyping
How empty parameter lists are interpreted depends on the compiler mode:
void func(); - In C: This means a function accepting an unknown, unspecified number of arguments of arbitrary types. To declare a function that takes absolutely zero arguments in C, you must write
void func(void). - In C++: This explicitly means a function that takes zero arguments (identical to
void func(void)).
Why?
C++ requires the compiler to verify function calls against exact parameter signatures at compile time to perform function overloading and type safety checks. Allowing arbitrary parameters without signatures would break compiler checks.
4. Pointer Safety: nullptr vs. NULL / 0
C++11 introduced the keyword nullptr to replace the traditional macro NULL or literal 0.
// The Problem:
void print(int val);
void print(int* ptr);
print(NULL); // Ambiguity! NULL is macro-defined as 0, matching print(int).
print(nullptr); // Correctly matches print(int*)How nullptr works:
nullptris a strongly-typed literal of typestd::nullptr_t.- It can be implicitly converted to any raw pointer type (
char*,int*,MyClass*) or member-pointer type. - It cannot be implicitly converted or promoted to integer types (like
intorlong), completely avoiding function overload selection errors.
5. Standard Wrapper Headers
C++ provides standard wrapper headers for C libraries:
#include <cstdio> // C++ Version (Preferred)
#include <stdio.h> // C VersionThe Difference:
<stdio.h>: Places all function names (likeprintf,scanf) directly in the global namespace. This risks name collisions in larger codebases.<cstdio>: Places these functions inside thestdnamespace (e.g.std::printf). This prevents global namespace pollution, keeping your scope clean.
💻 Conceptual Code Demonstration
#include <cstdio> // Imports std::printf into the 'std' namespace
void printType(int x) {
std::printf("Called printType(int) with value: %d\n", x);
}
void printType(char x) {
std::printf("Called printType(char) with char: %c\n", x);
}
void printType(int* ptr) {
if (ptr == nullptr) {
std::printf("Called printType(int*) with a null pointer!\n");
}
}
int main() {
// 1. Literal Character Size Demonstration
std::printf("sizeof('a') in C++: %zu\n", sizeof('a')); // Outputs 1, not 4
// 2. Overload Resolution matching
printType('a'); // Calls printType(char) because char literals are char-type
printType(10); // Calls printType(int)
// 3. Nullptr safety
// printType(NULL); // ERROR: ambiguous call if NULL compiles as 0
printType(nullptr); // Safely resolves to printType(int*)
return 0;
}