314 lines
17 KiB
Markdown
314 lines
17 KiB
Markdown
# Lecture 1 --- Introduction to C++, STL, Strings
|
||
|
||
- Brief Discussion of Website & Syllabus
|
||
- Crash Course in C++ Syntax
|
||
- Getting Started in C++ & STL, C++ Syntax, STL Strings
|
||
|
||
## 1.1 Transitioning from Python to C++ (from CSCI-1100 Computer Science 1)
|
||
|
||
- Python is a great language to learn the power and flexibility of programming and computational problem solving. This semester we will work in C++ and study lower level programming concepts, focusing on details including efficiency and memory usage.
|
||
- Outside of this class, when working on large programming projects, you will find it is not uncommon to use a mix of programming languages and libraries. The individual advantages of Python and C++ (and Java, and Perl, and C, and UNIX bash scripts, and ... ) can be combined into an elegant (or terrifyingly complex) masterpiece.
|
||
|
||
## 1.2 Compiled Languages vs. Interpreted Languages
|
||
|
||
- C/C++ is a *compiled language*, which means your code is processed
|
||
(compiled & linked) to produce a low-level machine language
|
||
executable that can be run on your specific hardware. You must
|
||
re-compile & re-link after you edit any of the files -- although a
|
||
smart development environment or *Makefile* will figure out what
|
||
portions need to be recompiled and save some time (especially on large
|
||
programming projects with many lines of code and many files). Also,
|
||
if you move your code to a different computer you will usually need to
|
||
recompile. Generally the extra work of compilation produces an
|
||
efficient and optimized executable that will run fast.
|
||
|
||
- In contrast, many newer languages including Python, Java, and Perl are
|
||
*interpreted languages*, that favor incremental development where
|
||
you can make changes to your code and immediately run all or some of
|
||
your code without waiting for compilation. However, an interpreted
|
||
program will often run slower than a compiled program.
|
||
|
||
- These days, the process of compilation is almost instantaneous for
|
||
simple programs, and in this course we encourage you to follow the
|
||
same incremental editing & frequent testing development strategy that
|
||
is employed with interpreted languages.
|
||
|
||
- Finally, many interpreted languages have a Just-In-Time-Compiler (JIT)
|
||
that can run an interpreted programming language and perform
|
||
optimization on-the-fly resulting in program performance that rivals
|
||
optimized compiled code. Thus, the differences between compiled and
|
||
interpreted languages are somewhat blurry.
|
||
|
||
- You will practice the cycle of coding & compilation & testing during
|
||
Lab 1. You are encouraged to try out different development
|
||
environments (code editor & compiler) and quickly settle on one that
|
||
allows you to be most productive. Ask your lab TAs & mentors
|
||
about their favorite programming environments! The course website
|
||
includes many helpful links as well.
|
||
|
||
- C++ has more required punctuation than Python, and the syntax is more restrictive. The compiler will
|
||
proofread your code in detail and complain about any mistakes you
|
||
make. Even long-time C++ programmers make mistakes in syntax, and
|
||
with practice you will become familiar with the compiler's error
|
||
messages and how to correct your code.
|
||
|
||
## 1.3 A Sample C++ Program: Find the Roots of a Quadratic Polynomial
|
||
|
||
```cpp
|
||
#include <iostream> // library for reading & writing from the console/keyboard
|
||
#include <cmath> // library with the square root function & absolute value
|
||
#include <cstdlib> // library with the exit function
|
||
|
||
|
||
// Returns true if the candidate root is indeed a root of the polynomial a*x*x + b*x + c = 0
|
||
bool check_root(int a, int b, int c, float root) {
|
||
// plug the value into the formula
|
||
float check = a * root * root + b * root + c;
|
||
// see if the absolute value is zero (within a small tolerance)
|
||
if (fabs(check) > 0.0001) {
|
||
std::cerr << "ERROR: " << root << " is not a root of this formula." << std::endl;
|
||
return false;
|
||
} else {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
/* Use the quadratic formula to find the two real roots of polynomial. Returns
|
||
true if the roots are real, returns false if the roots are imaginary. If the roots
|
||
are real, they are returned through the reference parameters root_pos and root_neg. */
|
||
bool find_roots(int a, int b, int c, float &root_pos, float &root_neg) {
|
||
// compute the quantity under the radical of the quadratic formula
|
||
int radical = b*b - 4*a*c;
|
||
// if the radical is negative, the roots are imaginary
|
||
if (radical < 0) {
|
||
std::cerr << "ERROR: Imaginary roots" << std::endl;
|
||
return false;
|
||
}
|
||
float sqrt_radical = sqrt(radical);
|
||
// compute the two roots
|
||
root_pos = (-b + sqrt_radical) / float(2*a);
|
||
root_neg = (-b - sqrt_radical) / float(2*a);
|
||
return true;
|
||
}
|
||
|
||
int main() {
|
||
// We will loop until we are given a polynomial with real roots
|
||
while (true) {
|
||
std::cout << "Enter 3 integer coefficients to a quadratic function: a*x*x + b*x + c = 0" << std::endl;
|
||
int my_a, my_b, my_c;
|
||
std::cin >> my_a >> my_b >> my_c;
|
||
// create a place to store the roots
|
||
float root_1, root_2;
|
||
bool success = find_roots(my_a,my_b,my_c, root_1,root_2);
|
||
// If the polynomial has imaginary roots, skip the rest of this loop and start over
|
||
if (!success) continue;
|
||
std::cout << "The roots are: " << root_1 << " and " << root_2 << std::endl;
|
||
// Check our work...
|
||
if (check_root(my_a,my_b,my_c, root_1) && check_root(my_a,my_b,my_c, root_2)) {
|
||
// Verified roots, break out of the while loop
|
||
break;
|
||
} else {
|
||
std::cerr << "ERROR: Unable to verify one or both roots." << std::endl;
|
||
// if the program has an error, we choose to exit with a
|
||
// non-zero error code
|
||
exit(1);
|
||
}
|
||
}
|
||
// by convention, main should return zero when the program finishes normally
|
||
return 0;
|
||
}
|
||
```
|
||
|
||
## 1.4 Some Basic C++ Syntax
|
||
|
||
- Comments are indicated using // for single line comments and /* and */ for multi-line comments.
|
||
- #include asks the compiler for parts of the standard library and other code that we wish to use (e.g. the
|
||
input/output stream function std::cout).
|
||
- int main() is a necessary component of all C++ programs; it returns a value (integer in this case) and it
|
||
may have parameters.
|
||
- { }: the curly braces indicate to C++ to treat everything between them as a unit.
|
||
|
||
## 1.5 The C++ Standard Template Library, a.k.a. “STL”
|
||
|
||
- The standard template library contains types and functions that are important extensions to the core C++ language.
|
||
We will use the standard template library to such a great extent that it will feel like part of the C++ core language.
|
||
std is a namespace that contains the standard template library.
|
||
|
||
- I/O streams are the first component of the standard template library that we see. std::cout (“console output”) and
|
||
std::endl (“end line”) are defined in the standard template library header file *iostream*.
|
||
|
||
<!--## 1.6 A few notes on C++ vs. Java
|
||
|
||
- In Java, everything is an object and everything “inherits” from java.lang.Object. In C++, functions can
|
||
exist outside of classes. In particular, the main function is never part of a class.
|
||
|
||
- Source code file organization in C++ does not need to be related to class organization as it does in Java. On
|
||
the other hand, creating one C++ class (when we get to classes) per file is the preferred organization, with the
|
||
main function in a separate file on its own or with a few helper functions.-->
|
||
|
||
## 1.6 Variables and Types
|
||
|
||
- A variable is an object with a name. A name is C++ identifier such as “a”, “root_1”, or “success”.
|
||
- An object is computer memory that has a type. A type (e.g., int, float, and bool) is a structure to memory
|
||
and a set of operations.
|
||
- For example, a float is an object and each float variable is assigned to 4 bytes of memory, and this memory
|
||
is formatted according to the IEEE floating point standards for what represents the exponent and mantissa. There
|
||
are many operations defined on floats, including addition, subtraction, printing to the screen, etc.
|
||
- In C++ and Java the programmer must specify the data type when a new variable is declared. The C++
|
||
compiler enforces type checking (a.k.a. static typing). In contrast, the programmer does not specify the type
|
||
of variables in Python and Perl. These languages are dynamically-typed — the interpreter will deduce the data
|
||
type at runtime.
|
||
|
||
## 1.7 Expressions, Assignments and Statements
|
||
|
||
Consider the statement: root_pos = (-b + sqrt_radical) / float(2*a);
|
||
|
||
- The calculation on the right hand side of the = is an expression. You should review the definition of C++
|
||
arithmetic expressions and operator precedence from any reference textbook. The rules are pretty much the
|
||
same in C++ and Java and Python.
|
||
- The value of this expression is assigned to the memory location of the float variable root_pos. Note also that
|
||
if all expression values are type *int* we need a cast from *int* to *float* to prevent the truncation of integer
|
||
division.
|
||
|
||
## 1.8 Conditionals and IF statements
|
||
|
||
- The general form of an if-else statement is
|
||
|
||
```cpp
|
||
if (conditional-expression)
|
||
statement;
|
||
else
|
||
statement;
|
||
```
|
||
|
||
- Each statement may be a single statement, such as the continue statement above, or multiple statements
|
||
contained by {. . .}.
|
||
|
||
## 1.9 Functions and Arguments
|
||
|
||
- Functions are used to:
|
||
- Break code up into modules for ease of programming and testing, and for ease of reading by other people
|
||
(never, ever, under-estimate the importance of this!).
|
||
- Create code that is reusable at several places in one program and by several programs.
|
||
- Each function has a sequence of parameters and a return type. The function prototype below has a return
|
||
type of bool and five parameters.
|
||
|
||
```cpp
|
||
bool find_roots(int a, int b, int c, float &root_pos, float &root_neg);
|
||
```
|
||
- The order and types of the parameters in the calling function (the main function in this example) must match
|
||
the order and types of the parameters in the function prototype.
|
||
|
||
## 1.10 Value Parameters and Reference Parameters
|
||
|
||
- What’s the & symbol on the 4th and 5th parameters in the find_roots function prototype?
|
||
- Note that when we call this function, we haven’t yet stored anything in those two root variables.
|
||
```cpp
|
||
float root_1, root_2;
|
||
bool success = find_roots(my_a,my_b,my_c, root_1,root_2);
|
||
```
|
||
- The first three parameters to this function are value parameters.
|
||
– These are essentially local variables (in the function) whose initial values are copies of the values of the corresponding argument in the function call.
|
||
– Thus, the value of *my_a* from the main function is used to initialize *a* in function *find_roots*.
|
||
– Changes to value parameters within the called function do NOT change the corresponding argument in the calling function.
|
||
- The final two parameters are reference parameters, as indicated by the &.
|
||
- Reference parameters are just aliases for their corresponding arguments. No new objects are created.
|
||
- As a result, changes to reference parameters are changes to the corresponding variables (arguments) in the calling function.
|
||
- In general, the “Rules of Thumb” for using value and reference parameters:
|
||
- When a function (e.g., check_root) needs to provide just one simple result, make that result the return value of the function and pass other parameters by value.
|
||
- When a function needs to provide more than one result (e.g., find_roots, these results should be returned using multiple reference parameters.
|
||
- We’ll see more examples of the importance of value vs. reference parameters as the semester continues.
|
||
|
||
## 1.11 for & while Loops
|
||
|
||
- Here is the basic form of a for loop:
|
||
```cpp
|
||
for (expr1; expr2; expr3)
|
||
statement;
|
||
```
|
||
– expr1 is the initial expression executed at the start before the loop iterations begin;
|
||
– expr2 is the test applied before the beginning of each loop iteration, the loop ends when this expression evaluates to false or 0;
|
||
– expr3 is executed at the very end of each iteration, it is typically used to increment or decrement the loop counter;
|
||
– statement is the “loop body”.
|
||
|
||
- Here is the basic form of a while loop:
|
||
```cpp
|
||
while (expr)
|
||
statement;
|
||
```
|
||
- expr is checked before entering the loop and after each iteration. If expr ever evaluates the false the loop is finished.
|
||
|
||
## 1.12 C-style Arrays
|
||
|
||
- An array is a fixed-length, consecutive sequence of objects all of the same type. The following declares an array with space for 15 double values. Note the spots in the array are currently uninitialized.
|
||
```cpp
|
||
double a[15];
|
||
```
|
||
- The values are accessed through subscripting operations. The following code assigns the value 3.14159 to location i=5 of the array. Here *i* is the subscript or index.
|
||
```cpp
|
||
int i = 5;
|
||
a[i] = 3.14159;
|
||
```
|
||
- In C/C++, array indexing starts at 0.
|
||
- Arrays are fixed size, and each array knows NOTHING about its own size. The programmer must keep track of the size of each array. (Note: C++ STL has generalization of C-style arrays, called vectors, which do not have these restrictions.)
|
||
|
||
## 1.13 Python Strings vs. C chars vs. C-style Strings vs. C++ STL Strings
|
||
|
||
- Strings in Python are immutable, and there is no difference between a string and a char in Python. Thus, ’a’ and "a" are both strings in Python, not individual characters. In C++ & Java, single quotes create a character type (exactly one character) and double quotes create a string of 0, 1, 2, or more characters.
|
||
- A “C-style” string is an array of chars that ends with the special char ’\0’. C-style strings (char\* or char[]) can be edited, and there are a number of helper functions to help with common operations.
|
||
- The “C++-style” STL string type has a wider array of operations and functions, which are more convenient and more powerful.
|
||
|
||
## 1.14 About STL String Objects
|
||
|
||
- A string is an object type defined in the standard library to contain a sequence of characters.
|
||
- The string type, like all types (including int, double, char, float), defines an interface, which includes construction (initialization), operations, functions (methods).
|
||
- When an object is created, a special function is run called a “constructor”, whose job is to initialize the
|
||
object. There are several ways of constructing string objects:
|
||
– By default to create an empty string: std::string my_string_var;
|
||
– With a specified number of instances of a single char: std::string my_string_var2(10, ' ');
|
||
– From another string: std::string my_string_var3(my_string_var2);
|
||
- The notation my_string_var.size() is a call to a function *size* that is defined as a member function of the string class. There is an equivalent member function called *length*.
|
||
- Input to string objects through streams (e.g. reading from the keyboard or a file) includes the following steps:
|
||
1. The computer inputs and discards white-space characters, one at a time, until a non-white-space character is found.
|
||
2. A sequence of non-white-space characters is input and stored in the string. This overwrites anything that was already in the string.
|
||
3. Reading stops either at the end of the input or upon reaching the next white-space character (without reading it in).
|
||
- The (overloaded) operator ’+’ is defined on strings. It concatenates two strings to create a third string, without changing either of the original two strings.
|
||
- The assignment operation ’=’ on strings overwrites the current contents of the string.
|
||
- The individual characters of a string can be accessed using the subscript operator [] (similar to arrays).
|
||
– Subscript 0 corresponds to the first character.
|
||
– For example, given std::string a = "Susan"; Then a[0] == 'S' and a[1] == 'u' and a[4] == 'n'.
|
||
- Strings define a special type string::size_type, which is the type returned by the string function size()
|
||
(and length()).
|
||
– The :: notation means that size type is defined within the scope of the string type.
|
||
– string::size_type is generally equivalent to unsigned int.
|
||
– You may see compiler warnings and potential compatibility problems if you compare an int variable to a.size().
|
||
|
||
## 1.15 Another Sample C++ Program: Reading From & Writing To Files
|
||
|
||
The STL streams std::cin & std::cout are used to read data from and write data to the "console". Often, we would rather read data from a file and/or write the output to a file. We can do this using the STL file stream library fstream. And here is an [example program](getline.cpp). Actually, this example program is the starting point to most of your homeworks. It shows how you can read information from a file, and write information into another file.
|
||
|
||
# 1.16 String Concatenation
|
||
|
||
The `+` operator can be used to concatenate `std::string` objects or a `std::string` with a C-style string.
|
||
|
||
```cpp
|
||
#include <iostream>
|
||
#include <string>
|
||
|
||
int main() {
|
||
std::string str1 = "Hello";
|
||
std::string str2 = "World";
|
||
std::string result = str1 + " " + str2; // Concatenation
|
||
std::cout << result << std::endl; // Output: Hello World
|
||
return 0;
|
||
}
|
||
```
|
||
|
||
## 1.17 Two Useful String Functions
|
||
|
||
- find()
|
||
- substr()
|
||
|
||
This [example program](strings.cpp) which uses these two string functions, can also be very useful in your homeworks.
|
||
|