Basics of C++ Class

C++ class is a custom data type user defines, which is called user-defined type.
A data type in C++ represents certain types of data.
For example, there are built-in types such as int and double which represent integer and decimal numbers.
Declaring a variable with a data type requires memory and you can perform operations such as addition, subtraction, multiplication, and division with it.
You can also use those variables as function arguments, parameters, and return values.
In that sense, you can define your own data type to operate like built-in data type variables.

Why do we need a user-defined type?

A user-defined type is really necessary when you have to write a program that deals with real-world problems.

Let’s say you are trying to write a program that manages the money that includes coins per person.
You will need to know the number of dollars, quarters, dimes, nickels, and pennies.
For that, you will at least need five integers and you have to carry all those variables in the program which is very error-prone.

It may not be a big problem if you only need to manage money for one person.
But what if you have thousands of people?
It will be impossible to maintain with plain old data types like int.

That’s where a user-defined type becomes the hero.
In this case, the user-defined type will include dollars and all the coins but will act like just one data type – Money.

Example

Let’s actually take a look at how you declare a user-defined type and use it.
I am going to use struct in this example.
(struct and class are really the same except one thing which I will go over later.)

#include <iostream>

using namespace std;

// struct or class is a keyword
// Money is the name of the type.
// {} gives you the scope of the type
// There are five int variables which are called member variables.
struct Money
{
    int numDollars;
    int numQuarters;
    int numDimes;
    int numNickels;
    int numPennies;
};

// you can pass Money as function argument
void printTotalMoney(const Money &money)
{
    // you can use member variables just like built-in data type
    double totalMoney = 
        money.numDollars + 
        money.numQuarters * 0.25 + 
        money.numDimes * 0.1 +
        money.numNickels * 0.05 +
        money.numPennies * 0.01;
    
    cout << "I have total $" << totalMoney << endl;
}

int main()
{
    // declare a variable with data type Money and variable name myWage
    // just like int or double
    Money myWage;
    
    // use . operator in order to access member variable
    // there will be 10 dollars
    myWage.numDollars = 10;
    
    // 2 quarters
    myWage.numQuarters = 2;
    
    // 3 dimes
    myWage.numDimes = 3;
    
    // 4 nickels
    myWage.numNickels = 4;
    
    // 5 pennies
    myWage.numPennies = 5;
    
    printTotalMoney(myWage);
    return 0;
}

The example code declares a UDT called Money.
It has five variables which are called member variables. (member variable of data type called Money)
Once you declare a Money variable, you can use it just like any other variable with built-in types.
In the example code, I used ‘Money’ struct as a function argument which is also legal!
You can use ‘.’ operator in order to access member variables of Money.

One important thing we need to keep in mind is that a compiler needs to know the layout of the struct before it’s used.
In other words, you cannot declare a variable with Money data type before you declare Money struct.

class, private by default
struct, public by default

We observed It is much easier to have a Money data type instead of multiple integers.
However, there is a potential problem we need to deal with.

The problem is that anyone can access the member variables of Money.
It is fine in the above example code since it’s very simple and easy to fix even if there are any bugs.
However, once the program grows and as many functions may access the member variables, errors will likely happen and it will take a long time to debug where it went wrong.

Is there any way to control the access so it would be hard to make mistakes?
That’s where ‘class’ is coming to rescue.

By default, every member variable in a struct is public which means any code can access the members.
However, a class is the exact opposite of a struct.
Every member variable in a class is private by default that no one outside of the class can access the members.
In other words, private member variables can only be used by the class!

#include <iostream>

using namespace std;

// members in a class is private by default
// you don't have type private: explicitly in class
class Money
{
    int numDollars;
    int numQuarters;
    int numDimes;
    int numNickels;
    int numPennies;
};

// this is essentially the same as the above
// you have to type private: explicitly to make members private here
// struct Money
// {
// private:
//     int numDollars;
//     int numQuarters;
//     int numDimes;
//     int numNickels;
//     int numPennies;
// };

int main()
{
    Money temp;
    
    // error! can't access private members!
    // this will cause a compilation error
    // what can we do now???
    temp.numDollars = 10;
    
    return 0;
}

Then, how will Money be useful for us since we can’t access the member variables?
We can make the members public so it can be accessed.

// you have to type public: explicitly since members are 
// private by default in a class
class Money
{
public:
    int numDollars;
    int numQuarters;
    int numDimes;
    int numNickels;
    int numPennies;
};

// this is same as the above.
// members in a struct is public by default
// so you don't have to type public: explicitly like the above
// struct Money
// {
//     int numDollars;
//     int numQuarters;
//     int numDimes;
//     int numNickels;
//     int numPennies;
// };

But there isn’t any point in using class if it will have all public members.
In fact, it is highly discouraged to have public member variables in C++.

Member functions

Well, we need to think about what we actually want to do with the class.
It is clear that we want to be able to print total money and we also want to initialize the money to 0 and be able to add money.
That sounds like we will need some functions to do the work.

Just like we are able to have member variables inside class or struct, we can also have functions inside a class, which is called member functions.
We can also decide if member functions will be either public or private.
In this case, let’s implement some public functions to do the works.

Member function implementation inside class declaration

Member functions can be implemented inside the class declaration.

#include <iostream>

using namespace std;

class Money
{
    // remember! class members are private by default!
    // it means we don't even have to write the word 'private'
    int numDollars;
    int numQuarters;
    int numDimes;
    int numNickels;
    int numPennies;
    
// here we need to mark it public since member functions will 
// need to be exposed outside the class
public:
    // initialize the money to 0
    // this is to be called in the beginning
    void initMoney()
    {
        numDollars = 0;
        numQuarters = 0;
        numDimes = 0;
        numNickels = 0;
        numPennies = 0;
    }

    // add dollars, quarters, dimes, nickels and pennis
    void addDollars(int dollars)
    {
        numDollars += dollars;
    }

    void addQuarters(int quarters)
    {
        numQuarters += quarters;
    }

    void addDimes(int dimes)
    {
        numDimes += dimes;
    }

    void addNickels(int nickels)
    {
        numNickels += nickels;
    }

    void addPennies(int pennies)
    {
        numPennies += pennies;
    }

