C++ Programming Series: Pointers (Part 4, Last)

Too busy! Too busy! Don’t expect regular and weekly posts from me. I am studying medicine.

In the previous post, we discussed that pointers are actually arrays! This post is to discuss more about pointers, arrays and the arithmetic that can be done with them.

We can do addition and subtraction with pointers. Multiplication and division is not possible! Here is the code giving an example of pointer arithmetic (try to understand it deeply):

int array[] = {20, 30, 40, 50, 60};
int* pArray = array;

pArray++;
cout << *pArray << endl; //Prints 30, same as array[1]

pArray++;
cout << *pArray << endl; //Prints 40, same as array[2]

cout << pArray[2] << endl; //Prints 60, same as array[4]
//pArray[4] will give error or garbage value!

pArray -= 2;
cout << *pArray << endl; //Prints 20, same as array[0]

cout << pArray[4] << endl; //Prints 60. same as array[4]

When we increment a pointer of type int, the address is actually shifted by the number of bytes that an integer consists of. Similarly, when we increment a pointer of type string, the address is shifted 4 bytes forward. The opposite happens when we decrements a pointer.

Consider the code below:

string words[] = { "First", "Second", "Third", "Fourth", "Fifth" };

string* pWords = words;

Now, pWords is pointing towards the memory address of words[0] or “First”. If we add one into it:

pWords++; //or pWords += 1;

…then it will be shifted 4 bytes forwards to reach the next string of the array, words. Or in other words, pWords is now, equivalent to &words[1]. Now, if we subtract one from it, it will get to the same address as before.

C++ is a very flexible language. We can add the numbers into the pointer temporarily like pWords + 3. Now, if pWords is equivalent to &words[0], then pWords + 3 would give us the address equal to &words[3]. If we dereference this memory address, we will get the proper string value, “Fourth” like this:

string words[] = { "First", "Second", "Third", "Fourth", "Fifth" };
string* pWords = words;

//Adding temporarily for getting the memory address of the
//fourth element of array and dereferencing that memory
//address to get the value from there
cout << *(pWords + 3) << endl; //Prints "Fourth"

Isn’t that similar to that?

cout << pWords[3] << endl; //Prints "Fourth"

Yes, they are completely the same! What is happening with pWords[3] is the same as what is happening with *(pWords + 3).

That’s it! Your exercise is to find out what is the output of the code below (without checking it out in the compiler):

int array[] = { 1,2,3,4,5,6,7,8,9,10 };
int* pArray = array;

pArray += 5;
cout << pArray[3] << endl; //Output 1
pArray -= 3;
cout << pArray[4] << endl; //Output 2
pArray--;
cout << *pArray << endl; //Output 3
pArray + 2;
cout << *pArray << endl; //Output 4
pArray += 1;
cout << *(pArray + 1) << endl; //Output 5

That is all pointers for you. Congratulations! You learned the pointers! Time to step ahead…

Advertisements

C++ Programming Series: Pointers (Part 2)

In the previous post, we learned how to get the memory address of a variable and how to define a variable that holds the memory address i.e pointer.

Suppose that there is a variable of type int called number. We initialize it with value equals to 10. Now, suppose that it has a memory address 091 (Sounds ridiculous but it’s just a supposition). This memory address is present somewhere in our device’s memory.

Some of the memory addresses are shown in the table below, along with the values present in each.

Address 090 091 092 093 094 095
Value Garbage number number number number Garbage

Now, we know that number has a memory address 091. Then, why 092, 093 and 094 are also filled with value, number? Well, just think a little on why not 095? 095 is just a garbage value!

Okay, okay! Let me clear this confusion. number is of type int and the size of int is 4 bytes. Each memory address carries 1 byte. Therefore, to fit a variable of type int, it requires 4 neighboring memory addresses.

So, number is having memory addresses, 091, 092, 093 and 094. But the only memory address that is useful to us, is the first one i.e 091. Every variable only knows its first memory address and its size. When we know the first memory address of a variable, we can easily get the value of that variable.

Now, suppose that we have a pointer of type int called pNumber. We initialize it with the memory address of the number (How to get memory address of a variable? By putting ampersand(&) behind it).

Now, the pNumber is also 091. We dereference it (i.e we put an asterisk(*) behind the pNumber) to get the value 10.

Actually, when we dereference the pointer, we are actually, looking up the memory address which in this case, is 091. Pointer of type int will suggest that whatever is present in this memory address will be the starting byte of the variable which is of type int.

Please read the above statement twice! It is a bit tricky!

