C++ for beginners

Hello World

Fail: hello.cpp

#include <iostream>

int main() 
{
  
  std::cout << "Hello World!\n";

  return 0;
  
}
  • std::cout is the “character output stream”. It is pronounced “see-out”
  • << is an operator that comes right after it
#include <iostream>

This is known as a pre-processor directive. It instructs the compiler to locate the file that contains code for a library known as iostream. This library contains code that allows for input and output, such as displaying data in the terminal window, or reading input from your keyboard.

int main() {
  // Statements
}

Every C++ program must have a function called main(). A function is basically a sequence of instructions for the computer to execute. This main() function houses all of our instructions for our program.

Output a variable score:

std::cout << score << "\n";

Compile and execute

C++ is a compiled language. That means that to get a program to run, you must first translate it from the human-readable form to something a machine can “understand.” That translation is done by a program called a compiler.

What you read and write is called source code, and what the computer executes is called executable, object code, or machine code (a machine language

Typically C++ source code files are given the suffix: .cpp (ex: hello.cpp) or .h (ex: std_lib_facilities.h).

Course code (hell.cpp) > Prepocessor > Compiler > Linker > Executable (a.out).

A compiler translates the C++ program into machine language code which it stores on the disk as a file with the extension .o (e.g. hello.o). A linker then links the object code with standard library routines that the program may use and creates an executable image which is also saved on disk, usually as a file with the file name without any extension (e.g. hello).

The executable is loaded from the disk to memory and the computer’s CPU (Central Processing Unit) executes the program one instruction at a time.

Compile using default executable file name:

$ g++ hello.cpp

Execute on bash (terminal):

$ ./a.out

Renaming the executable file

$ g++ hello.cpp -o hello
$ ./hello

For review, #include is a preprocessor directive that tells the compiler to include whatever library that follows.

Programs with multiple .cpp files need to be linked at compile time:

g++ main.cpp fns.cpp

Comments

Single line comments:

// Prints "hi!" to the terminal
std::cout << "hi!"; // print

Multi-line comment:

/* This is all commented.
std::cout << "hi!";
None of this is going to run! */

return 0;

The return statement is used to end a function. If the program reaches this statement, returning a value of 0 is an indication to the operating system that the code executed successfully. This line of code is optional.

return 0;

Variables

variable is simply a name that represents a particular piece of your computer’s memory that has been set aside for you to store, retrieve, and use data.

Every variable has a data type.

Basic data types

  • int – integer numbers. Example: 420
  • double – floating point numbers. Example: 3.14
  • char – individual characters. Example: ‘a’
  • string – sequence of characters. Example: “Hello World”
  • bool – truth values. Example: false

Declareing a Variable

A variable represents a particular piece of computer’s memory that has been set aside for you to use to store, retrieve, and manipulate data.

Every variable in C++ must be declared before it can be used!

int number;

Initialize a variable:

year = 2019;

Declaring and initializing variable. It is highly suggested to initialize a variable before using it later.

int score = 0;

Variable names consist only of upper/lower case letters, digits, and/or underscores.

C++ is known as a strongly typed language. If you try to give an integer value a decimal number, you are going to get unexpected results, warnings, or errors.

The Scope of Things

  • Variables defined in global scope are accessible throughout the program
  • Variables defined in a function have local scope and are only accessible inside the function

Arithmetic Operators

  • + addition
  • - subtraction
  • * multiplication
  • / division
  • % modulo (divides and gives the remainder)

Single equal sign = indicates assignment, not equality in the mathematical sense.

Chaining

We use quotes when we want a literal string. We don’t use quotes when we refer to the value of  variable.

int age = 28;

std::cout << "Hello, I am ";
std::cout << age;
std::cout << " years old\n";

We can use multiple << operators to chain the things we want to output. This is called chaining:

int age = 28;

std::cout << "Hello, I am " << age << " years old\n";

User Input

std::cout << "Enter your password: ";
std::cin >> password;

The name cin refers to the standard input stream (pronounced “see-in”, for character input). The second operand of the >> operator (“get from”) specifies where that input goes.

Relational Operators

  • == equal to
  • != not equal to
  • > greater than
  • < less than
  • >= greater than or equal to
  • <= less than or equal to

Logical Operators

Logical operators are used to combine two or more conditions. They allow programs to make more flexible decisions. The result of the operation of a logical operator is a bool value of either true or false.

  • &&: the and logical operator
  • ||: the or logical operator
  • !: the not logical operator

And: &&

The and logical operator is denoted by &&. It returns true if the condition on the left and the condition on the right are both true. Otherwise, it returns false.

  • ( 1 < 2 && 2 < 3 ) returns true
  • ( 1 < 2 && 2 > 3 ) returns false

The keyword and can also be used in the place of &&.

#include <iostream>

int main() {

  int hunger = true;
  int anger = true;
  
  if(hunger and anger){
    std::cout << "Hangry\n";
  }
  
}

Or: II

The or logical operator || returns true when the condition on the left is trueor the condition on the right is true. Only one of them needs to be true.

  • ( 1 < 2 || 2 > 3 ) returns true
  • ( 1 > 2 || 2 > 3 ) returns false

The keyword or can be used in the place of ||.

#include <iostream>

int main() {
  int day = 6;
  
  if (day == 6 || day == 7){
    std::cout << "Weekend\n";
  }
}

Not: !

The not logical operator ! reverses the bool outcome of the expression that immediately follows.

  • ( !true ) returns false
  • ( !false ) returns true
  • ( !(10 < 11) ) returns false

The keyword not can be used in the place of !.

#include <iostream>

int main() {
  
  bool logged_in = false;
  
  if (!logged_in){
    std::cout << "Try again\n";
  }
  
}

If, Else and Else If

An if statement is used to test an expression for truth and execute some code based on it. If the condition is true, then the statements within are executed. Otherwise, the statements are skipped and the program continues on.

if (flip == 1) {
  std::cout << "Heads\n";
}
  • Inside the parentheses (), a condition is provided that evaluates to true or false
  • If the condition evaluates to true, the code inside the curly braces {} runs, or executes

We can also add an else clause to an if statement to provide code that will only be executed if the condition is false.

if (coin == 1) {
  std::cout << "Heads\n";
}
else {
  std::cout << "Tails\n";
}

The else if statement always comes after the if statement and before the else statement. The else if statement also takes a condition.

if (grade == 9) {
  std::cout << "Freshman\n";
} 
else if (grade == 10) {
  std::cout << "Sophomore\n";
}
else if (grade == 11) {
  std::cout << "Junior\n";
} 
else if (grade == 12) {
  std::cout << "Senior\n";
}
else {
  std::cout << "Super Senior\n";
}

Switch Statement

switch statement provides an alternative syntax that is easier to read and write.

switch (grade) {
  case 9:
    std::cout << "Freshman\n";
    break;
  case 10:
    std::cout << "Sophomore\n";
    break;
  case 11:
    std::cout << "Junior\n";
    break;
  case 12:
    std::cout << "Senior\n";
    break;
  default:
    std::cout << "Invalid\n";
    break;
}
  • The switch keyword initiates the statement and is followed by (), which contains the value that each case will compare. In the example, the value or expression of the switch statement is grade. One restriction on this expression is that it must evaluate to an integral type (intcharshortlonglong long, or enum).
  • The case keyword checks if the expression matches the specified value that comes after it. The value following the first case is 9. If the value of grade is equal to 9, then the code that follows the : would run.
  • The break keyword tells the computer to exit the block and not execute any more code or check any other cases inside the code block. Without the break keyword at the end of each case, the program would execute the code for all matching cases and the default code as well.
  • At the end of each switch statement, there is a defaultstatement. If none of the cases are true, then the code in the default statement will run.

Loops

loop is a programming tool that repeats some code or a set of instructions until a specified condition is reached. When we see that a process has to repeat multiple times in a row, we write a loop. Loops allow us to create efficient code that automates processes to make scalable, manageable programs.

While Loop

While loop will continue to execute the code inside of it, over and over again, as long as the condition is true.

int guess = 0;
std::cin >> guess;

while (guess != 8) {
  std::cout << "Wrong guess, try again: ";
  std::cin >> guess;
}

&& symbol means and and it combines two conditions into one

For Loop

When we know exactly how many times we want to iterate (or when we are counting), we can use a for loop instead of a while loop:

for (int i = 0; i < 20; i++) 
{
  std::cout << "I will not throw paper airplanes in class.\n";
}
  • The initialization of a counterint i = 0
  • The continue condition: i < 20
  • The change in the counter (in this case an increment): i++

Vectors

vector is a sequence of elements that you can access by index. The first index in a vector is 0.

The std::vector lives in the <vector> header.

#include <vector>

And the syntax to create a vector looks like:

std::vector<type> name;
// Example int vector:
std::vector<int> calories_today;
// string vector:
std::vector<std::string> last_jedi;

Inside the angle brackets is the data type of the vector. After the angle brackets is the name of the vector. The type of the vector cannot be changed after the declaration.

We can also initialize a vector, giving it values, as we are creating it in the same line.

std::vector<double> location = {42.651443, -73.749302};

Another way we can initialize vector is by presizing, or setting the size. Example: initialize a vector with two elements:

std::vector<double> location(2);

Vector Index

An index refers to an element’s position within an ordered list. Vectors are 0-indexed, meaning the first element has index 0, the second index 1, and so on.

std::vector<char> vowels = {'a', 'e', 'i', 'o', 'u'};
  • The character at index 0 is 'a'
  • The character at index 1 is 'e'
  • The character at index 2 is 'i'

To output of the elements, we can do:

std::cout << vowels[0] << "\n";
std::cout << vowels[1] << "\n";

Using the notation vector[index] with square brackets after the vector name and the element’s index number inside.

Adding and Removing Vector Elements

To add a new element to the “back”, or end of the vector, we can use the .push_back() function.

std::vector<std::string> dna = {"ATG", "ACG"};
// Add elements:
dna.push_back("GTG");
dna.push_back("CTG");

We can also remove elements from the “back” of the vector using .pop_back().

dna.pop_back();

Vector size

The .size() function returns the number of elements in the vector (and elements in the string).

std::vector<std::string> grocery = {"Hot Pepper Jam", "Dragon Fruit", "Brussel Sprouts"};
std::cout << grocery.size() << "\n"; // ==3

Change each of the values within a vector

for (int i = 0; i < vector.size(); i++) {
  vector[i] = vector[i] + 10;
}

Functions

  • You can build DRY (Don’t Repeat Yourself) code, reusing the code you already wrote
  • Functions help make your code flexible and modular, meaning you can group your code more easily by task

A C++ function is comprised of two distinct parts:

  • Declaration: this includes the function’s name, what the return type is, and any parameters (if the function will accept input values, known as arguments).
  • Definition: also known as the body of the function, this contains the instructions for what the function is supposed to do.
return_type function_name( any, parameters, you, have ) {
   // Code block here
   return output_if_there_is_any;
}
bool is_even(int number) {
  if (number % 2 == 0) {
    return true;
  }
  return false;
}

Built-in Functions

We gain access to various functions by including headers like <cmath> or <string>.

  • sqrt() to find the square root of any number. Example: sqrt(9) ;
  • rand() with the modulo operator to generate a random number between 0 and your favorite number. Example: number = rand() % 29;
  • pow(a, b) will raise ato the power of b
// This seeds the random number generator:
  srand (time(NULL));
  
  // Use rand() below to initialize number
  int number = rand() % 29;
  std::cout << number;

Void Function

void function, also known as a subroutine, has no return value.

void hello() {
  std::cout << "Hello World!\n";
}
void get_emergency_number(std::string emergency_number){
  std::cout << "Dial " << emergency_number << "\n";
}

Return Types

A function can return most data types we’ve covered, including doubleintboolcharstd::string, andstd::vector.

  • The return statement is the last line the function will execute
  • There must be a value returned from the function
  • The return value must be the same type as the function’s return type

Parameters

Parameters are variables used in a function’s definition. They act as placeholders for the input values you’ll use during your function call.

  • The function call must include the same number of arguments as there are parameters.
  • The corresponding arguments must be passed in the same order.

Declaring functions

With a few functions, you can declare the function above main() and then you can define the function below main() like this:

#include <iostream>

// Declaration at the top:
void eat();

int main() {
  eat();
}

// Definition at the bottom:
void eat() {
  std::cout << "nom nom nom\n";
}

To make your code cleaner and more modular, you can move the function definitions over to another specialized .cpp file (e.g., my_functions.cpp), leaving a list of declarations above main().

Before your program even compiles, it links together any files you list in your compilation statement into a single executable:

g++ main.cpp my_functions.cpp

Functions Default Arguments

If you add a parameter to a function in C++, then an argument will be required when you call the function. To make your code more flexible you can add default arguments to your function declarations. Default arguments are values assigned to parameters when the function is declared and defined:

// Declaration
void intro(std::string name, std::string lang = "C++");

// Definition
void intro(std::string name, std::string lang) {
  std::cout << "Hi, my name is "
            << name
            << " and I'm learning "
            << lang
            << ".\n";
}

Then, if you leave the argument blank in your function call, your function will run with the default value. If you DO have an argument to add when you call the function, that argument will replace the default argument when your code executes.

Parameters without default arguments come first.

int add_nums(int num1, int num2 = 0);

Header files

You can move all function declarations over to a header file, another file — usually with the same name as the file with all of the function definitions — with the extension .hpp or .h. For example, if your function definitions are in my_functions.cpp, the corresponding header file would be my_functions.hpp or my_functions.h.

With headers, you can just add #include "my_functions.hpp" to the very top of main.cpp:

#include "my_functions.hpp"

Inline functions

Term “inline functions” with a couple different meanings.

1.

An inline function is a function definition, usually in a header file, qualified by inline like this:

inline 
void eat() {
  std::cout << "nom nom\n";
}

Using inline advises the compiler to insert the function’s body where the function call is, which sometimes helps with execution speed (and sometimes hinders execution speed). If you do use it, we recommend testing how it affects the execution speed of your program.

2.

You will sometimes also hear about “inline functions” that are just member functions (i.e. functions inside of classes) which have been defined and declared in a single line in a header file because the function body is so short:

// cookie_functions.hpp

// eat() belongs to the Cookie class:
void Cookie::eat() {std::cout << "nom nom\n";}

Please note that you should ALWAYS add the inlinekeyword if you are inlining functions in a header (unless you are dealing with member functions, which are automatically inlined for you).

Function overloading

In a process known as function overloading, you can give multiple C++ functions the same name. Just make sure at least one of these conditions is true:

  • Each has different type parameters.
  • Each has a different number of parameters.

Overloading enables you to change the way a function behaves depending on what is passed in as an argument:

void print_cat_ears(char let) {
  std::cout << " " << let << "   " << let << " " << "\n";
  std::cout << let << let << let << " " << let << let << let << "\n";
}

void print_cat_ears(int num) {
  std::cout << " " << num << "   " << num << " " << "\n";
  std::cout << num << num << num << " " << num << num << num << "\n";
}

Given the above functions, you could call the functions like so and C++ will know what to do:

print_cat_ears('A');
print_cat_ears(4);

Example:

int fancy_number(int num1, int num2);
int fancy_number(int num1, int num2, int num3);
int fancy_number(double num1, double num2);

Function Templates

When two functions have different types but the same body — as was the case with print_cat_ears() —, there is a cleaner solution you can use: templates.

template is a C++ tool that allows programmers to add data types as parameters.

This feature comes in handy for classes as well as for functions. In fact, std::string and std::vector are both template-based types.

Unlike regular functions, templates are entirely created in header files.

Templates let you choose the type implementation right when you call the function.

Here’s how we could build a template for print_cat_ears():

template <typename T>
void print_cat_ears(T item) {
  std::cout << " " << item << "   " << item << " " << "\n";
  std::cout << item << item << item << " " << item << item << item << "\n";
}

We can call the function for intcharstd::string, or double.

If the template’s return type is flexible or depends on the implementation, it can be type T like this:

template <typename T>
T get_smallest(T num1, T num2) {
  return num2 < num1? num2 : num1;
}

Using templates will slow down the program’s compile time, but speed up the execution time.

Classes

The class serves as a blueprint for objects, which are instances of the class (just like age is an instance of int). An object gets characteristics and behaviors from its class.

We can create an empty C++ class like this in a header file:

class City {

}; // <-- notice this semicolon!

Components of a class are called class members. Just like you can get a string’s length using .length(), you can access class members using the dot operator (object.class_member).

There are two types of class members:

  • Attributes, also known as member data, consist of information about an instance of the class.
  • Methods, also known as member functions, are functions that you can use with an instance of the class.
class City {

  // attribute
  int population;

// we'll explain 'public' later
public:
  // method
  void add_resident() {
    population++;
  }

};

It’s common to declare methods inside the class (in a header), then define them outside the class (in a .cpp file of the same name). You can do this using ClassName:: before the method name to indicate its class like this:

int City::get_population() {
  return population;
}

Unlike with regular functions, you will need to include the header file in the .cpp file where you define the methods.

The method must also be declared inside the class if you want to define it outside.

Creating Objects

To create (or instantiate) an object, we can do this:

City accra;

We can give the object’s attributes values like this (note that these must be attributes you defined in the class):

accra.population = 2270000;

Later, we can access this information using the method we added to the City class (if it’s in a public part of the class):

accra.get_population();

Public and Private

By default, everything in a class is private, meaning class members are limited to the scope of the class.

But sometimes you need access to class members, and for that there is public. You can use it to make everything below accessible outside the class:

class City {

  int population; 

public: // stuff below is public
  void add_resident() { 
    population++;
  }

};

There is also a private access modifier for when you want something below public to be private to the class:

class City {

  int population; 

public:
  void add_resident() { 
    population++;
  }

private: // this stuff is private
  bool is_capital;
};

Constructors

constructor is a special kind of method that lets you decide how the objects of a class get created. It has the same name as the class and no return type. Constructors really shine when you want to instantiate an object with specific attributes.

If we want to make sure each City is created with a name and a population, we can use parameters and a member initializer list to initialize attributes to values passed in:

// city.hpp
#include "city.hpp"

class City {

  std::string name;
  int population;

public:
  City(std::string new_name, int new_pop);

};

// city.cpp
City::City(std::string new_name, int new_pop)
  // members get initialized to values passed in 
  : name(new_name), population(new_pop) {}

You could also write the definition like this:

City::City(std::string new_name, int new_pop) {
  name = new_name;
  population = new_pop;
}

However, a member initialization list allows you to directly initialize each member when it gets created.

To instantiate an object with attributes, you can do:

// inside main()
City ankara("Ankara", 5445000);

Destructors

destructor is a special method that handles object destruction. Like a constructor, it has the same name as the class and no return type, but is preceded by a ~ operator and takes no parameters:

City::~City() {

  // any final cleanup

}

Object destruction is about tidying up and preventing memory leaks.

You generally won’t need to call a destructor; the destructor will be called automatically in any of the following scenarios:

  • The object moves out of scope.
  • The object is explicitly deleted.
  • When the program ends.

Memory

Everything we put into memory has an address. For example, when we declare and initialize an int variable named power:

int power = 9000;

This will set aside an int-size piece of memory for the variable power somewhere and put the value 9000 into that memory.

References

In C++, a reference variable is an alias for something else, that is, another name for an already existing variable.

Suppose we have an int variable already called songqiao, we can create an alias to it by using the & sign in the declaration:

int &sonny = songqiao;

So here, we made sonny a reference to songqiao.

Now when we make changes to sonny (add 1, subtract 2, etc), songqiao also changes.

  • Anything we do to the reference also happens to the original.
  • Aliases cannot be changed to alias something else.

Pass-By-Reference

When we passed parameters to a function, we used normal variables and that’s known as pass-by-value. But because the variables passed into the function are out of scope, we can’t actually modify the value of the arguments.

Pass-by-reference refers to passing parameters to a function by using references. When called, the function can modify the value of the arguments by using the reference passed in.

This allows us to:

  • Modify the value of the function arguments.
  • Avoid making copies of a variable/object for performance reasons.

The following code shows an example of pass-by-reference. The reference parameters are initialized with the actual arguments when the function is called:

void swap_num(int &i, int &j) {

  int temp = i;
  i = j;
  j = temp;

}

int main() {

  int a = 100;
  int b = 200;

  swap_num(a, b);

  std::cout << "A is " << a << "\n";
  std::cout << "B is " << b << "\n";

}

When swap_num() is called, the values of the variables a and b will be modified because they are passed by reference.  Notice that the int &i and int &j are the parameters of the function swap_num(). When swap_num() is called, the values of the variables a and b will be modified because they are passed by reference. 

Suppose we didn’t pass-by-reference here and have the parameters as simply int i and int j in the swap_num()function, then i and j would swap, but a and b wouldn’t be modified.

To reiterate, using references as parameters allows us to modify the the arguments’ values. This can be very useful in a lot cases.

Const

The const keywords tells the compiler that we won’t change something. For example, in the following code, we are telling the compiler that the double variable pi will stay at 3.14through out the program:

double const pi = 3.14;

If we try to change pi, the compiler will throw an error.

Sometimes, we use const in a function parameter; this is when we know for a fact that we want to write a function where the parameter won’t change inside the function. Here’s an example:

int triple(int const i) {
  return i * 3;
}

In this example, we are not modifiying the i. If inside the function triple(), the value of i is changed, there will be a compiler error.

So to save the computational cost for a function that doesn’t modify the parameter value(s), we can actually go a step further and use a const reference:

int triple(int const &i) {
  return i * 3;
}

This will ensure the same thing: the parameter won’t be changed. However, by making i a reference to the argument, this saves the computational cost of making a copy of the argument.

Memory Address

We haved learned about references (aliases), which are created by using the & symbol in a variable declaration. But the & sign can have another meaning.

The “address of” operator, &, is used to get the memory address, the location in the memory, of an object.

We can find where the variable is stored on the computer by printing out:

std::cout << &porcupine_count << "\n";

It will return something like:

0x7ffd7caa5b54

This is a memory address represented in hexadecimal. A memory address is usually denoted in hexadecimal instead of binary for readability and conciseness.

The double meaning of the & symbol can be tricky at first, so make sure to note:

  • When & is used in a declaration, it is a reference operator.
  • When & is not used in a declaration, it is an address operator.

Pointers

pointer variable is mostly the same as other variables, which can store a piece of data. Unlike normal variables, which store a value (such as an intdoublechar), a pointer stores a memory address.

While references are a newer mechanism that originated in C++, pointers are an older mechnaism that was inherited from C. We recommend avoiding pointers as much as possible; usually, a reference will do the trick. However, you will see pointers a lot in the wild, particularly in older projects, where they are used in a very similar way to references.

Pointers must be declared before they can be used, just like a normal variable. They are syntactically distinguished by the *, so that int* means “pointer to int“ and double* means “pointer to double“.

So suppose we have a variable called gum:

int gum = 8;

We can create a pointer to it by:

int* ptr = &gum;
  • int* makes it a pointer rather than a normal variable.
  • ptr is the pointer name.
  • &gum is the memory address of the other variable gum.

Syntactically, spaces around * do not matter, but the best practice is to have it after the data type.

int* number;
int *number;
int * number;

Dereference

Way to obtain the value pointed to by the pointer.

he asterisk sign * a.k.a. the dereference operator is used to obtain the value pointed to by a variable. This can be done by preceding the name of a pointer variable with *.

int blah = *ptr;

The double meaning of the * symbol can be tricky at first, so make sure to note:

  • When * is used in a declaration, it is creating a pointer.
  • When * is not used in a declaration, is is a dereference operator.

Null Pointer

When we declare a pointer variable like so, its content is not intialized:

int* ptr;

In other words, it contains an address of “somewhere”, which is of course not a valid location. This is dangerous! We need to initialize a pointer by assigning it a valid address.

But suppose we don’t know where we are pointing to, we can use a null pointer.

nullptr is a new keyword introduced in C++11. It provides a typesafe pointer value repsenting an empty pointer.

We can use nullptr like so:

int* ptr = nullptr;

In older C/C++ code, NULL was used for this purpose. nullptr is meant as a modern replacement to NULL.

Manual Memory Management

To avoid wastage of memory, you can dynamically allocate any memory required during runtime using the new and delete operators in C++.

int main() {
  // memory allocation
  ptr = new int[num];
  ...
  // memory is released
  delete ptr;
}

If you create something with new, at some point you must delete it. When something is not deleted, it will cause a memory leak.

The Rule of Three

The rule of three is a rule of thumb in C++ that claims that if a class defines one of the following special member functions, it should define all three:

  • Destructor
  • Copy constructor
  • Copy assignment operator

The Rule of Five

With C++11, a new rule emerged: the rule of five. This adds two more special functions to the rule of three list:

  • Destructor
  • Copy constructor
  • Copy assignment operator
  • Move constructor
  • Move assignment operator

As you can see, manual memory management is difficult and old-fashioned. Instead of using new and delete, there’s something in the standard library that will make your life a lot easier

Standard Library Smart Pointers

A smart pointer is an abstract data type that was popularized by C++ during the early 1990’s. It simulates a pointer while providing additional features, such as automatic memory management.

In the standard library, we have the following:

  • unique_ptr: a smart pointer that owns and manages another object through and disposes of that object when the unique_ptr goes out of scope.
  • shared_ptr: a smart pointer that retains shared ownership of an object through a pointer. Several shared_ptr objects may own the same object.

// palindrome finder
#include <iostream>

// Define is_palindrome() here:
bool is_palindrome(std::string text) {
  
  std::string reversed_text = "";
  
  for (int i = text.size() - 1; i >= 0; i--) {
    reversed_text += text[i];
  }
  
  if (reversed_text == text) {
    return true;
  }
  
  return false;
  
}

int main() {
  
  std::cout << is_palindrome("madam") << "\n";
  std::cout << is_palindrome("ada") << "\n";
  std::cout << is_palindrome("lovelace") << "\n";
  
}

Links

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.