    // print total money
    void printTotalMoney()
    {
        // you can use member variables just like built-in data type
        double totalMoney = 
            numDollars + 
            numQuarters * 0.25 + 
            numDimes * 0.1 +
            numNickels * 0.05 +
            numPennies * 0.01;
        
        cout << "I have total $" << totalMoney << endl;
    }
};

int main()
{
    Money myWage;
    
    // you can call member functions using . operator
    myWage.initMoney();
    
    // add 10 dollars
    myWage.addDollars(10);
    
    // add 2 quarters
    myWage.addQuarters(2);
    
    // add 3 dimes
    myWage.addDimes(3);
    
    // add 4 nickels
    myWage.addNickels(4);
    
    // add 5 pennies
    myWage.addPennies(5);
    
    // print total money
    myWage.printTotalMoney();
    return 0;
}

By having member functions, you can control the access and thus protect the member variables.
You can only reset, add or print the money that it is impossible to apply other operations such as subtraction, multiplication, and division.

One thing I would like to note that it is not recommended to implement member functions inside the class declaration.

Member function implementation outside the class declaration

You can implement member function outside the declaration which is the more recommended way.
One thing to note is that you have to tell the function belongs to the class by typing ‘<class name>::’ before the function name.

#include <iostream>

using namespace std;

class Money
{
    // remember! class members are private by default!
    // it means we don't even have to write the word 'private'
    int numDollars;
    int numQuarters;
    int numDimes;
    int numNickels;
    int numPennies;
    
// here we need to mark it public since member functions will 
// need to be exposed outside the class
public:
    // initialize the money to 0
    // this is to be called in the beginning
    void initMoney();

    // add dollars, quarters, dimes, nickels and pennis
    void addDollars(int dollars);
    void addQuarters(int quarters);
    void addDimes(int dimes);
    void addNickels(int nickels);
    void addPennies(int pennies);

    // print total money
    void printTotalMoney();
};

// please note Money:: is necessary to indicate the function is member of the class
void Money::initMoney()
{
    numDollars = 0;
    numQuarters = 0;
    numDimes = 0;
    numNickels = 0;
    numPennies = 0;
}

void Money::addDollars(int dollars)
{
    numDollars += dollars;
}

void Money::addQuarters(int quarters)
{
    numQuarters += quarters;
}

void Money::addDimes(int dimes)
{
    numDimes += dimes;
}

void Money::addNickels(int nickels)
{
    numNickels += nickels;
}

void Money::addPennies(int pennies)
{
    numPennies += pennies;
}

void Money::printTotalMoney()
{
    // you can use member variables just like built-in data type
    double totalMoney = 
        numDollars + 
        numQuarters * 0.25 + 
        numDimes * 0.1 +
        numNickels * 0.05 +
        numPennies * 0.01;
    
    cout << "I have total $" << totalMoney << endl;
}

int main()
{
    Money myWage;
    
    // you can call member functions using . operator
    myWage.initMoney();
    
    // add 10 dollars
    myWage.addDollars(10);
    
    // add 2 quarters
    myWage.addQuarters(2);
    
    // add 3 dimes
    myWage.addDimes(3);
    
    // add 4 nickels
    myWage.addNickels(4);
    
    // add 5 pennies
    myWage.addPennies(5);
    
    // print total money
    myWage.printTotalMoney();
    return 0;
}

Constructor

Although member functions made the code better than before there is one thing that bothers – initMoney().
All it does is just initializing the money to 0 in the beginning and it’s very easy to forget calling the function.
What would happen if we forget to init? It really depends on a compiler and we might get some garbage dollars.
In addition to that, what if we want to start Money with a certain amount other than 0?
Do we need to implement another member function to set money?

What we want here is to initialize the money to a certain amount (or 0) when the Money variable is declared.
Fortunately, C++ provides a constructor that does the work!
A constructor is a function that will be called when a class becomes a being. (i.e., when Money variable is declared)
It is supposed to initialize all the member variables properly before referred.

#include <iostream>

using namespace std;

class Money
{
    // remember! class members are private by default!
    // it means we don't even have to write the word 'private'
    int numDollars;
    int numQuarters;
    int numDimes;
    int numNickels;
    int numPennies;
    
// here we need to mark it public since member functions will 
// need to be exposed outside the class
public:
    // constructor.
    // it doesn't return anything since object is already allocated
    // this is only supposed to initialize the members
    // please note that name of constructor must match name of the class
    Money(
        int dollars = 0,
        int quarters = 0,
        int dimes = 0,
        int nickels = 0,
        int pennies = 0);

    // add dollars, quarters, dimes, nickels and pennis
    void addDollars(int dollars);
    void addQuarters(int quarters);
    void addDimes(int dimes);
    void addNickels(int nickels);
    void addPennies(int pennies);

    // print total money
    void printTotalMoney();
};

// constructor can be implemented inside the class
Money::Money(
    int dollars,
    int quarters,
    int dimes,
    int nickels,
    int pennies)
{
    numDollars = dollars;
    numQuarters = quarters;
    numDimes = dimes;
    numNickels = nickels;
    numPennies = pennies;
}

void Money::addDollars(int dollars)
{
    numDollars += dollars;
}

void Money::addQuarters(int quarters)
{
    numQuarters += quarters;
}

void Money::addDimes(int dimes)
{
    numDimes += dimes;
}

void Money::addNickels(int nickels)
{
    numNickels += nickels;
}

void Money::addPennies(int pennies)
{
    numPennies += pennies;
}

void Money::printTotalMoney()
{
    // you can use member variables just like built-in data type
    double totalMoney = 
        numDollars + 
        numQuarters * 0.25 + 
        numDimes * 0.1 +
        numNickels * 0.05 +
        numPennies * 0.01;
    
    cout << "I have total $" << totalMoney << endl;
}

int main()
{
    Money myWage(10, 2, 3, 4, 5);
    
    // print total money
    myWage.printTotalMoney();
    return 0;
}

Recommended implementation of constructor

As you can see from the above, the constructor takes dollars, quarters, dimes, nickels, dimes, and pennies as its arguments and sets the money to them.
However, there is a better way to initialize – using an initializer list.

// Money::Money(
//     int dollars,
//     int quarters,
//     int dimes,
//     int nickels,
//     int pennies)
// {
//     numDollars = dollars;
//     numQuarters = quarters;
//     numDimes = dimes;
//     numNickels = nickels;
//     numPennies = pennies;
// }