To make it easy, here’s the same table:

Address 090 091 092 093 094 095
Value Garbage number —–> pNumber number number number Garbage

After looking up the memory address, pointer takes the value which in this case, is 10.

If you try sizeof() for pointer of any type, it will tell you that the size of pointer is 8 bytes (or may be different depending on your device). This is because a pointer consists memory address and memory address is a hexadecimal value. Hexadecimal values are big values! Therefore, every pointer resembles to type long int which is also 8 bytes in size.

We can manipulate with the pointers as well. We will discuss it in the upcoming posts in detail. For now, just get along with pointers and the concept described above. It should not be hard now! There is still a huge ground to cover regarding pointers…

C++ Programming Series: Pointers (Part 1)

In this post, we are going to discuss pointers. But before proceeding, I just want to say that if you really followed all my posts till now then, Congratulations! You learned the basics of programming in general!

But there are still a lot of basics in C++! C++ is a very old programming language but we still use it because of the fact that C++ is the only language to have a very high performance with object orientation. The term, ‘object orientation’ is a very broad term which we will not discuss in this series.

C++ is powerful because it is a very low level language. And when something is low level, it will be way more flexible but hard to work with. With the help of C++, we can access every bit of our device memory directly. And so, this direct access needs us to be cautious of how it works and what are we really doing with it.

A pointer is the memory address of a variable. I don’t want to say that but learning pointers is a hard thing! Although the definition may looks so simple, to work with pointers isn’t that simple. However, if we understand the way pointer works and all such concepts, it will all be a piece of cake!

Getting the memory address of a variable:

int main()
{
  //As we all know, a basic variable of type 'int'
  int value = 20;
  
  //To get the memory address of any variable,
  //put ampersand(&) at the back of a variable's name.

  //This prints a hexadecimal value which
  //represents the memory address of the variable
  cout << &value << endl;

  return 0;
}

It looks useless but it is very useful! Memory address of a variable is that address inside our device memory where that particular variable is stored. It is a hexadecimal value which is something that is not important to know about. Here is a link explaining what is hexadecimal.

POINTER CONCEPT:

If two variables have same memory addresses, they will act like one variable. Or in other words, a variable can not have two different memory addresses. If we think that a variable have two different memory addresses, they will act like two variables.

Filling a pointer with the memory address of a variable:

//A basic variable of type 'int'
int value = 20;

//Pointer declaration is just like references
//except that it has asterisk(*) instead of ampersand(&)

//A pointer to type 'int'
int* pValue = &value;

//'pValue' is a pointer to 'value'
//or 'pValue' contains the memory location of 'value'

cout << pValue << endl;
cout << &value << endl;
//Both gives us the same memory address

Yup! There is a bit confusion of where to use ampersands, asterisks and other symbols while working with pointers and references. But once we got used to it, it will get easy!

That’s it for now! We will discuss it more later. For now, it is quite much to get used to. No, pointers are not useless! Keep proceeding. Pointers are not a hard subject! I was joking!

C++ Programming Series: File I/O

In this post, we are going to discuss about input and output. No, I am not talking about cout, cin, getline() or any other methods we have discussed till now. I am talking about writing and reading files.

For working with files, we need to include another header called fstream.

There are three classes in it, for file I/O:

  • ofstream – Class for writing files
  • ifstream – Class for reading files
  • fstream – Class for writing as well as reading files

We are going to discuss ofstream and ifstream only. fstream is a bit different to use but who cares! We don’t need that!

The codes for file I/O are present below. It is pretty simple and there is more comment in the code than the code itself, for explaining things!

File Writing:

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
  //The 'ofstream' class for writing a file
  ofstream fileWriter("a_file.txt");

  int number = 21;

  //Writing the stuff
  fileWriter << number;
  fileWriter << " ";
  fileWriter << 13;

  //Closing that file which is opened; it is important!
  fileWriter.close();

  return 0;
}

File Reading:

#include <iostream>
#include <fstream>
using namespace std;

int main()
{
  //The 'ifstream' class for reading a file
  ifstream fileReader;

  //Opening a file called 'a_file.txt' in local directory
  fileReader.open("a_file.txt");

  //For checking whether the file fails to open or not
  if (fileReader.fail())
    cout << "There is no file in the address!" << endl;

  //While the file that is opened, has some context
  //in it at the pointer location
  while (fileReader.good())
  {
    //Variable to store reading from the file
    int number;

    //Reading the number at the pointer location and then,
    //proceeding the pointer forward for further reading
    fileReader >> number;

    //Displaying the number present in the file
    cout << number << endl;
  }

  //Closing that file which is opened; it is important!
  fileReader.close();

  return 0;
}

