1. C++ Basics
- 1. C++ Basics
- 1. Introduction to C++
- 2. Basic Syntaxes
- 3. Variables and Types
- 7. Strings
- 9. Arrays
- 10.10 Generating Random Numbers
- 一个神奇的指针传参方式↓
- 11. File Input/Output (Header )
- 12. Namespace
This chapter explains the features, technical details and syntaxes of the C++ programming language.
To be a proficient programmer, you need to master two things:
(1) the syntax of the programming language, and
(2) the core libraries (i.e., API) associated with the language.
英文单词记录
- procedural-oriented 面向过程
- object-oriented(OO) 面向对象
- generic programming 泛型编程:一种计算机编程风格,其中算法是以待指定的类型编写的,当需要为特定类型提供参数时,这些类型会被实例化。
- STL(Standard Template Library) 标准模板库
- Pitfall 隐患
- entity 实体/统一体
- identifier 标识符
- underscore 下划线
- Convention 公约
- prudently 慎重
技巧记录
- it is really not meant for dummies.
- 这可不是给傻瓜玩的。
- C++ Standards
- 'bool valid = false;'
- 'bool gameOver = false;'
1. Introduction to C++
C++ is standardized as ISO/IEC 14882. Currently, there are many versions.
C++ Features
- C++ is C.
- C++ supports (almost) all the features of C.
- Like C, C++ allows programmers to manage the memory directly.
- C++ is OO.
- C++ enhances the procedural-oriented C language with the object-oriented extension.
- Template C++.
- C++ introduces generic programming, via the so-called template. You can apply the same algorithm to different data types.
- STL.
- C++ provides a huge set of reusable standard libraries, in particular, the Standard Template Library (STL).
C++ Strength and Pitfall
C++ is a powerful language for high-performance applications, including writing operating systems and their subsystems, games and animation.
C++ is also a complex and difficult programming language, which is really not meant for dummies.
C++ is performance centric. The C++ compiler does not issue warning/error message for many obvious programming mistakes, undefined and unspecified behaviors, such as array index out of range, using an uninitialized variable, etc, due to the focus on performance and efficiency rather than the ease of use - it assumes that those who choose to program in C++ are not dummies.
2. Basic Syntaxes
英文单词记录
- closing brace 后大括号
- semicolon 分号
- Token 文本中的最小单位,如 字/词/符号 等等
- i.e.(“that is” , "in other words")
- semi-colon (
;
) 分号- period(
.
) 句号- decimal point (
.
) 小数点- contiguous 连续的
- Indentation 缩进
技巧记录
- Use comments liberally.
- Use extra whitespaces and newlines liberally.
2.1 Revision
std
The names cout
and endl
belong to the std
namespace.
They can be referenced via fully qualified name std::cout
and std::endl
, or simply as cout
and endl
with a "using namespace std;"
statement.
return 0
C++ compiler will automatically insert a "return 0;
" at the end of the the main()
function, thus, it statement can be omitted.
Instead of using numeric value of zero and non-zero, you can also use
EXIT_SUCCESS
orEXIT_FAILURE
, which is defined in thecstdlib
header (i.e., you need to "#include <cstdlib>
".
2.3 Statements and Blocks
Statement
A programming statement is the smallest independent unit in a program.
It performs a piece of programming action.
Why not ends with a period like an english sentence?
This is because period crashes with decimal point - it is hard for the dumb computer to differentiate between period and decimal point!
Block
A block (or a compound statement) is a group of statements surrounded by braces { }
.
All the statements inside the block is treated as one unit.
Blocks are used as the body in constructs like function, if-else and loop, which may contain multiple statements but are treated as one unit.
There is no need to put a semi-colon after the closing brace to end a complex statement.
Empty block (without any statement) is permitted.
2.4 White Spaces and Formatting Source Codes
White Spaces
Blank, tab and new-line are collectively called white spaces.
C++, like most of the computing languages, ignores extra white spaces. That is, multiple contiguous white spaces are treated as a single white space.
3. Variables and Types
英文单词记录
- LHS left-hand-side
- rvalue right-value
- intuitive 直觉的
3.2 Identifiers
An identifier is needed to name a variable (or any other entity such as a function or a class).
Identifiers beginning with an underscore are typically reserved for system use.
Variable Naming Convention
The first word is in lowercase, while the remaining words are initial-capitalized, with no spaces between words.
his convention is also known as camel-case.(骆驼式命名法)
Recommendations
- Do NOT use meaningless names like
a
,b
,c
,d
,i
,j
,k
,i1
,j99
. - Avoid single-alphabet names, which is easier to type but often meaningless, unless they are common names like
x
,y
,z
for coordinates,i
for index. - It is perfectly okay to use long names of says 30 characters to make sure that the name accurately reflects its meaning!
- Use singular and plural nouns prudently to differentiate between singular and plural variables.
3.3 Variable Declaration
C++ is a "strongly-type" language. A variable takes on only one type. Once the type of a variable is declared, it can only store a value belonging to this particular type.
The concept of type was introduced into the early programming languages to simplify interpretation of data made up of 0s and 1s. Knowing the type of a piece of data greatly simplifies its interpretation and processing.
It is recommended that your declare a variable just before it is first used.
declare vs initialize
surely.
Uninitialized Variables
When a variable is declared, it contains garbage until you assign an initial value. It is important to take note that C/C++ does not issue any warning/error if you use a variable before initialize it - which certainly leads to some unexpected results.
3.4 Constants (const)
const
must be initialized during declaration
Constant Naming Convention
Use uppercase words, joined with underscore. For example, MIN_VALUE
, MAX_SIZE
.
3.6 Assignment (=)
The symbol "=
" is known as the assignment operator.
It denotes assignment instead of equality.
3.7 Fundamental Types
Integers
char
, short
, int
, long
, long long
in a non-decreasing order of size.
The actual size depends on the implementation.
Characters
char
could be signed
or unsigned
, depending on the implementation
You can use signed char
or unsigned char
to explicitly declare signed
or unsigned char
.
Floating-point Numbers
float
, double
and long double
, for single, double and long double precision floating point numbers.
A float
can represent a number between ±1.40239846×10^-45
and ±3.40282347×10^38
, approximated. A double
can represented a number between ±4.94065645841246544×10^-324
and ±1.79769313486231570×10^308
, approximated.
Take note that not all real numbers can be represented by float
and double
, because there are infinite real numbers. Most of the values are approximated.
Boolean Numbers
A special type called bool
(for boolean), which takes a value of either true
or false
.
In addition, many C++ library functions use a type called size_t
, which is equivalent (typedef
) to a unsigned int
, meant for counting, size or length, with 0 and positive integers.
*The sizeof Operator
sizeof(char) is 1 bytes
sizeof(short) is 2 bytes
sizeof(int) is 4 bytes
sizeof(long) is 4 bytes
sizeof(long long) is 8 bytes
sizeof(float) is 4 bytes
sizeof(double) is 8 bytes
sizeof(long double) is 12 bytes
sizeof(bool) is 1 bytes
The results may vary among different systems.
*Header
The climits
header (ported to C++ from C's limits.h
) contains information about limits of integer type. For example,
/* Test integer limits in <climits> header */
#include <iostream>
#include <climits> // integer limits
using namespace std;
int main() {
cout << "int max = " << INT_MAX << endl;
cout << "int min = " << INT_MIN << endl;
cout << "unsigned int max = " << UINT_MAX << endl;
cout << "long long max = " << LLONG_MAX << endl;
cout << "long long min = " << LLONG_MIN << endl;
cout << "unsigned long long max = " << ULLONG_MAX << endl;
cout << "Bits in char = " << CHAR_BIT << endl;
cout << "char max = " << CHAR_MAX << endl;
cout << "char min = " << CHAR_MIN << endl;
cout << "signed char max = " << SCHAR_MAX << endl;
cout << "signed char min = " << SCHAR_MIN << endl;
cout << "unsigned char max = " << UCHAR_MAX << endl;
return 0;
}
int max = 2147483647
int min = -2147483648
unsigned int max = 4294967295
long long max = 9223372036854775807
long long min = -9223372036854775808
unsigned long long max = 18446744073709551615
Bits in char = 8
char max = 127
char min = -128
signed char max = 127
signed char min = -128
unsigned char max = 255
Again, the outputs depend on the system.
Header <cfloat>
Similarly.
Header <limits>
The climits
and cfloat
headers are ported over from C's limit.h
and float.h
. C++ added a new header called limits
.
*The typedef Statement
Many C/C++ compilers define a type called size_t
, which is a typedef
of unsigned int
.
4.7 Implicit Type-Conversion vs. Explicit Type-Casting
Converting a value from one type to another type is called type casting (or type conversion). There are two kinds of type casting:
- Implicit type-conversion performed by the compiler automatically,
- Explicit type-casting via an unary type-casting operator in the form of
(*new-type*)*operand*
or*new-type*(*operand*)
.
C++ will not perform automatic type conversion, if the two types are not compatible.
注意不是四舍五入,而是截断
Operator static-cast<type>
C++ introduces a new operator called static_cast<*type*>
to perform type conversion (because the regular cast mentioned earlier is too lax and could produce expected results). static_cast
signal an error if conversion fails. For example,
double d = 5.5;
int i = static_cast<int>(d);
float f = static_cast<float>(i);
long l = static_cast<logn>(d);
5.5 Terminating Program
exit()
You could invoke the function exit(int exitCode)
, in <cstdlib>
(ported from C's "stdlib.h
"), to terminate the program and return the control to the Operating System. By convention, return code of zero indicates normal termination; while a non-zero exitCode
(-1) indicates abnormal termination. For example,
abort()
The header <cstdlib>
also provide a function called abort()
, which can be used to terminate the program abnormally.
The "return" Statement
You could also use a "return *returnValue*
" statement in the main()
function to terminate the program and return control back to the Operating System. For example,
if (errorCount > 10) {
cout << "too many errors" << endl;
exit(-1); // Terminate the program
// OR abort();
//return -1; // Terminate and return control to OS from main()
//终止并将控制权从main()返回给操作系统
}
5.7 Dangling else
if (i == 0)
if (j == 0)
cout << "i and j are zero" << endl;
else cout << "i is not zero" << endl; // intend for the outer-if
The else
clause in the above codes is syntactically applicable to both the outer-if and the inner-if. The C++ compiler always associate the else
clause with the innermost if (i.e., the nearest if).
7. Strings
C++ supports two types of strings:
- the original C-style string: A string is a
char
array, terminated with aNULL
character'\0'
(Hex0
). It is also called Character-String or C-style string. - the new
string
class introduced in C++98.
The "high-level" string
class is recommended, because it is much easier to use and understood. However, many legacy programs used C-strings; many programmers also use "low-level" C-strings for full control and efficiency; furthermore, in some situation such as command-line arguments, only C-strings are supported.
Hence, you may have to understand both sets of strings. However, avoid C-string unless it is absolutely necessary.
7.1 String Declaration and Initialization
To use the string
class, include the <string>
header and "using namespace std
".
#include <string>
using namespace std;
string str1("Hello"); // Initialize with a string literal (Implicit initialization)
string str2 = "world"; // Initialize with a string literal (Explicit initialization via assignment operator)
string str3; // Initialize to an empty string
string str4(str1); // Initialize by copying from an existing string object
7.2 String Input/Output
- We need to "
#include <string>
" to use thestring
class, and "using namespace std
" asstring
is defined understd
namespace. - "
cin >> *aStr*
" reads a word (delimited by space) fromcin
(keyboard), and assigns tostring
variable*aStr*
. getline(cin, *aStr*)
reads the entire line (up to'\n'
) fromcin
, and assigns to*aStr*
. The'\n'
character is discarded.- To flush
cin
, you could useignore(numeric_limits<streamsize>::max(), '\n')
function to discard all the characters up to'\n'
.numeric_limits
is in the<limits>
header.
7.3 String Operations
调用形式得先调用对象,用
.
连接,如str1.function()
-
Checking the length of a string:
-
Check for empty string:
-
Copying from another string: Simply use the assignment (=) operator.
-
Concatenated with another string: Use the plus (+) operator, or compound plus (+=) operator.
string str1("Hello,"); string str2(" world"); cout << str1 + str2 << endl; // "Hello, world" cout << str1 << endl; // "Hello," cout << str2 << endl; // " world" str1 += str2; cout << str1 << endl; // "Hello, world" cout << str2 << endl; // " world" string str3 = str1 + str2; cout << str3 << endl; // "Hello, world world" str3 += "again"; cout << str3 << endl; // "Hello, world worldagain"
-
Read/Write individual character of a string:
-
Extracting sub-string:
-
Comparing with another string:
int compare(string another); // Compare the content of this string with the given another. // Return 0 if equals; a negative value if this string is less than another; positive value otherwise. == and != Operators // Compare the contents of two strings
string str1("Hello"), str2("Hallo"), str3("hello"), str4("Hello"); cout << str1.compare(str2) << endl; // 1 'e' > 'a' cout << str1.compare(str3) << endl; // -1 'h' < 'H' cout << str1.compare(str4) << endl; // 0 // You can also use the operator == or != if (str1 == str2) cout << "Same" << endl; if (str3 != str4) cout << "Different" << endl; cout << boolalpha; // print bool as true/false cout << (str1 != str2) << endl; cout << (str1 == str4) << endl;
-
Search/Replacing characters:
- Many others.
/* Example on C++ string function (TestStringOp.cpp) */
#include <iostream>
#include <string> // use string class
using namespace std;
int main() {
string msg = "hello, world!";
cout << msg << endl;
cout << msg.length() << endl; // length of string
cout << msg.at(1) << endl; // char at index 1
cout << msg[1] << endl; // same as above
cout << msg.empty() << endl; // test for empty string
cout << msg.substr(3, 3) << endl; // sub-string begins at
// pos 3 of size 3
cout << msg.replace(3, 3, "why") << endl; // replace sub-string
cout << msg.append("end") << endl; // append behind
cout << msg + "end" << endl; // same as above
cout << msg.insert(3, "insert") << endl; // insert after pos 3
string msg1;
msg1 = msg; // copy
cout << msg1 << endl;
cout << "Enter a line: ";
getline(cin, msg); // read a line of input
cout << msg << endl;
}
8. Formatting Input/Output using IO Manipulators (Header <iomanip>)
8.1 Output Formatting
/* Test Formatting Output (TestFormattedOutput.cpp) */
#include <iostream>
#include <iomanip> // Needed to do formatted I/O
using namespace std;
int main() {
// Floating point numbers
double pi = 3.14159265;
cout << fixed << setprecision(4); // fixed format with 4 decimal places
cout << pi << endl;
cout << "|" << setw(8) << pi << "|" << setw(10) << pi << "|" << endl;
// setw() is not sticky, only apply to the next operation.
cout << setfill('-');
cout << "|" << setw(8) << pi << "|" << setw(10) << pi << "|" << endl;
cout << scientific; // in scientific format with exponent
cout << pi << endl;
// booleans
bool done = false;
cout << done << endl; // print 0 (for false) or 1 (for true)
cout << boolalpha; // print true or false
cout << done << endl;
return 0;
}
8.2 Input Formatting
cp/* Test Formatting Input (TestFormattedInput.cpp) */
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main() {
string areaCode, phoneCode;
string inStr;
cout << "Enter your phone number in this format (xxx)xxx-xxxx : ";
cin.ignore(); // skip '('
cin >> setw(3) >> areaCode;
cin.ignore(); // skip ')'
cin >> setw(3) >> phoneCode;
cin.ignore(); // skip '-'
cin >> setw(4) >> inStr;
phoneCode += inStr;
cout << "Phone number is (" << areaCode << ")"
<< phoneCode.substr(0, 3) << "-"
<< phoneCode.substr(3, 4) << endl;
return 0;
}
9. Arrays
9.1 Array Declaration and Usage
int main() {
int const SIZE = 5;
int a1[SIZE]; // Uninitialized
for (int i = 0; i < SIZE; ++i) cout << a1[i] << " ";
cout << endl; // ? ? ? ? ?
int a2[SIZE] = {21, 22, 23, 24, 25}; // All elements initialized
for (int i = 0; i < SIZE; ++i) cout << a2[i] << " ";
cout << endl; // 21 22 23 24 25
int a3[] = {31, 32, 33, 34, 35}; // Size deduced from init values
int a3Size = sizeof(a3)/sizeof(int);
cout << "Size is " << a3Size << endl; // 5
for (int i = 0; i < a3Size; ++i) cout << a3[i] << " ";
cout << endl; // 31 32 33 34 35
int a4[SIZE] = {41, 42}; // Leading elements initialized, the rests to 0
for (int i = 0; i < SIZE; ++i) cout << a4[i] << " ";
cout << endl; // 41 42 0 0 0
int a5[SIZE] = {0}; // First elements to 0, the rests to 0 too
for (int i = 0; i < SIZE; ++i) cout << a5[i] << " ";
cout << endl; // 0 0 0 0 0
int a6[SIZE] = {}; // All elements to 0 too
for (int i = 0; i < SIZE; ++i) cout << a6[i] << " ";
cout << endl; // 0 0 0 0 0
}
C/C++ does not perform array index-bound check. In other words, if the index is beyond the array's bounds, it does not issue a warning/error. For example,
const int size = 5;
int numbers[size]; // array index from 0 to 4
// Index out of bound!
// Can compiled and run, but could pose very serious side effect!
numbers[88] = 999;
cout << numbers[77] << endl;
9.3 Range-based for loop (C++11)
/* Testing For-each loop (TestForEach.cpp) */
#include <iostream>
using namespace std;
int main() {
int numbers[] = {11, 22, 33, 44, 55};
// For each member called number of array numbers - read only
for (int number : numbers) {
cout << number << endl;
}
// To modify members, need to use reference (&)
for (int &number : numbers) {
number = 99;
}
for (int number : numbers) {
cout << number << endl;
}
return 0;
}
9.5 Array of Characters - C-String
/* Test C-string (TestCString.cpp) */
#include <iostream>
using namespace std;
int main() {
char msg[256]; // Hold a string of up to 255 characters (terminated by '\0')
cout << "Enter a message (with space)" << endl;
cin.getline(msg, 256); // Read up to 255 characters into msg
cout << msg << endl;
// Access via null-terminated character array
for (int i = 0; msg[i] != '\0'; ++i) {
cout << msg[i];
}
cout << endl;
cout << "Enter a word (without space)" << endl;
cin >> msg;
cout << msg << endl;
// Access via null-terminated character array
for (int i = 0; msg[i] != '\0'; ++i) {
cout << msg[i];
}
cout << endl;
return 0;
}
10.3 Default Arguments
C++ introduces so-called default arguments for functions. These default values would be used if the caller omits the corresponding actual argument in calling the function.
/* Test Function default arguments (functionDefaultArgument.cpp) */
#include <iostream>
using namespace std;
// Function prototype - Specify the default arguments here
int fun1(int = 1, int = 2, int = 3);
int fun2(int, int, int = 3);
int main() {
cout << fun1(4, 5, 6) << endl; // No default
cout << fun1(4, 5) << endl; // 4, 5, 3(default)
cout << fun1(4) << endl; // 4, 2(default), 3(default)
cout << fun1() << endl; // 1(default), 2(default), 3(default)
cout << fun2(4, 5, 6) << endl; // No default
cout << fun2(4, 5) << endl; // 4, 5, 3(default)
// cout << fun2(4) << endl;
// error: too few arguments to function 'int fun2(int, int, int)'
}
int fun1(int n1, int n2, int n3) {
// cannot repeat default arguments in function definition
return n1 + n2 + n3;
}
int fun2(int n1, int n2, int n3) {
return n1 + n2 + n3;
}
10.4 Function Overloading
C++ introduces function overloading (or function polymorphism, which means many forms), which allows you to have multiple versions of the same function name, differentiated by the parameter list (number, type or order of parameters).
The version matches the caller's argument list will be selected for execution.
Overloaded functions cannot be differentiated by the return-type (compilation error).
/* Test Function Overloading (FunctionOverloading.cpp) */
#include <iostream>
using namespace std;
void fun(int, int, int); // Version 1
void fun(double, int); // Version 2
void fun(int, double); // Version 3
int main() {
fun(1, 2, 3); // version 1
fun(1.0, 2); // version 2
fun(1, 2.0); // version 3
fun(1.1, 2, 3); // version 1 - double 1.1 casted to int 1 (without warning)
// fun(1, 2, 3, 4);
// error: no matching function for call to 'fun(int, int, int, int)'
// fun(1, 2);
// error: call of overloaded 'fun(int, int)' is ambiguous
// note: candidates are:
// void fun(double, int)
// void fun(int, double)
// fun(1.0, 2.0);
// error: call of overloaded 'fun(double, double)' is ambiguous
}
void fun(int n1, int n2, int n3) { // version 1
cout << "version 1" << endl;
}
void fun(double n1, int n2) { // version 2
cout << "version 2" << endl;
}
void fun(int n1, double n2) { // version 3
cout << "version 3" << endl;
}
C/C++ does not allow functions to return an array.
10.10 Generating Random Numbers
The cstdlib
header (ported from C's stdlib.h
) provides a function rand()
, which generates a pseudo-random integral number between 0 and RAND_MAX
(inclusive).
RAND_MAX
is a constant defined in cstdlib
(typically the maximum value of 16-/32-bit signed integer, such as 32767).
You can generate a random number between [0,n)
via rand() % n
.
rand()
generates the same squence of pseudo-random numbers on different invocations.
The cstblib
also provides a srand()
function to seed or initialize the random number generator. We typically seed it with the current time obtained via time(0)
function (in <ctime>
header), which returns the number of seconds since January 1st, 1970.
一个神奇的指针传参方式↓
#include <iostream>
using namespace std;
void squareByReference (int & number); // Pass-by-reference
int main() {
int n2 = 9;
squareByReference(n2); // side-effect
}
void squareByReference (int & number) {
number = number * number;
}
11. File Input/Output (Header )
The <fstream>
header provides ifstream
(input file stream) and ofstream
(output file stream) for file input and output. The steps for file input/output are:
- Create a
ifstream
for input, orofstream
for output. - Connect the stream to an input or output file via
open(*filename*)
. - Perform formatted output via stream insertion operator
<<
, or input via stream extraction operator>>
, similar tocout <<
andcin >>
. - Close the file and free the stream.
/* Test File I/O (TestFileIO.cpp)
Read all the integers from an input file and
write the average to an output file */
#include <iostream>
#include <fstream> // file stream
#include <cstdlib>
using namespace std;
int main() {
ifstream fin; // Input stream
ofstream fout; // Output stream
// Try opening the input file
fin.open("in.txt");
if (!fin.is_open()) {
cerr << "error: open input file failed" << endl;
abort(); // Abnormally terminate the program (in <cstdlib>)
}
int sum = 0, number, count = 0;
while (!(fin.eof())) {
// Use >> to read
fin >> number;
sum += number;
++count;
}
double average = double(sum) / count;
cout << "Count = " << count << " average = " << average << endl;
fin.close();
// Try opening the output file
fout.open("out.txt");
if (!fout.is_open()) {
cerr << "error: open output file failed" << endl;
abort();
}
// Write the average to the output file using <<
fout << average;
fout.close();
return 0;
}
12. Namespace
all the identifiers in the C++ standard libraries (such as cout
, endl
and string
) are placed under the namespace called std
.
To reference an identifier under a namespace, you have three options:
- Use the fully qualified names, such as
std::cout
,std::endl
,std::setw()
andstd::string
. For example,
Missing the "std::
" results in "error: 'xxx' was not declared in this scope".
- Use a using declaration to declare the particular identifiers. For example,
You can omit the "std::
" for cout
and endl
, but you still have to use "std::
" for setw
.
- Use a using namespace directive. For example,
The using namespace
directive effectively brings all the identifiers from the specified namespace to the global scope, as if they are available globally. You can reference them without the scope resolution operator. Take note that the using namespace
directive may result in name crashes with identifier in the global scope.
- For long namespace name, you could define a shorthand (or alias) to the namespace, as follows:
You can now refer to your class as *shorthand*::*entityName*
.
这语句还可以放在函数内以限制作用域