// this is using initializer list and recommended way
Money::Money(
    int dollars,
    int quarters,
    int dimes,
    int nickels,
    int pennies) : 
    numDollars(dollars), 
    numQuarters(quarters), 
    numDimes(dimes), 
    numNickels(nickels), 
    numPennies(pennies)
{}

Why is using the initializer list recommended over the other one?
Please note that a class can have another class as a member variable and you will need to call the constructor of the class member.
Everyone tries this at least once but this doesn’t work!

class VendingMachine 
{
    Money money;
public:
    VendingMachine(int dollars, int quarters, int dimes, int nickels, int pennies)
    {
        // creates a local variable which is then ignored when it goes out of scope
        Money money(dollars, quarters, dimes, nickels, pennies);
        
        // OR
        // creates an un-named local Money object which is then tossed away
        Money(dollars, quarters, dimes, nickels, pennies);
        
        // this works, but why bother with it when ctor initializer will work for you?
        // this is really calling copy constructor which I am going to talk in other post
        money = Money(dollars, quarters, dimes, nickels, pennies);
    }
};

The initializer list will solve all the problems here.
It will actually call the constructor of Money properly during the construction of VendingMachine.

class VendingMachine 
{
    Money money;
public:
    VendingMachine(int dollars, int quarters, int dimes, int nickels, int pennies) : 
        money(dollars, quarters, dimes, nickels, pennies) // this is actually calling constructor of Money
    {}
};

Conclusion

We have taken a look at the basics of C++ user defined types – class and struct.
However, there are many more topics to learn about class as this post just explained really basic stuff.
I am going to have other posts that will explain const for member functions, operator overloading, copy constructor & destructor & assignment operator, inheritance & virtual, and pointers to member functions.
Thank you for reading the post!

C++ Filestream

In C++, you can interact (read/write) with disk files using filestream classes.
The C++ filestream is very similar to standard cin and cout streams.
Just like cin and cout, there are two classes for filestream: ifstream for input and ofstream for output.
For the input stream, you can imagine there is a stream connected to disk file and characters are copied from the file to the stream and your program is reading characters from the stream.
For the output stream, you can imagine the opposite way of the input stream: your program writes to the stream and stream to the disk file.

Basic Usage of Filestream

There are two classes to interact with disk files: ifstream and ofstream.
Although usage of the filestream is very similar to cin and cout there are some differences worthwhile to note.
You don’t need to create an object for cin and cout because they are global objects and will be created/destroyed depending on the start/end of the program.
However, you have to create your own objects for ifstream and ofstream manually so you can control which files to read and write.

You need to include a header called ‘fstream’ in order to use filestreams.
And you have two choices to open the file.
1. you can provide the file name (and path if the file is not located in the same directory as the program) in the constructor of ifstream or ofstream.
2. you can explicitly call ‘open’ member function with the filename.

Let’s take a look at some example here

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    // first option
    ifstream inptuFileStream1("/some/filename/with/path");
    ofstream outputFileStream1("/some/filename/with/path");
    
    // second option
    ifstream inputFileStream2;
    ofstream outputFileStream2;
    
    inputFileStream2.open("/some/filename/with/path");
    outputFileStream2.open("/some/filename/with/path");
    
    return 0;
}

Disk files are managed by the operating systems (create/update/delete) and C++ facilities actually calls OS subroutines internally in order to work with those disk files.
Creating filestream objects or calling ‘open’ with the filename is actually establishing the relationship with those files: ifstream for read and ofstream for write.

Once the relationship is established, you can use those filestreams just like cin/cout.
After opening the file it is very important to test if the file is successfully opened but I will talk about that later in this post.
Let’s quickly take a look at how the read/write operations are done with file streams.

// read from filestream and place the data to string
string data;
int intData;
inputFileStream1 >> data >> intData;

// write to filestream
string data2 = "this is data to write";
int intData2 = 10;
outputFileStream1 << intData2 << data2;

It’s very simple and in fact, it works exactly like cin and cout once the relationship with the disk file is set correctly.

Once you are done with the filestream, it is generally considered a good practice to close the stream telling the OS that the connection to the disk file should be closed now so the state of the file can be updated properly.
For the input stream, you might not care that much since you probably didn’t change the file at all during the read.
However, it might be crucial to update the state for the output stream since the filesystem usually buffers data internally for efficiency which means that those data in the buffers need to be properly flushed to the file.

Fortunately, it is very easy to close the file streams.

// close the input filestream
inputFileStream1.close();

// close the output filestream
outputFileStream1.close();

What if you want to read files multiple times from the beginning?
You just need to make sure to clear internal state bits of the filestream, which I will discuss later in the post, and close and reopen the stream.

Filestream Errors

We have taken a quick look at how to open a file and read/write to and from the file.
However, we need to understand filestream errors in order to understand and use filestream better.
A stream object has internal bits as data members that remembers the state.
It is important to understand these because the stream will not work properly if there is any error bit is turned on.
In this section, I will mostly focus on the input stream case since it cares about errors the most.

Here are a few examples of state bits.

good

The stream is considered ‘good‘ after the file is successfully opened and has not had any problems during read or write.
If there is any error it will turn on corresponding error bit and it’s not in ‘good’ state anymore.
Consequently, all the read/write stream operation will be no-op.
It will stay the same until ‘clear()‘ function is called on the stream which clears all the error bits.
Please note that closing the filestream doesn’t clear the bits. You have to explicitly call ‘clear()‘ unless you use fresh new stream.
In short, the stream needs to be in ‘good‘ state to do read or write operation.

Member function for checking ‘good‘ is good().

fail

The stream is considered ‘fail‘ when it fails to read from the input stream.
The common example for this is type errors such that trying to read string and place to int variable.
In this case, it will turn on the ‘fail‘ bit and thus it’s not in ‘good‘ state anymore until it’s clear() is called.

eof

This means the stream reached the end of the file and is not able to read anymore.
This is not really an error but it is still necessary to indicate reading the file is done.
Just like ‘fail‘, when ‘eof‘ is set, the stream is not in ‘good‘ state anymore.

