C++ Page #1: Introduction


There's strictly no warranty for the correctness of this text. You use any of the information provided here at your own risk.


Contents:

  1. About C++
  2. Compiler. Different Versions of C++
  3. A First Program - Hello World
  4. Comments
  5. for-Loops, while-Loops, if-Statements, break and continue
  6. Strings and String-Functions
  7. Getting User-Input on the Command-Line
  8. Example-Program "Cookie Monster"
  9. Pointers. nullptr
  10. References
  11. Vectors: Dynamic Lists
  12. An Example of a "split()"-Function
  13. STL-Arrays
  14. unordered_map (Hashes / Dictionaries)
  15. Vectors of Vectors
  16. Managing Memory with new and delete
  17. Further Reading


1. About C++

C++ was designed by Bjarne Stroustrup in the early 1980s. It was first published in 1985. Since then it has received many revisions, there was especially a major update in 2011.
C++ is an object-orientated language, based on C. In the early days (up to 1983) it was called "C with Classes".
But although C++ is compatible to C, it is considered to be a different language than C.
If you write a program in C++, and have the choice to either use C-constructions or C++-constructions, it is suggested to prefer the latter ones.

Here's a timeline, when these common programming languages were created, respectively first released:

CAround 1970
C++Around 1980 to 1985
Perl1987
Python1991
Lua1993
Java1995
JavaScript1995
PHP1995
C#2001

Back to C++: Obviously it has some constructions in common with C. But with its classes, it sometimes also feels a bit similar to Python. Python is of course an interpreted language, and easier to use than C++. On the other hand, C++-code runs faster. So it may be a good idea to write prototypes of object-oriented programs in Python first, and then translate them to C++ later.

It seems, throughout the years there have been many changes to the language. "C++23" is the recent version at the moment, but "C++26" is already planned. Especially since the update of 2011, C++ seems to be a lot easier to use than earlier versions. Older tutorials may show deprecated syntax that has been replaced by much more convenient language constructions.
So when reading a tutorial that is too old, you may get the wrong impression, that programming in C++ is much more difficult than it actually is today.
Especially explicitly managing memory (which is essential in C) seems only rarely be needed in C++ any more, and in many cases, you can use references instead of pointers, which makes things a lot easier.

How fast a program written in C++ runs, depends on the way, the code was written. The developer has a lot of options to optimize the code for speed. Without optimization, the program might not even run that fast.

So C++ is a compiled language. It's suited for large projects as well as C is. It has classes and objects. In general, it may be bit easier to write in C++ than in C. All these features combined make C++ one of the favourite languages of the professional software industry. For example, the company "Electronic Arts" uses C++ for its modern, commercial computer games. This company even released its own version of the C++ "Standard Template Library" (STL), which is optimized for speed. This version is called "EASTL".

Here's a general tutorial about C++ I can recommend.


2. Compiler. Different Versions of C++

The compiler-executable for C++ in the gcc-distribution is called "g++".

If you have a file "h.cpp", you can run

g++ h.cpp

and get a file "a.out", which you can run then with

./a.out

C++ has evolved over the years. There has been a major update in 2011.
If code doesn't compile, the reason may be, that modern constructions of this update were used. Then it may help to compile with:

g++ -std=c++11 source.cpp

Actually, for my Linux distribution (OpenSuSE Leap 15.6) there are different versions of the gcc/g++-compiler. By default

g++ -v

shows version 7.5.0. But version 14 is also available. It can be installed in addition to version 7.5.0. When compiling a new program, version 14 can then simply be selected by running

g++-14 [yourfile.cpp]

For example the useful library "std::filesystem" has entered the official C++-language just in 2017 with "C++17". Running "g++-14" can handle the line "#include <filesystem>", while "g++-7" can't.
So the g++ compiler version 14 can handle at least the language version "C++17".


3. A First Program - Hello World

Here's a "Hello World" in C++:

#include <iostream>

using namespace std;

int main() {
    cout << "Hello World." << endl;
    return 0;
}

"cout" is the program's output stream. "cout" means "character output". So characters are redirected there with "<<".
"cout" and "endl" are part of the namespace "std" and could also be written as "std::cout" and "std::endl". If you wrote them that way, you wouldn't need the "using namespace ..."-line above.


It's also possible to define your own namespaces. You can use single variables from that namespace by just using "using" (not "using namespace"), followed by two colons, and then the name of the variable. Like that:

using my_namespace::a;
Or you can introduce the whole namespace with "using namespace" followed by the name of your namespace:
#include <iostream>

using namespace std;

namespace my_namespace {
    int a = 1;
    int b = 2;
}

int main () {
    using namespace my_namespace;
    cout << a << endl;
    cout << b << endl;
    return 0;
}


4. Comments

