CS100 Lecture 11
C++ Introduction, Strings
Contents
- Brief history of C++
- Basic IO
- Standard library
std::string
Brief history of C++
C with Classes
Back to 1979, the Bell Labs: C with Classes was invented by Bjarne Stroustrup.
- An object-oriented C, with the ideas of "class" from Simula (and several other programming languages).
- Based on C, with many improvements: better type checking, better linkage, ...
The development of C++ also influences that of C.
- Today's C has also deprecated the unsafe function declarations, and has adopted better type checking.
The birth of C++
After C with Classes was seen as a "medium success" by Stroustrup, he moved on to make a better new language - C++ (1983).
~~C++ is an object-oriented programming language.~~
C++ is a multi-paradigm programming language that - is a better C, - supports data abstraction, and that - supports object-oriented programming.
Standardization of C++
Standardization: C++98, C++11, C++14, C++17, C++20, C++23, C++26, ...
- C++98: The first ISO standard in 1998.
- C++11: Marks the beginning of modern C++.
- C++14/17: Some slight fixes and improvements of C++11.
- C++20: The first standard that delivers on virtually all the features that Bjarne Stroustrup dreamed of in The Design and Evolution of C++ in 1994.
- "D&E Complete"
CS100 is based on C++17.
Overview of C++
What do embedded systems, game development, high frequency trading, and particle accelerators have in common? - C++, of course!
Effective C++ Item 1 (by Scott Meyers): View C++ as a federation of languages.
The easiest way is to view C++ not as a single language but as a federation of related languages ... Fortunately, there are only four: - C. - Object-Oriented C++. - Template C++. - The STL.
"Better C"
Safer & more reasonable designs.
bool,trueandfalseare built-in. No need to#include <stdbool.h>.trueandfalseare of typebool, notint.- The return type of logical operators
&&,||,!and comparison operators<,<=,>,>=,==,!=isbool, notint. - The type of string literals
"hello"isconst char [N+1], notchar [N+1]. - The type of character literals
'a'ischar, notint.
"Better C"
Safer & more reasonable designs.
- Potentially dangerous type conversions are not allowed to happen implicitly. They are errors, not just warnings.
constvariables initialized with literals are compile-time constants. They can be used as the length of arrays.int fun()declares a function accepting no arguments. It is not accepting unknown arguments.
Basic IO
Hello world
#include <stdio.h>
int main(void) {
printf("Hello world\n");
return 0;
}
#include <iostream>
int main() { // just an empty `()`
std::cout << "Hello world\n";
return 0;
}
Note on the main function: In C++, a function declared with an empty parameter list accepts no arguments, so there is no need to put a void there.
A+B problem
#include <stdio.h>
int main(void) {
int a, b;
scanf("%d%d", &a, &b);
printf("a + b = %d\n", a + b);
return 0;
}
#include <iostream>
int main() {
int a, b;
std::cin >> a >> b;
std::cout << "a + b = " << a + b
<< '\n';
return 0;
}
- For input: There is no need to take the address of
aandb! C++ has a way to obtain the reference of the argument. - There is no need to write
%d! C++ has a way of identifying the type of the argument, and will select the correct way to handle that type.
IOStream: Input and Output Stream
#include <iostream>
int main() {
int a, b;
std::cin >> a >> b;
std::cout << "a + b = " << a + b << '\n';
return 0;
}
std::cin and std::cout: two objects defined in the standard library file <iostream>.
- They are not functions.
- The input and output "functions" are actually the operators
<<and>>, which are overloaded to do something different from bit shifting. - We will learn about operator overloading in later lectures.
IOStream: Input and Output Stream
#include <iostream>
int main() {
int a, b;
std::cin >> a >> b;
std::cout << "a + b = " << a + b << '\n';
return 0;
}
std::cin and std::cout: two objects defined in the standard library file <iostream>.
std::cinstands for standard input stream.std::coutstands for the standard output stream.
IOStream: Input and Output Stream
std::cin >> x: Reads something and stores it in the variable x.
xcan be of any supported type: integers, floating-points, characters, strings, ...- C++ has a way of identifying the type of
xand selecting the correct way to read it. We don't need the annoying"%d","%f", ... anymore. - C++ functions have a way of obtaining the reference of the argument. We don't need to take the address of
x.
IOStream: Input and Output Stream
std::cin >> xreturnsstd::cin, so we can write several reads in a chained way:-
std::cin >> x >> y >> zis equivalent to((std::cin >> x) >> y) >> z, which is equivalent tocpp std::cin >> x; std::cin >> y; std::cin >> z;- Similarly, outputs can also be chained:std::cout << x << y << zis equivalent tocpp std::cout << x; std::cout << y; std::cout << z;
Standard library
Standard library file names
The names of C++ standard library files have no extensions: <iostream> instead of <iostream.h>, <string> instead of <string.h>.
Namespace std
std::cin and std::cout: names from the standard library.
C++ has a large standard library with a lot of names declared.
To avoid name collisions, all the names from the standard library are placed in a namespace named std.
- Example of name collisions in C: Suppose we want to write our own quick-sort:
c
#include <stdlib.h>
void qsort(int *a, int n) { // Ooops! stdlib already has one named `qsort`.
// ...
}
Namespace std
std::cin and std::cout: names from the standard library.
C++ has a large standard library with a lot of names declared.
To avoid name collisions, all the names from the standard library are placed in a namespace named std.
- You can write
using std::cin;to introducestd::cininto the current scope, so thatcincan be used withoutstd::. - You may write
using namespace std;to introduce all the names instdinto the current scope, but you will be at the risk of name collisions again.
Compatibility with C standard library
The C++ standard library has everything from the C standard library, but not exactly the same as in C.
- For some historical issues, C has many awkward designs and weird defaults, some of which are not compatible in C++.
- The C++ version of a C standard library file
<xxx.h>is<cxxx>, with all the names also introduced intonamespace std.
#include <cstdio>
int main() {
int a, b; std::scanf("%d%d", &a, &b);
std::printf("%d\n", a + b);
}
[Best practice] Use <cxxx> instead of <xxx.h> when you need the C standard library in C++.
std::string
Defined in the standard library file <string> (not <string.h>, not <cstring>!!)
The string.
Define and initialize a string
std::string str = "Hello world";
// equivalent: std::string str("Hello world");
// equivalent: std::string str{"Hello world"}; (modern)
std::cout << str << std::endl;
std::string s1(7, 'a');
std::cout << s1 << std::endl; // aaaaaaa
std::string s2 = s1; // s2 is a copy of s1
std::cout << s2 << std::endl; // aaaaaaa
std::string s; // "" (empty string)
Default-initialization of a std::string will produce an empty string, not indeterminate value and has no undefined behaviors!
Strings
- The memory of
std::stringis allocated and deallocated automatically. - We can insert or erase characters in a
std::string. The memory of storage will be adjusted automatically. std::stringdoes not need an explicit'\0'at the end. It has its way of recognizing the end.- When you use
std::string, pay attention to its contents instead of the implementation details.
Length of a string
Member function s.size()
std::string str{"Hello world"};
std::cout << str.size() << std::endl;
Not strlen, not sizeof!!
Member function s.empty()
if (str.empty()) {
// ...
}
Concatenation of strings
Use + and += directly!
- No need to care about the memory allocation.
- No awkward functions like
strcat.
std::string s1 = "Hello";
std::string s2 = "world";
std::string s3 = s1 + ' ' + s2; // "Hello world"
s1 += s2; // s1 becomes "Helloworld"
s2 += "C++string"; // s2 becomes "worldC++string"
Concatenation of strings
At least one operand of + should be std::string.
const char *old_bad_ugly_C_style_string = "hello";
std::string good_beautiful_Cpp_string = "hello";
std::string s1 = good_beautiful_Cpp_string + "aaaaa"; // OK.
std::string s2 = "aaaaa" + good_beautiful_Cpp_string; // OK.
std::string s3 = old_bad_ugly_C_style_string + "aaaaa"; // Error
Is this ok?
std::string hello{"hello"};
std::string s = hello + "world" + "C++";
Concatenation of strings
At least one operand of + should be std::string.
const char *old_bad_ugly_C_style_string = "hello";
std::string good_beautiful_Cpp_string = "hello";
std::string s1 = good_beautiful_Cpp_string + "aaaaa"; // OK.
std::string s2 = "aaaaa" + good_beautiful_Cpp_string; // OK.
std::string s3 = old_bad_ugly_C_style_string + "aaaaa"; // Error
Is this ok?
std::string hello{"hello"};
std::string s = hello + "world" + "C++";
Yes! + is left-associated. (hello + "world") is of type std::string.
Use +=
In C, a = a + b is equivalent to a += b. This is not always true in C++.
For two std::strings s1 and s2, s1 = s1 + s2 is different from s1 += s2.
s1 = s1 + s2constructs a temporary objects1 + s2(so that the contents ofs1are copied), and then assigns it tos1.s1 += s2appendss2directly to the end ofs1, without copyings1.
Try these with n = 1000000:
std::string result;
for (int i = 0; i != n; ++i)
result += 'a'; // Fast
std::string result;
for (int i = 0; i != n; ++i)
result = result + 'a'; // Very slow
Lexicographical comparison of strings
Just use <, <=, >, >=, ==, !=!
- No loops. No weird functions like
strcmp.
Copying a string
Just use =!
std::string s1{"Hello"};
std::string s2{"world"};
s2 = s1; // s2 is a copy of s1
s1 += 'a'; // s2 is still "Hello"
The copy assignment operator of std::string will copy the contents of it.
\(\Rightarrow\) We will learn about copy assignment operators in later lectures.
String IO
Use std::cin >> s and std::cout << s, as simple as handling an integer.
- Does
std::cin >> signore leading whitespaces? Does it read an entire line or just a sequence of non-whitespace characters? Do some experiments on it.
std::getline(std::cin, s): Reads a string starting from the current character, and stops at the first '\n'.
- Is the ending
'\n'consumed? Is it stored? Do some experiments.
Traversing a string: Use range-based for loops.
Example: Print all the uppercase letters in a string.
for (char c : s) // The range-based for loops
if (std::isupper(c)) // in <cctype>
std::cout << c;
std::cout << std::endl;
Equivalent way: Use subscripts, which is verbose and inconvenient.
for (std::size_t i = 0; i != s.size(); ++i)
if (std::isupper(s[i]))
std::cout << s[i];
std::cout << std::endl;
[Best practice] Use range-based for loops. They are modern, clear, simple, generic, and hence more recommended.
\(\Rightarrow\) More about range-based for loops in later lectures.
Conversion between strings and arithmetic numbers
For a number x of any arithmetic type, std::to_string(x) returns a string representing it.
int ival = 42;
double dval = 3.14;
std::string s = std::to_string(ival) + std::to_string(dval);
std::cout << s << '\n'; // Possible output: 423.140000
std::stoi(s), std::stol(s), ...: Extracts the arithmetic value represented by s.
See this list.
Summary
- IO: Use
<iostream>,std::cin >> x >> y,std::cout << x << y. - Namespace
std. - C++ standard library files: names with no extensions.
- Compatible with C, but use
<cxxx>instead of<xxx.h>.
Summary
std::string
- No need for a terminating
'\0'. - Automatic memory management.
s.size()returns the length.s.empty()returns whethersis empty.- Use
+and+=for concatenation. Use<,<=,>,>=,==,!=for comparison. Use=for copying.
Summary
std::string
- Use
>>and<<for IO, as well asstd::getline. - Use
s[i]to access the elements. - Use range-based
forloops to traverse a string. - Use
std::to_stringandstd::stoi,std::stol, ... for numeric conversions. - Full list of functions related to
std::string: https://en.cppreference.com/w/cpp/string/basic_string