It is worthwhile to note a couple of things regarding ‘eof‘.

  • It is set only after attempting to read after reading the last character of the file. On the other hand, ‘eof‘ is not set when it reads the last character.
  • fail‘ bit will be also set when ‘eof‘ is encountered.
  • User shouldn’t test ‘eof‘ to control the reading since it is only raised when end-of-file is reached. But what if stream read failed before the end? Testing ‘eof‘ will not be able to catch anything.

I am not going to discuss ‘bad‘ bit here since I think it’s more related to hardware error and there isn’t anything we can do about it.

Detecting and Handling Errors

After going over some important error bits we need to be able to detect and handle those errors.

// this is a member function and tells you if there isn't any errors
bool good();

// conversion operator returns same value as good() above.
// please note that >> operator returns the stream object
// and thus conversion operator will work the same.
if (inputFileStream)
if (!inputFileStream)
if (inputFileStream >> data)
while (inputFileStream >> data) 

// returns true if the file is opened successfully.
bool is_open();

// returns true if fail bit is set due to input failure
bool fail();

// returns true if eof bit is set
bool eof();

// resets all the error bits. clear the error state.
// this is necessary to resume the stream.
// otherwise, the disk IO operations will be just noop until it's cleared
void clear();

Handy Member Functions for Reading

There are other ways to read inputs instead of using >> operator.
I will briefly explain a couple of functions.

istream& get(char&);
cin.get(charVar);

Reads one character to provided variable.
It does not skip anything. (For ex. >> operator just skips characters like spaces, tabs, and newlines)
This returns the reference to the stream object itself.

istream& getline(char *array, int n);
inputFile.getline(bufferCharArr, bufferLen);

This function reads characters to the provided buffer until it reaches ‘\n’ or ‘n’ – 1 characters are read.
It terminates the buffer with ‘\0’ regardless so you will get valid cstring after the operation.
‘n’ needs to be less than the buffer size in order to prevent any buffer overflows.
For your convenience, ‘\n’ is removed from the stream and not placed onto buffers because you typically don’t want to read newlines.
If the buffer array is filled without finding the ‘\n’, the input operation will fail the same way as invalid input error to notify you newline was not found.

istream& getline(istream&, std::string&);

Special function provided by <string> library.
This function reads the entire line into the provided string variable.
You don’t have to worry about buffer overflow since string grows as much as the memory permits.
I personally think this is the most recommended way to process a file line by line.

Code Example

This code example does the following operations.

  1. read a file that has a few integers.
  2. write to another file with a value multiplied by 2
#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    // input file in the same directory as the program.
    ifstream inputFile("data.txt");
    
    // check if the file is opened successfully
    if (!inputFile.is_open())
    {
        cout << "File was not successfully opened." << endl;
        return -1;
    }
    
    // prepare output stream to write result
    ofstream outputFile("result.txt");
    
    // check if the file is opened successfully
    if (!outputFile.is_open())
    {
        cout << "File was not successfully opened." << endl;
        return -1;
    }
    
    int data;
    // read until input failure happens
    while (inputFile >> data)
    {
        outputFile << data * 2 << endl;
    }
    
    inputFile.close();
    outputFile.close();
    
    return 0;
}

C++ Standard Library C-string Functions

C-string is a char array terminated with a null byte(‘\0’), which is the original string that was used since C and early C++.
C/C++ standard library provides useful C-string functions.
The header you need to include to use C-string functions is <cstring>.
In this post, I am going to explain some popular C-string functions with example codes.

Before diving into the examples, it is worthwhile to note that C-string is entirely different from the C++ String class which means you cannot use C string standard library functions with C++ String class.

size_t strlen(const char *str)

Returns the length of the provided char array that doesn’t count the null byte.
size_t is usually a typedef of some larger int such as unsigned.
Although you can directly assign the return value to int you might need to typecast to avoid a compiler warning.

Example Code

#include <iostream>

using namespace std;

// this is an example implementation of the function
// you just want to import cstring header and use the function there
// as it will be far better and optimized than this one.
size_t strlen(const char *str)
{
    size_t len = 0;
    for (; *s; ++len, ++s);
    return len;
}

int main()
{
    char *temp1 = "thishas8";
	cout << strlen(temp1) << endl;
	
	char temp2[] = "thishas8";
	cout << strlen(temp2) << endl;
    return 0;
}

// output
// 8
// 8

int strcmp(const char *str1, const char *str2)

Lexicographically compare s1 and s2 and returns the following result.

  • < 0 if two strings don’t match and the first mismatch char of str1 is less than the one of str2
  • 0 if two string matches
  • > 0 if two strings don’t match and the first mismatch char of str1 is greater than the one of str2

The comparison stops when strings are terminated or unequal characters are found.

Example Code

#include <iostream>

using namespace std;

// this is an example implementation of the function
// you just want to import cstring header and use the function there
// as it will be far better and optimized than this one.
int strcmp(const char *str1, const char *str2)
{
    for (; *str1 && *str2 && *str1 == *str2; ++str1, ++str2);
    if (*str1 == *str2)
    {
        return 0;
    }
    else if (*str1 < *str2)
    {
        return -1;
    }
    else
    {
        return 1;
    }
}

int main()
{
    char *temp1 = "this is an example";
    char *temp2 = "this is an example";
    cout << strcmp(temp1, temp2) << endl;
    
    char *temp3 = "this is an example!";
    cout << strcmp(temp1, temp3) << endl;
    
    char *temp4 = "this is an exampl";
    cout << strcmp(temp1, temp4) << endl;
    
    char *temp5 = "this is a different example";
    cout << strcmp(temp1, temp5) << endl;
    return 0;
}

int strncmp(const char *s1, const char *s2, size_t n)

Lexicographically compare s1 and s2 up to ‘n’ characters and returns the following result.

  • < 0 if two strings don’t match and the first mismatch char of str1 is less than the one of str2
  • 0 if two string matches
  • > 0 if two strings don’t match and the first mismatch char of str1 is greater than the one of str2

The comparison stops when strings are terminated or unequal characters are found or have compared ‘n’ characters.

Code Example

#include <iostream>

using namespace std;

