본문 바로가기

Programming/C++ Basic

[Basic C++] 10 - What is a pointer in C++ (2/2)

dIn this post, I am going to talk about how to use pointers in real programs. There are numerous methods you need to learn to get used to a pointer, so consider this post as the beginning of the long journey. I will cover how to pass a pointer variable to a function and how to point a function mainly. I am not going to go too deep inside a pointer because it needs more than we know about C++. I make intermediate and advanced programming in C++ later. 

 


Table of Contents

1. Passing a pointer to a function
2. Pointer to function

3. Double pointer


1. Passing a pointer to a function

 

1.1 ) Reference / Address

We have already learned how to pass the reference of value to the function to a) modify the actual variable, not the copy, and b) increase memory efficiency by not copying the same variable multiple times. Let's check how they work first. Code example 1 shows how to pass a variable and reference to a function. In addition, when it comes to an array, you are only allowed to pass its reference to a function in C++.

 

Code example 1

#include <iostream>

void func1(int a)

{

       std::cout << &a << std::endl;

}

void func11(int* a)

{

       std::cout << a << std::endl;

}

void func2(int* array)

{

       std::cout << array << std::endl;

}

int main()

{

       int a = 10;

       int array[] = { 1,2,3 };

       std::cout <<"The address of \"a\" in the main :" << &a << std::endl;

       std::cout << "The address of \"a\" in func1 : ";

       func1(a);

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

       std::cout << "The address of \"array\" in main : " << array << std::endl;

       std::cout << "The address of \"array\" in func2 : ";

       func2(array);

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

       std::cout << "The address of \"a\" in the main :" << &a << std::endl;

       std::cout << "The address of \"a\" in func11 : ";

       func11(&a);

}

 

Figure 1 Result of code example 1

 

In the example, it is very clear that func1 copied the value "a" as a new local variable since the addresses of "a" in the main and in func1 are totally different. On the other hand, when the address of "a" was passed to func11, the addresses were the same. It also applied to the array since in C++ only the address of an array is passed to a function.

 

There are two ways to pass an address to a function in C++. The first one is like the above example. The address of a variable with a reference operator &, and a function accepts the address as a pointer variable. The second one is to pass a variable to a function and add a reference operator to the function argument.

// Method One

function (int * a) { body } // argument as a pointer

int main() { int a=10;, function(&a) } // function call by reference



// Method Two

function (int &a) { body } // argument as a reference

int main() { int a=10;, function(a) } // function call by variable identifier

 

The result is the same even if you pass a pointer because the value of a pointer is the address of a variable just like a reference.

 

POINTER AND REFERENCE ARE DIFFERENT!

 

1.2) Void pointer

Let suppose you have two variables with different types but only one function accepting a pointer. One possible solution to this problem is to create a new function corresponding to another data type. However, this may be too much for multiple data types.

 

C++ provides a useful technique called a "void pointer". Void pointers are pointer with no specific data properties like type and length. Thus they can point any kinds of data types. But instead, void pointers are not allowed to be dereferenced directly using a dereference operator *. The compiler would not know which data type it should return unless notified explicitly by a programmer. (We already know int 8 and float 8 occupy the different sizes of memory.)

 

In order to return/dereference void pointers, typecasting is needed by another pointer with a specific data type. Look at code example 2

 

Code example 2

#include <iostream>

void function(void* p, const char* tid)

{

       if (tid == typeid(int).name())

       {

             std::cout << "void p is int !\n";

             int* pp = (int*)p;

             std::cout << *pp + 10 << std::endl;

       }

       else if (tid == typeid(float).name())

       {

             std::cout << "void p is float !\n";

             float* pp = (float*)p;

             std::cout << *pp + 50.1;

       }

}

int main()

{

       int a = 10;

       float b = 10.0;

       function(&a, typeid(a).name());

       function(&b, typeid(b).name());

}

 

Figure 2 Result of code example 2

 

int variable "a" and float variable "b" were passed to the function as pointers for the addition operation. The second argument of the function was created to detect the data type of the first argument. The "typeid" function returns the data type of a variable as type_info object (const char pointer). Thus you can only compare it with the same type_info object. In other words, something like {type_info object == "int"} does not work.

 

The if statements in the function checke the data type of the input variables and execute addition operations. Due to the above mentioned reason, {type_id object == typeid(data_type)} was used instead.

 

Now let's see how void pointers work. The two variables were passed to the function as void pointers in which they did not have any types. Then new pointers with specific types were declared in the function to assign new data types to the void pointers.

 

In addition, the below two operations are not the same.

int * (void pointer)

(int *) (void pointer)

2.  Pointers to function

 

A pointer to a function is often used to pass a function as an argument to another function. Passing a function itself as an argument to another function is not allowed in C++ thus a function pointer is always needed. The syntax of a function pointer is following,

 

type (*function_name)(function_arguments)

 

Figure 3 Schematic explanation of pointers to functions

 

See code example 3 to understand this method in detail

 

Code example 3

#include <iostream>

int function_a(int i, int j)

{

       return (i / j);

}

int function_b(int i, int j)

{

       return (i * j);

}

void function_A(int i, int j, int (*func_a)(int, int), int (*func_b)(int, int))

{

       int result = (*func_a)(i, j) + (*func_b)(i, j);

       std::cout << "function_A takes the pointer to
       function_a and function_b.  The result is : " << result;

}

int main()

{

       int i = 100;

       int j = 10;

       function_A(i, j ,function_a, function_b);

}

 

Figure 3 Result of code example 3

 

This is not an efficient program but it is enough to tell you how function pointers work in C++. "function_A" accepts two int variables as copies and two functions as a pointer. The argument for the function pointer is just like a function prototype.

 


3. Double pointer (Pointer to Pointer)

 

A double pointer is something you feel hard to learn because the behavior of such a complex pointer is too hard to grasp to novice programmers. However, understanding the role and usage of double pointers will increase the efficiency of your program very much. I will fully cover it in the next post.

 

A double pointer is a pointer to another pointer. It stores the address of the pointer that it points to. Figure 4 shows the syntax of a double pointer and how it works.

 

Figure 4 Double pointer

 

But, why do we even need to know this technique in C++?