In addition to C's syntax:

/* ..... */
in C++ you can use:
// ...

Then all characters after the double-slashes in a line are considered to be comment.


5. for-Loops, while-Loops, if-Statements, break and continue

The following constructions work just like in C:

#include <iostream>

using namespace std;

int main() {
    int i;
    for (i = 0; i <= 10; i++) {
        if (i == 5) {
            continue;
        }
        cout << i << endl;
    }
    i = 0;
    while (i < 10) {
        cout << i << endl;
        if (i == 5) {
            break;
        }
        i++;
    }
    return 0;
}

It's also possible to iterate over "collections" (such as vectors or STL-arrays, see below) with:

for (int i : vec) { ... }

If "vec" contains strings, you'd have to write respectively:

for (string i : vec) { ... }

In this case, you can also use the "auto"-feature, which tries to identify the data type of a variable from its context:

for (auto i : vec) { ... }


6. Strings and String-Functions

In C++, there's a datatype "string". Such strings are objects, so they have methods. These methods can be called using the "."-operator (like in Python). Useful methods are:

If a string is equal to another string can also simply be checked with the "=="-operator.

There can be "string constants" in the code, that aren't assigned to any variable.

Single characters in a string are of datatype 'char' and can be accessed by using square brackets like in "a[0]". This can also be used for replacing single characters in a string.

#include <iostream>

using namespace std;

int main() {
    string a = "Hello";
    cout << a.length() << endl;
    cout << a.substr(1, 3) << endl;
    string b = "Hello";
    if (a.compare(b) == 0) {
        cout << "a is \"" << b << "\"." << endl;
    }
    cout << a[1] << endl;
    a[1] = 'x';
    cout << a << endl;
    cout << a.find("l", 0) << endl;
    return 0;
}


7. Getting User-Input on the Command-Line

"cin", the counterpart to "cout", can be used to ask the user for an integer (or a double / floating point number) on the console.

int a;
cin >> a;

If the user should enter a string, the function

getline(cin, [string])

has to be used. In practice, it's probably better to always use "geline()", and if necessary convert the input with "stoi()" later.


8. Example-Program "Cookie Monster"

This is a nice little program from a good Perl-book (Laura Lemay: "Sams Teach Yourself Perl in 21 Days"), I can recommend. If you get to this program and can run it, you already know some of the constructions, a programming-language uses:

#include <iostream>

using namespace std;

int main() {
    // Cookie Monster
    string cookies;
    while (cookies != "COOKIES") {
        cout << "I want COOKIES: ";
        getline(cin, cookies);
    }
    cout << "Mmmm. COOKIES." << endl;
}

This is actually not much more difficult than in Perl or Python.


9. Pointers. nullptr

Pointers are basically declared and used as they are in C.

The keyword for null-pointers is "nullptr" (instead of "NULL" in C).


10. References

In addition to pointers, in C++ there are also references. Their operator is "&".
They are more restricted than pointers, but easier to use.

References are tied to a variable at definition, and can't be pointed somewhere else afterwards.
Unlike pointers, references can't be "NULL".
There isn't something similar to "pointer arithmetics".
References can also appear as function parameters.
After definition, references can just be used synonymously to the original variable.

#include <iostream>

using namespace std;

void myfunc(int &ref) {
    cout << ref << endl;
}

int main() {
    int a = 10;
    int &b = a;
    cout << b << endl;

    /* Passing a variable to a reference that is used
       as a function parameter (see above): */
    myfunc(a);
    return 0;
}

So references as function parameters can especially make sure, that variables are passed to functions by reference. In most cases, that is what developers want, because larger objects such as vectors would otherwise get copied in full when passed by value.

To be able to also pass string literals such as ""Hello"" to a function by reference, the term "const string &s" can be used as a function parameter (where "s" is the variable name).

According to an internet-discussion, the compiler makes it possible to just return a larger local variable like for example a vector from a function. It also takes care of efficiency. (In C, you would have to allocate memory in the function yourself, and return a pointer from the function.) So when you create a vector inside a function in C++, and want to return it from there, you just return it by value. You don't need to return a pointer to it (although that would be an option, if you used a pointer to a vector from the beginning, like that:

vector<string> *vecp = new vector<string>;

and later you'd have to call

delete vecp;

somewhere then.) But especially, you don't return a reference to the vector from the function. Because the local vector may vanish, when the function ends, and then the reference may not reference anything useful any more.


11. Vectors: Dynamic Lists

If you want to store a known amount of data of a single type, you can use C-arrays or STL-arrays, that are described in the next section.

Vectors can be used, when a dynamic list is required. Then, the line

#include <vector>

has to be added. And to make it all work, in most cases the code has to be compiled with:

g++ -std=c++11 source.cpp