// this is an example implementation of the function
// you just want to import cstring header and use the function there
// as it will be far better and optimized than this one.
int strncmp(const char *str1, const char *str2, size_t n)
{
    size_t bytesCompared = 0;
    for (size_t i = 0; 
         i < n && *str1 && *str2 && *str1 == *str2; 
         ++i, ++str1, ++str2, ++bytesCompared);
    
    if (bytesCompared == n || *str1 == *str2)
    {
        return 0;
    }
    else if (*str1 < *str2)
    {
        return -1;
    }
    else
    {
        return 1;
    }
}

int main()
{
    char *temp1 = "this is an example";
    char *temp2 = "this is an example";
    cout << strncmp(temp1, temp2, 18) << endl;
    
    char *temp3 = "this is an example!";
    cout << strncmp(temp1, temp3, 18) << endl;
    
    char *temp4 = "this is an exampl";
    cout << strncmp(temp1, temp4, 18) << endl;
    
    char *temp5 = "this is a different example";
    cout << strncmp(temp1, temp5, 18) << endl;
    
    char *temp6 = "this is";
    cout << strncmp(temp1, temp6, 7) << endl;
    return 0;
}

char *strcpy(char *dest, const char *src)

Copies string from src to dest and return dest string pointer.
But you need to make sure there is enough room in dest to prevent any buffer overflow.

Example Code

#include <iostream>

using namespace std;

// this is an example implementation of the function
// you just want to import cstring header and use the function there
// as it will be far better and optimized than this one.
char *strcpy(char *dest, const char *src)
{
    char *iter = dest;
    while (*src)
    {
        *iter++ = *src++;
    }
    
    *iter = '\0';
    return dest;
}

int main()
{
    char *src = "this is an example";
    char dest[19] = {0};
    
    cout << "[" << dest << "]" << endl;
    cout << "[" << strcpy(dest, src) << "]" << endl;
    cout << "[" << dest << "]" << endl;
    cout << "[" << src << "]" << endl;
    return 0;
}

char *strncpy(char *dest, const char *src, size_t n)

Copy exactly ‘n’ characters from src to dest.
If the length of ‘src’ string is less than ‘n’ dest will be padded with 0 until ‘n’ characters are copied.
If the length of ‘src’ string is greater than ‘n’ dest will not have null byte – ‘\0’.
In that case, ‘dest’ string is not null byte terminated which would allow buffer overflow.
Please note that ‘dest’ string needs to have enough space to copy from ‘src’.

Code Example

#include <iostream>

using namespace std;

// this is an example implementation of the function
// you just want to import cstring header and use the function there
// as it will be far better and optimized than this one.
char *strncpy(char *dest, const char *src, size_t n)
{
    char *iter = dest;
    for (size_t i = 0; i < n; ++i, ++iter)
    {
        if (*src)
        {
            *iter = *src++;    
        }
        else
        {
            *iter = '\0';
        }
    }
    
    if (!*src)
    {
        *iter = '\0';    
    }
    
    return dest;
}

int main()
{
    char src[] = "this is an example";
    char dest[sizeof(src)] = {0};
    
    cout << "[" << strncpy(dest, src, sizeof(src)) << "]" << endl;
    cout << "[" << dest << "]" << endl;
    
    char dest2[sizeof(src)] = {0};
    cout << "[" << strncpy(dest2, src, 4) << "]" << endl;
    cout << "[" << dest2 << "]" << endl;
    
    return 0;
}

char *strcat(char *dest, const char *src)

Appends the string ‘src’ to ‘dest’ and returns ‘dest’.
The null byte in ‘dest’ will be overwritten and will be put after src is appended.
Make sure there is enough space in ‘dest’.

Code Example

#include <iostream>

using namespace std;

// this is an example implementation of the function
// you just want to import cstring header and use the function there
// as it will be far better and optimized than this one.
char *strcat(char *dest, const char *src)
{
    char *iter = dest;
    for (; *iter; ++iter);
    
    while (*src)
    {
        *iter++ = *src++;
    }
    
    *iter = '\0';    
    
    return dest;
}

int main()
{
    char dest[100] = {0};
    
    cout << "[" << strcat(dest, "this ") << "]" << endl;
    cout << "[" << strcat(dest, "is ") << "]" << endl;
    cout << "[" << strcat(dest, "an ") << "]" << endl;
    cout << "[" << strcat(dest, "example") << "]" << endl;
    cout << "[" << dest << "]" << endl;
    return 0;
}

char *strncat(char *dest, const char *src, size_t n)

Appends the string ‘src’ to ‘dest’ for first ‘n’ characters and returns ‘dest’.
If ‘src’ is shorter than ‘n’ then only copy ‘src’ until it reaches null byte.
Make sure ‘dest’ has enough space to copy from ‘src’.

Code Example

#include <iostream>

using namespace std;

// this is an example implementation of the function
// you just want to import cstring header and use the function there
// as it will be far better and optimized than this one.
char *strncat(char *dest, const char *src, size_t n)
{
    char *iter = dest;
    for (; *iter; ++iter);
    
    for (size_t i = 0; i < n && *src; ++i)
    {
        *iter++ = *src++; 
    }
    
    *iter = '\0';    
    
    return dest;
}

int main()
{
    char dest[100] = {0};
    
    cout << "[" << strncat(dest, "this ", 6) << "]" << endl;
    cout << "[" << strncat(dest, "is ", 3) << "]" << endl;
    cout << "[" << strncat(dest, "an ", 0) << "]" << endl;
    cout << "[" << strncat(dest, "example", 4) << "]" << endl;
    cout << "[" << dest << "]" << endl;
    return 0;
}

char *strstr(const char *src, const char *sub)

Returns a pointer to the first occurrence of ‘sub’ string in ‘src’.
It will return a null pointer if ‘sub’ is not found in ‘src’.

Code Example

#include <iostream>

using namespace std;

// this is an example implementation of the function
// you just want to import cstring header and use the function there
// as it will be far better and optimized than this one.
char *strstr(const char *src, const char *sub)
{
    char *iter = (char *)src;
    for (; *iter; ++iter)
    {
        char *iterSrc = iter;
        char *iterSub = (char *)sub;
        while (*iterSrc == *iterSub)
        {
            ++iterSrc;
            ++iterSub;
        }
        
        if (!*iterSub)
        {
            return iter;
        }
    }
    
    return 0;
}