Reading and writing a file requires us to have the concept of a pointer. The pointer points to some place in the file which then, proceeds forward with every single read/write operation. That pointer is similar to the one which appears at the time of typing.

I hope that you understood how to read and write a file. But there are still some doubts and confusions!

The first one is the formatting of the file that we are reading. White spaces are something that no one wants to read/get from the file. So, ifstream don’t consider these spaces and no matter how much white space there is, it will be considered as one space only.

Of course, we can’t just read data as discrete if that data is arranged without spaces in between. For example, if the file contains two words without any space like this, “nospace”, ifstream reads it as “nospace” and so, giving a space between them rectifies the issue.

The second one is the data type for reading and writing a file. We can use all primitive types. We can use strings as well if we include the string header.

The third one is formatting a file being written. We can have formatting by just writing in character literals like \t or \n to have a tab or a new line respectively.

This is how we simply read and write files. Now, your task is to modify the registration program that we made with functions previously, to write a file with the data inputted by the user.

Soon we will see, how much fun is programming! It is fun for me as I am developing a game in C++ called SamuraiDuel.

Featured

Developing a Game: SamuraiDuel

Now-a-days, I am developing a game called SamuraiDuel. It is going to be a 2D game and being built on OpenGL, SDL2, Box2D and CEGUI all in the language, C++.

SamuraiDuel Title
SamuraiDuel Title

Before starting to develop the game, I first developed the base of a very low level Game Engine which I should call a GL Engine, GL SDK or something like that, in order to work with OpenGL with ease. Of course, I called it BAC GL Engine 2 (I tried to make one before but it has some big flaws and so, I put ‘2’ this time after the name).

I am not satisfied with that name. If you had one in your mind, please do comment below.

SamuraiDuel is going to be a side scroller fast paced pixelated game. Of course, it will take time to get completed and once it is completed, this is the place where I will confirm this.

There is the screenshot of the game! I hope that you like that…

SamuraiDuelDevelopment4

All pixel arts are made by me and I think it looks fair.

That’s all that I have to say! If you want some features in it or just has something to tell, comment below and tell that to me! It will be really appreciable.

UPDATE: The project is closed and is no more under development due to lack of funding and maybe, motivation. Sorry guys! But who knows… I might complete it someday!

C++ Programming Series: References

I believe that my series is getting complex with every post being published! This has to be done because we should also be getting more complex and more logical with every topic we discuss.

Today’s topic is References. Before proceeding on, let us discuss few problems with functions. The first one is that we don’t know any methods of getting multiple outputs. The second one is that we don’t make any change in the variable that we pass into the function via parameters.

The following code expresses the second problem with functions:

void multiplyBy2(int variable)
{
  variable *= 2;
  //No returning
}

int main()
{
  int variable = 2;
  mulitplyBy2(variable); //This should change the variable's value to 4
  cout << variable << endl; //Prints 2, not 4
  return 0;
}

NOTE: We can have same names for variables having completely isolated scopes. Note that multiplyBy2 has a parameter called variable and main function also has a variable called variable. Sounds confusing!

We have a solution for that and that is, to return that variable in the function and then, put that into any variable or just call that temporary return value directly.

But we expect the method above to change the variable’s value which is not the case here! Why? Well, the point is that when we pass the variable via the parameter of the function, we are actually copying that variable into another completely new variable. This new variable has a very limited scope i.e we can only access it inside the function.

Let us discuss a very simple example of what copying is:

int value1 = 2;

int value2 = value1; //Here, value1 is copied into value2
value2*=2; //value2 is a different variable; it will not effect value1 in any case!

cout << value1 << endl; //Prints 2, not 4
cout << value2 << endl; //Prints 4

The highlighted codes shows what is actually happening in the function, multiplyBy2() in the example, given above.

How to do it in the way that we want? The answer is right inside the topic of this post: References. There is another way and that one is through Pointers which is way more complex but we will discuss it later on.

What is a reference? Reference is just another name given to the same variable. In our real life, we can have the reference case of a bird called ‘raven’. Raven is a black bird. So, people can refer to ‘raven’ by calling it as ‘black bird’. In a very similar way, variables can have references as well.

//Consider that there is a bird called 'raven'
int raven = 10;

//That 'black_bird' is a reference to 'raven' 
int& black_bird = raven;