Vectors are declared with the keyword "vector", followed by the type of data to be stored in the vector included between "lesser than" and "greater than"-characters, followed by the name of the vector:

vector<int> my_vector;

In "-std=c++11", they can be initialized with values in curly brackets (similar to C-arrays):

vector<int> my_vector = {1, 2, 3};

Useful methods of vectors are:

If you want to store strings, floats and doubles together in a vector, you can declare the vector for "string" altogether, and convert the strings that store the numbers with the functions "stoi()", "stof()" and "stod()" (found in namespace "std") later.

Vectors can also be arguments to functions. Here's an example:

#include <iostream>
#include <vector>

// Compile with: g++ -std=c++11 source.cpp

using namespace std;

void printIntVector(vector<int> vec) {
    int i;
    int vecsize = vec.size();
    cout << "[";
    for (i=0; i < vecsize; i++) {
        cout << vec[i];
        if (i < vecsize - 1) {
            cout << ", ";
        }
    }
    cout << "]" << endl;
}

int main() {
    vector<int> items = {1, 2, 3};
    items.push_back(100);
    printIntVector(items);
    items.pop_back();
    printIntVector(items);
    return 0;
}

If not specified otherwise, the vector is passed to a function by value. That means, that for use in the function a copy of the vector is created, and the function just operates on that copy.
If you want to pass the vector by reference instead, an "&" has to be added in the function's declaration. Then the function operates on the same vector, that exists outside the functions, and changes made to that vector inside the function also effect the vector in the rest of the program:

void printIntVector(vector<int> &vec) {...}

A vector can be assigned to another vector (with "="). This creates a copy of the vector.


Here I translated the example about lists from my Perl-page to C++:

#include <iostream>
#include <vector>

using namespace std;

int main() {

    // Initialize a vector of strings:
    vector<string> fruits = {"apple", "banana"};

    // Add an element at the end of the vector:
    fruits.push_back("peach");

    // Create a loop, that iterates through the vector (printing it).
    for (auto i : fruits) {
        cout << i << endl;
    }
    cout << endl;

    // Get the last element of the vector, then remove it from there:
    string l = fruits.back();
    fruits.pop_back();
    int fruitslen = fruits.size();
    cout << fruitslen << endl;
    cout << l << endl;

    // Get the first element of the vector, then remove it from there:
    l = fruits.front();
    fruits.erase(fruits.begin());
    fruitslen = fruits.size();
    cout << fruitslen << endl;
    cout << l << endl;

    // Add an element at the beginning of the vector:
    fruits.insert(fruits.begin(), "peach");
    fruits.insert(fruits.begin(), "apple");

    // Iterate through the vector again:
    cout << endl;
    for (auto i : fruits) {
        cout << i << endl;
    }
    cout << endl;

    // Get the number of elements of the vector:
    fruitslen = fruits.size();
    cout << fruitslen << endl << endl;

    // Erase an element in the middle of the vector:
    fruits.erase(fruits.begin() + 1);

    // Add an element in the middle of the vector:
    fruits.insert(fruits.begin() + 1, "cherry");

    // Iterate through the vector again:
    cout << endl;
    for (auto i : fruits) {
        cout << i << endl;
    }
    cout << endl;

    // Access an element by element number.
    // Notice that the element numbers are in the range from 0 to the number of elements minus 1,
    // so "fruits.at(1)" is the second element of the list:
    cout << fruits.at(1) << endl;
    fruits.at(1) = "strawberry";
    cout << fruits.at(1) << endl;

    return 0;
}

Many vector-operations like for example

vector<string> v;
v.push_back("Hello");

of the default "Standard Template Library" (STL) imply reallocation of memory and may be relatively time-consuming at runtime. If you care for speed optimization, you may want to think about other, more complex constructions that are more difficult to use though.
When in doubt, of course you always have the option to fall back to pure C. But there just isn't a STL-vector there.


12. An Example of a "split()"-Function