// this is for testing purpose
char *strncpy(char *dest, const char *src, size_t n)
{
    char *iter = dest;
    for (size_t i = 0; i < n; ++i, ++iter)
    {
        if (*src)
        {
            *iter = *src++;    
        }
        else
        {
            *iter = '\0';
        }
    }
    
    if (!*src)
    {
        *iter = '\0';    
    }
    
    return dest;
}

int main()
{
    char *src = "This is an example";
    char *sub = "exam";
    
    char *subFound = strstr(src, sub);
    char result[80] = {0}; 
    cout << "[" << strncpy(result, subFound, 4) << "]" << endl;
    cout << "[" << result << "]" << endl;
    
    char *sub2 = "exams";
    subFound = strstr(src, sub2);
    cout << "[" << subFound << "]" << endl;
    
    return 0;
}

Intro to Array data structure Part 2 – 2D Array

Continuing from the last post I am going to discuss more about the array data structure which is 2D array.
In this post, I will focus on the basic concept and usage.

What is 2D Array?

2D array is basically array within array.
Typically array contains specified data type in its element.
However, it is possible that the element can contain another array instead!

This is a 2D array with 3 rows and 5 columns.
In each row, there is an array of size 5 which is the column size.
In other words, there is an array of size 3 (row) and there is another array size 5 within each element.

Code Example

Here is a code example of usage of the 2D array.

This is a basic access usage example.

#include <iostream>

using namespace std;

int main()
{
    // declaration of 2D array without initializing elements
    int two_d_arr[3][5];
    
    // you can also initialize 2D array just like 1D array
    // you just need to make sure there is an array for each element.
    // 3 rows. Each row contains an array of size 5
    int two_d_arr2[3][5] = {{10, 15, 23, 31, 3}, {13, 72, 29, 19, 85}, {61, 42, 1, 5, 27}};
    
    // when initializing 2D array you don't need to specify row size
    // compiler will figure out row size for you as long as correct column size is provided
    // int two_d_arr2[][5] = {{10, 15, 23, 31, 3}, {13, 72, 29, 19, 85}, {61, 42, 1, 5, 27}};
    
    // you can use for loop to access 2D array
    // this will print out each column per row first
    for (int i = 0; i < 3; ++i)
    {
        for (int j = 0; j < 5; ++j)
        {
            // first bracket [i] represents row index
            // second bracket [j] represents column index
            cout << two_d_arr2[i][j] << " ";
        }
        
        cout << endl;
    }
    cout << endl;
    
    /*
     * output
     * 10 15 23 31 3
     * 13 72 29 19 85
     * 61 42 1  5  27
     */
    
    // or you can switch row and column if you want
    // this will print out each row per column first
    for (int i = 0; i < 5; ++i)
    {
        for (int j = 0; j < 3; ++j)
        {
            // first bracket [i] represents row index
            // second bracket [j] represents column index
            cout << two_d_arr2[j][i] << " ";
        }
        
        cout << endl;
    }
    
    /*
     * output
     * 10 13 61
     * 15 72 42
     * 23 29 1
     * 31 19 5
     * 3  85 27
     */
    
    return 0;
}

Accessing 2D array is really like 1D array except you need to specify row and column index.

Here is another code example that 2D array is used as a function parameter.

#include <iostream>

using namespace std;

// array parameter needs to know column size. 
// but row size is still necessary as another parameter in order to loop it
void printArray(int arr[][5], int rowSize)
{
    for (int i = 0; i < rowSize; ++i)
    {
        for (int j = 0; j < 5; ++j)
        {
            cout << arr[i][j] <<  " ";
        }
        
        cout << endl;
    }
}

int main()
{
    int two_d_arr2[][5] = {{10, 15, 23, 31, 3}, {13, 72, 29, 19, 85}, {61, 42, 1, 5, 27}};
    
    printArray(two_d_arr2, 3);
    return 0;
}

Overall, it’s fairly simple to use 2D array that we just need to provide row and column index accordingly.
Sometimes you can skip row index when declaring 2D array with initialization or using as a function parameter.

Please note that you can have 3D array or more!
You just need to have a proper index when you access them.

Conclusion

We have taken a look at the basics of array data structure.
However, there are still more topics to discuss about array!
I will try to have another post about it.
You might also want to take a look at my post about linked list so you can have apple to apple comparison.

Intro to Array data structure Part 1

Today, we will go over a popular data structure – array.
This is the most basic and fundamental data structure in computer science regardless of any programming language.
Even many complex data structures use array inside the implementation.
Programming language like python doesn’t have array but it provides list instead. (of course, python list is much more flexible and easier to use than C++ array)
In this post, I will go over some important characteristics of array with example code based on C++.

What is Array?

Array is a contiguous piece of memory of a certain data type.
It sounds hard but it will be very clear once you see this picture and example code.

Here, this picture is an array of integer with size 3.

array

Data type is an integer and there are a total of three elements for the array.
Please note that all those three elements are located right next to each other.

The first element of the array contains the integer 10 and 3 for second and 99 for third respectively.
In order to access each element, we need to know the index of the element.
This could be a little counter-intuitive but index of C++ always starts from 0 for array.

For example, if you would like to access the first element you need to know that it’s located at index 0.

Let’s take a look at the C++ code example for array declaration and basic usage.

#include <iostream>

using namespace std;

int main()
{
    //this is just a normal integer variable
    int temp;
    
    // this is an array of integer with size 3
    // please note that [ ] is necessary in order to declare it as an array.
    // you need to provide size inside [ ] unless you are initializing right away.
    // however, if you are initializing the array like below compilre can figure out the size.
    int arr[] = {10, 3, 99};
    
    // 3 inside [ ] means size of the array and it is necessary if you are not initializing like above
    // int arr[3]; 
    
    // you can access each element in the array using index
    // you will see 10 in the screen
    cout << "value of first index of the array:" << arr[0] << endl;
    
    // you can also assign a value to each element using index
    // you will see 11 on the screen
    arr[0] = 11;
    cout << "value of first index of the array after change:" << arr[0] << endl;
    
    // you will see 3 on the screen
    cout << "value of second index of the array:" << arr[1] << endl;
    
    // in this case, arr can only hold int because it's declared as int arr[3]!
    // this will cause a compilation error!
    // arr[2] = "test";
    
    // implicit conversion from 1.1 to 1. bad!
    // double precision will be dropped!
    // you will see 1 on the screen if you print arr[2]
    // arr[2] = 1.1;
    
    return 0;
}

