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,- trueand- falseare built-in. No need to- #include <stdbool.h>.- trueand- falseare of type- bool, not- int.
- 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 >> xreturns- std::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 object- s1 + s2(so that the contents of- s1are copied), and then assigns it to- s1.
- s1 += s2appends- s2directly to the end of- s1, without copying- s1.
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 whether- sis 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