It seems, there isn't a dedicated "split()"-function in the C++ standard library that splits a string at a substring (a "delimiter"), and stores the parts in a vector of strings.
There are several proposals for such a function on the internet.
Here's an approach of mine making use of C's "strtok()"-function. But remember, I'm just a C/C++-beginner, so don't use this code in a "real" project such as productivity software or such.
I'm also using pointers (to vectors of strings) here, so the vectors don't have to be copied when passing them from or to functions. So the "mysplit()"-function returns a "pointer to a vector of strings". The elements can then be accessed through the pointer (using the "->"-operator"), or the pointer can be dereferenced to get back an ordinary vector of strings:

#include <iostream>
#include <string>
#include <vector>
#include <cstring>

using namespace std;

/* Example of a split()-function.
   Code may be buggy, do not use in real projects.
   License: GNU GPL 3. */

void printStringVector(vector<string> &vecref) {
    int vecsize = vecref.size();
    cout << "[";
    for (int i=0; i < vecsize; i++) {
        cout << "\"";
        cout << vecref[i];
        cout << "\"";
        if (i < vecsize - 1) {
            cout << ", ";
        }
    }
    cout << "]" << endl;
}

char *getCString(string &cpps) {
    // Allocates memory for a C-string, copies the C++-string there
    // and returns a pointer to it.

    int slength = cpps.size();
    char *cs = (char *) malloc(slength + 1);
    if (cs == NULL) {
        return NULL;
    }
    strcpy(cs, cpps.c_str());
    /* An internet discussion says, C++-strings
       may not automatically get the null-terminator character
       when returned by ".c_str()", so I make sure the hard way: */
    char *p = cs;
    p += slength;
    *p = '\0';
    return cs;
}

vector<string> mysplit(string &splitstring, string delim) {

    /* Splits a string, storing its parts/tokens in a vector.
       The delimiter can only be an ordinary string,
       not a regular expression. */

    vector<string> v;
    char *str = getCString(splitstring);
    char *delimiter = getCString(delim);
    char *token;
    token = strtok(str, delimiter);
    while (token != NULL) {
        v.push_back(token);
        token = strtok(NULL, delimiter);
    }
    free(delimiter);
    free(str);
    return v;
}

int main() {
    string s = "Split me into a number of substrings";
    vector<string> v = mysplit(s, " ");
    printStringVector(v);
    return 0;
}


13. STL-Arrays

Similar to vectors, static arrays can be defined in a C++-way using the "Standard Template Library" (STL). These STL-arrays are more comfortable than C-arrays. The line

#include <array>

has to be added, and compiling with

g++ -std=c++11 source.cpp

is probably also needed.

Then you can define an array of 10 elements with:

array<int,10> items = {1, 2, 3};

It has a ".size()" function and (unlike C-arrays) can be passed directly to functions like vectors (by value or - with "&" - by reference):

void printIntSTLArray(array<int,10> arr) {...}

There isn't a push-method for STL-arrays, but elements can be written directly like in:

arr[9] = 25;

A quick example:

#include <iostream>
#include <array>

using namespace std;

void printArray(array<int,3> arr) {
    for (auto i: arr) {
        cout << i << endl;
    }
}

int main() {
    array<int,3> arr = {1, 2, 3};
    printArray(arr);
    return 0;
}


14. unordered_map (Hashes / Dictionaries)

To implement a data type with pairs of keys and values that are not in a specific order (something that would be called a "hash" in Perl or a "dictionary" in Python), there is the data type called "unordered_map" in C++. Here's an example:

#include <iostream>
#include <unordered_map>

using namespace std;

int main() {
    unordered_map<string, int> a = { {"One", 1},
                                     {"Two", 2},
                                     {"Three", 3} }; 
    cout << a["One"] << endl;
    return 0;
}


15. Vectors of Vectors

In C++, you can also have vectors of vectors (and so on):

#include <iostream>
#include <vector>

// Compile with: g++ -std=c++11

using namespace std;

void printIntVector(vector<int> vec) {
    int i;
    int vecsize = vec.size();
    cout << "[";
    for (i=0; i < vecsize; i++) {
        cout << vec[i];
        if (i < vecsize - 1) {
            cout << ", ";
        }
    }
    cout << "]" << endl;
}

int main() {
    vector<vector<int> > items = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
    for (vector<int> i : items) {
        printIntVector(i);
    }
    return 0;
}

Notice, there has to be the space character between the two ">" in "vector<vector<int> > ...", which is a bit odd. Maybe to avoid confusing the characters ">>" with the operator that looks the same.


16. Managing Memory with new and delete

Memory can be managed by using the keywords "new" and "delete" in combination with a pointer.
Here's an example:

#include <iostream>

using namespace std;

int main() {
    char *p = new char[10];
    p[0] = 'H';
    p[1] = 'e';
    p[2] = 'l';
    p[3] = 'l';
    p[4] = 'o';
    p[5] = '\0';
    printf("%s\n", p);
    delete(p);
    return 0;
}

So "new" and "delete" basically work similar to the functions "malloc()" and "free()" in C.
Of course, you must not mix the two allocation-systems. That is, for example you must not call "delete" on something that has been allocated with "malloc()".

It seems, in recent versions of C++ it's not that often necessary to manage memory that way. As shown in the chapters above, for example strings (C++-strings), vectors and STL-arrays can be used without explicitly managing memory. This also applies to classes and objects.


17. Further Reading

The next page deals with creating classes and objects.



Back to the computing-page


Author: hlubenow2 {at-symbol} gmx.net