As you see above, an array is merely a container that can hold many elements of the same data type.
You can have an array of double, short, int or string. (Please note that string is already an array of char)

One thing you have to remember is that unlike python an array in C++ can contain only a single data type.
Another words, if you have an array of int, then it can only hold int.
Although you can still assign double, short or any other number related data type it doesn’t necessarily mean it’s correct.

What happens you mistakenly assign 1.1 to arr[2] like the above example?
It will implicitly convert 1.1 to 1 because int cannot take double precision and will only take the integer part.
And the user might be surprised to see 1 on the screen instead of 1.1!

Array access with loop

You can use a loop (for, while or do-while) to access an array efficiently and elegantly.
And I will explain it using the example below.

Let’s say you are to write a program that does the following.
1. Take 5 test scores from the user
2. Find the lowest and highest test score
3. Calculate the average of those scores
4. Print the average, lowest and highest score along with individual test scores.

#include <iostream>

using namespace std;

int main()
{
    const int NUM_TESTS = 5;
    int scores[NUM_TESTS];
    
    for (int i = 0; i < NUM_TESTS; ++i)
    {
        cout << "Please enter a test score:";
        
        // you can use for loop to access each element in the array!
        // value of i will be from 0 to NUM_TESTS - 1 which are 0,1,2,3,4
        // please note that the index of the array always starts from 0!
        cin >> scores[i];
    }

    // in order to find lowest score you need to compare all the element
    // starting from the element at index 0
    // so far the element at index 0 is the lowest test score.
    int lowestScore = scores[0];
    
    // please note that this loop starts at index 1 since you already got the element at index 0
    // i will be 1,2,3,4
    for (int i = 1; i < NUM_TESTS; ++i)
    {
        // update lowestScore if current element is lower
        if (scores[i] < lowestScore)
        {
            lowestScore = scores[i];
        }
    }
    
    cout << "The lowest score is " << lowestScore << endl;
    
    // please refer to explantions for lowest score as this is very similar
    int highestScore = scores[0];
    for (int i = 1; i < NUM_TESTS; ++i)
    {
        if (scores[i] > highestScore)
        {
            highestScore = scores[i];
        }
    }
    
    cout << "The highest score is " << highestScore << endl;
    
    int total = 0;
    for (int i = 0; i < NUM_TESTS; ++i)
    {
        total += scores[i];
    }
    
    double avg = total * 1.0 / NUM_TESTS;
    cout << "Average of test scores:" << avg << endl;
    
    for (int i = 0; i < NUM_TESTS; ++i)
    {
        cout << scores[i] << " ";
    }
    cout << endl;
    
    return 0;
}

As you can see above it’s much easier to access (read/write) the array using loops and that’s usually recommended way unless you want to access some specific location.

Array as a function parameter

In the above example, we observed that you can have a variable for the array.
Then you might ask if the array can be used in function, either as a parameter or return type.


Quick answer is that a function can take an array as a parameter but it cannot return the array.
However, it doesn’t mean returning an array is completely impossible. Instead of returning array directly, it can return a pointer which is essentially the same as array.
Although a pointer to an array and an array is not exactly the same it is still possible to use pointer like an array.
I will discuss the difference between array and pointer in another post.
For now, let’s just focus on array used as a function parameter.
I rewrote above example code using functions instead.

#include <iostream>

using namespace std;

// this is basic syntax to have an array parameter
// you only need to specify the parameter is array. don't need to have size inside [ ]
int getHigestTestScore(int scores[], int size)
{
    // -999 is just a custom error code
    if (size <= 0)
    {
        return -999;
    }
    int highestScore = scores[0];
    for (int i = 1; i < size; ++i)
    {
        if (scores[i] > highestScore)
        {
            highestScore = scores[i];
        }
    }
    
    return highestScore;
}

// you could also specify the size like below and it works fine.
// but it's quite rigid and usually not a good choice
// in the end this function really assumes the array is sizes of 5 which isn't flexible
// and it involves some hard coded number which smells
int getHigestTestScore2(int scores[5])
{
    int highestScore = scores[0];
    for (int i = 1; i < 5; ++i)
    {
        if (scores[i] > highestScore)
        {
            highestScore = scores[i];
        }
    }
    
    return highestScore;
}

int main()
{
    int arr[] = {1,2,3,4,5};
    int high1 = getHigestTestScore(arr);
    
    int high2 = getHigestTestScore2(arr);
    return 0;
}

I think the example code is pretty clear on how to use array as a function parameter.
Although you can use a pointer instead of array I omitted here to just focus on array only.

Pros

  • Random access is allowed which enables fast search
  • No extra space is required like Linked List (i.e., next pointers)
  • Memory locality yields better access performance than Linked List since all the elements are all located next to each other

Cons

  • Adjusting the size is not flexible. You will need to copy/move elements after increasing/decreasing the size.
  • Insertion and deletion of elements are quite expensive because you have to copy/move all the elements after the operations.

Performance

Search – O(1)
Insertion – O(n)
Deletion – O(n)

Conclusion

We have taken a look at basic concepts and usage of array. However, this is not it!
There are many array related topics such as 2D array and array pointer I am going to discuss in next post.

Intro to Linked List data structure

Today, we will go over a popular data structure – linked list.
Linked list may not make much sense for some languages such as python and javascript since there is already a good one such as list.
However, since linked list is quite useful for languages like C++ it is still worthwhile to go over.
In this post I will go over some important characteristics about linked list and strengths and weaknesses.
Please note that all the explanations will be based on C++.

What is Linked List?

Linked list is a data structure that each node is connected like a chain via pointer.
It is one of fundamental data structure in C++ and widely used in C++ standard library (STL).

I believe a picture is worth a thousand words and let’s take a look at how a linked list looks like before any explanations.

As you see above there are three nodes in the linked list.
Each node is based on Node struct as below which contains a value and a pointer to the next Node.

struct Node
{
    // value that this Node contains. 
    // It could be any data type you want to contain
    int   val;
    
    // pointer to next node
    Node *next;
    