//Now, what we do with 'black_bird' is actually,
//what we are doing with 'raven' as well and vice versa...
black_bird*=2; //Both gets 20
raven+=5; //Both gets 25

cout << raven << endl; //Prints 25
cout << black_bird << endl; //Prints 25

The highlighted line shows how to make reference to a variable. It is pretty simple; just put ampersand or ‘&’ after the type of the variable that we are going to refer to.

int& is considered a type which we can call as ‘reference to an integer’. Same will be for any type reference as well.

Time to make some change in the multiplyBy2() function!

//Notice the ampersand before the variable's name
void multiplyBy2(int& variable)
{
  variable *= 2;
}

int main()
{
  int variable = 2;
  mulitplyBy2(variable); //Now, we are not copying, we are referencing!
  cout << variable << endl; //This time, it prints 4
  return 0;
}

Now that, the second problem is solved, the first problem is solved as well. We can have multiple outputs by having more parameters to the function. These parameters are going to be references and whatever is going to be changed with these references, this change is going to happen with the actual variables which are passed as parameters in the function.

//The first two parameters represent inputs
//and the next three represent outputs
void get3TimesDivision( float number1, float number2,
float& division1, float& division2, float& division3 )
{
  division1 = number1 / number2;
  division2 = division1 / number2;
  division3 = division2 / number2;
}

int main()
{
  //Multiple Outputs using References
  float div1 = 0.0f, div2 = 0.0f, div3 = 0.0f;
  get3TimesDivision( 8.0f, 2.0f, div1, div2, div3 );

  cout << div1 << endl; //Prints 4
  cout << div2 << endl; //Prints 2
  cout << div3 << endl; //Prints 1

  return 0;
}

Note the point that where we want to have references, we cannot have constants or temporary values there. In the above case, if the parameters, number1 and number2, are references to float, we cannot pass 8.0f and 2.0f into the function. We must pass variables of type float with the respective values, into the function.

That’s all! References are a great way to deal with outputs. Just try to modify all the previous functions that we created together, to have references and not copies. Practice them very well. They are going to be used extensively!

C++ Programming Series: Headers and Prototypes (Part 2, Last)

In this post, we are going to discuss some confusions that you might have got in the previous post. You might have read #include "func.h" in that post and not #include <func.h>. Actually, both have different meanings!

If we type angle brackets (<>) instead of double quotes (“”) for func.h, the compiler will check for that file in the C++ base files directory and project specified include directory. From C++ base files, I mean those files which also includes the most commonly used iostream, math.h, string, etc, that are the files of standard C++. All these C++ standard files are header files although they may not have .h at the end of their names.

If we type double quotes as in the previous post, the compiler will check for that file in local project directory. This directory is the same directory where the IDE adds all our files to.

In a nutshell,

  • #include <file_name> – searches the file in base and project specified include directory.
  • #include “file_name” – searches the file in local project directory.

Now, we know what double quotes and angle brackets do with #include. But we actually, don’t know what #include do! #include simply, copy the codes from the file and then, paste it into that file where it is called.

This is something that we don’t need to know. What we need to know is the fact that C++ don’t allow more than one definitions. You can’t just do like that:

void func()
{
  //code here...
}

//Another time: gives error!
void func()
{
  //code here...
}

It might be possible that we include things twice or, the other and most common case is that the file that we are including, includes another file that is already included in our file! To make it clear, see the code below:

#include "a" //'a' file contains function 'func()'
#include "b" //'b' file includes file 'a'
//'func()' is defined twice
//So, gives error!

That hash(#) before the include suggests that the command after it, is a preprocessor directive and not a C++ code. These directives runs before the compilation of the actual program. There are many of these. You can check out preprocessor directives in details here.

In order to make sure that something is defined just once, you can use preprocessor directives like that:

#ifndef SOMETHING //This means 'if not defined preprocessor term called SOMETHING'
#define
  //code here
#endif //This ends the '#ifndef' statement

The above code just acts similar to the C++ if-statement that we discussed before.

SOMETHING can be anything. It can be an integer, a group of characters, a float, etc.

#define PI 3.14 //Now, PI is equal to 3.14

int main()
{
  cout << PI << endl; //We can use it as a regular double
  PI++; //Gives error; preprocessor definations are constants!
  return 0;
}

I hope that you got all of the above things. Just practice using headers and prototypes. Find errors and then, try to fix them yourself. I got a new exciting series called My Pixels where I have showcased some of my hand drawn pixel arts or sprites! Just check that out and see ya!