    // pointer to previous node.
    // this is optional
    // Node *prev;
};

The example code has only one pointer ‘next’ but you can also have another Node * to point to the previous Node.
If you have only one pointer (likely it’s a pointer to the next Node) it’s called a singly linked list.
If you have two pointers one pointing to the next and the other to the previous then it’s called a doubly linked list.

Linked List Operations – insert, search, delete

As you can imagine there are three basic operations for a linked list.
You need to be able to search a node in the list, insert and delete.
Let’s go over each operation.

Search

How should the search be?
Given you have a value to search you need to start from the head of the list and check if each node in a chain is the same as the search value.
Return a pointer to the node if you find it or null pointer otherwise.
Let’s take a look at code example for search.

/**
 * @brief  search a node based on search value
 * 
 * @param  head       head of linked list
 * @param  searchVal  value to search in the list
 * 
 * @return pointer to found node. null otherwise
 */
Node *searchNode(Node *head, int searchVal)
{
    // end of the list. value not found
    if (!head)
    {
        return 0;
    }

    if (head->val == serachVal)
    {
        return head;
    }
    else
    {
        return searchNode(head->next, searchVal);
    }
}

I implemented the operation recursively so I don’t need to write a loop. (I thought the recursive solution was easier than loop but it’s your choice)
I actually also used loop based implementation for insertion operation for your reference.

Insertion

Inserting a node could be slightly trickier depending on how you want to maintain the list.
There are three possible cases for insertion.

1. Insert the node at the head of the list
This one is the easiest as you just need to create a node and insert the node.
Here is the code example for head insertion.

/**
 * @brief  node insertion at the beginning of the list
 * 
 * @param  head    double pointer to head since you need to update 'head' after insertion
 * @param  newVal  new value to insertNode
 */
void insertNode(Node **head, int newVal)
{
    Node *newNode = new Node;
    newNode->val = newVal;
    newNode->next = *head;

    // update head
    *head = newNode;
}

2. Insert the node at the tail of the list
This one is slightly harder than head insertion but still pretty simple.
What you need to do is to traverse to the end of the list and insert the node there.

/**
 * @brief  node insertion at the end of the list
 * 
 * @param  head    double pointer to head since you still might need to update 'head'
 *                 if the list is empty
 * @param  newVal  new value to insert
 */
void insertNode(Node **head, int newVal)
{
    Node *newNode = new Node;
    newNode->val = newVal;
    newNode->next = 0;

    Node *tailNode = *head;
    while (tailNode && tailNode->next)
    {
        tailNode = tailNode->next;
    }

    if (!tailNode)
    {
        *head = newNode;
    }
    else
    {
        tailNode->next = newNode;
    }
}

3. Insert the node based on the sorted order of the list.
Imagine you want to maintain the list in sorted order (decreasing or increasing).
Then you will need to find a proper location to insert.

For example, let’s say you have a list like below and you would like to insert value 4.
1-> 3-> 5

Then you need to traverse the list and find a node that is not less than 4 which is 5, the last one, and create a node and insert.
However, there is a couple of other edge cases such as the inserting position happens to be at the head or tail of the list.
Although this one is not terribly difficult it does require little more thoughts than the others.

void insertNode(Node **head, int newVal)
{
    // create new Node
    Node *newNode = new Node;
    newNode->val = newVal;
    newNode->next = 0;
    
    // if empty list then just insert it here
    if (!*head)
    {
        *head = newNode;
        return;
    }
    // check if it needs to be inserted at head.
    else if (newNode->val < (*head)->val)
    {
        newNode->next = *head;
        *head = newNode;
        return;
    }
    
    Node *iter = *head;
    
    // loop until you find first Node that is not less than new value
    while (iter && iter->next)
    {
        if (iter->next->val >= newNode->val)
        {
            break;
        }
        
        iter = iter->next;
    }
    
    if (iter->next)
    {
        newNode->next = iter->next;
    }
    
    iter->next = newNode;
}

The tricky part of insertion is that you have to make sure you update the next pointers properly.
1. If insertion is happening at the head, make sure head pointer is updated and the next pointer of new node point to last head
2. If insertion is happening at the tail, make sure the last node of the list is pointing to the new node properly
3. If insertion is happening in the middle of the list, make sure the previous node’s next points to new node and new node points to the proper next one.

deletion

The deletion of a node is a very similar process as insertion.
First, you need to find which node to delete if there is any and properly updates the next pointers.
Just like insertion deleting node could be the head, the tail or in the middle of the list.
Let’s take a look at the code example.

/**
 * @brief  delete a node from the list if there is one
 *         for simplicity I don't delete all the duplicate values here
 * 
 * @param  head       double pointer to head in case you have to delete head node
 * @param  deleteVal  value to delete
 */
void deleteNode(Node **head, int deleteVal)
{
    Node *iter = *head;
    
    // nothing to delete
    if (!*head)
    {
        return;
    }
    // deleting head. need to update head
    else if ((*head)->val == deleteVal)
    {
        *head = (*head)->next;
        delete iter;
        return;
    }

    while (iter && iter->next)
    {
        if (iter->next->val == deleteVal)
        {
            break;
        }

        iter = iter->next;
    }

    if (iter->next)
    {
        Node *delNode = iter->next;
        iter->next = iter->next->next;
        delete delNode;
    }
}

Pros

  • Unlike an array size of a linked list is very flexible as long as the memory permits
  • Insertion and deletion are much simpler than an array. For an array insertion/deletion you have to move many other elements after the operation
  • It is a perfect data structure to implement more complex data structures like Stack and Queue since you only need to maintain head(or tail) of the list for insertion, search, deletion

Cons

  • It requires extra memory (next, prev pointers)
  • It does not allow random access like an array and therefore search could be slower than an array

Performance

Search – O(n)
Insertion – O(1) if always insert at the head (for cases like Stack)
O(n) otherwise
Deletion – O(1) if always delete head (for cases like Stack)
O(n) otherwise

Conclusion

We have taken a look at some basics of linked list.
Linked list is a great data structure for some special purposes due to its flexibility of insertion and deletion.
However, there are some weaknesses about it so it requires some discretion to wisely use it.

Thank you for reading my post and please let me know if you have any questions or suggestions and good luck!