Lesson # 7. Pointer Basics

Дата изменения: 19 ноября 2020

Theory

Pointer Basics

  • Pointers are way of referring to the location of a variable. Instead of storing a value like 5 or the character ‘c‘, a pointer’s value is the location of another variable.
  • The pointer variables have a size (a number of bytes in memory), a name, and a value. They must be declared and initialized.
  • «Pointer» (by itself) is not a type. It is a type constructor — a language construct which, when applied to another type, gives us a new type. In particular, adding a star (*) after any type names the type, which is a pointer to that type. For example:
  • /*
    declares a variable with the name my_char_pointer 
    with the type pointer to a char 
    (a variable that points to a character)
    */
    char * my_char_pointer; // pronounced "char star my char pointer"
    Declaring a pointer
  • The declaration of the pointer tells us the name of the variable and type of variable that this pointer will be pointing to.
  • Assigning to a pointer
  • We can assign to pointers, changing their values. In the case of a pointer, changing its value means changing where it points.
  • We have to initialize a pointer (giving it something to point at) before we use it for anything else.
  • If we do not initialize a pointer before we use it, we have an arrow pointing at some random location in our program (it may cause the program’s crash).
  • To get an arrow pointing at some address of that cell in memory, we need a way to name that box, and then we need to use the & operator (the operator is named the «address-of» operator). Conceptually, the & operator gives us an arrow pointing at its operand.
  • /* you can see code that declares an integer x 
    and a pointer to an integer xPtr */
    int x = 5;
    int *xPtr;
    xPtr = &x; // sets the value of the variable xPtr to the address of x
  • the value of x is initialized to 5 on the same line in which it is declared;
  • the value of xPtr is initialized to the location of x;
  • after it is initialized, xPtr points to the variable x.
  • The code &x = 5; will not compile. A programmer can access the location of a variable, but it is not possible to change the location of a variable.
  • Dereferencing a pointer

  • Once we have arrows pointing at locations of variables, we want to make use of them by «following the arrow» and operating on the box it points at the end of the arrow (when the value of the variable is changing). Following the arrow is accomplished using the star symbol *, a unary (унарный) operator that dereferences a pointer.
  • 6
    7
    
    // An example of the use of the derference operator: 
    *xPtr = 6; // changes the value that xPtr points to 6
  • Notice that the green arrow indicates that this line has not yet been executed, hence x still has the value 5 in the conceptual representation. Once line 7 is executed, however, the value will be 6.
  • Two contexts in which you will see the star (*) symbol, don’t mix them:
    1. In a variable declaration, such as int *p;, the star is part of the type name, and tells us that we want a pointer to some other type (in our example, int * is the type of p).
    2. When the star is the dereference operator. For example, the code r = *p; gives the variable r a new value, namely the value inside the memory cell that p points to. The code *p = r; changes the value inside the memory cell that p points at to be a new value, namely the value of the variable r.

  • When you work with pointers, you will use the star first to declare the variable and then later to dereference it. Only variables that are of a pointer type may be dereferenced.
  • int * q = &y; // is the same as the two statements:
    int *q; 
    q = &y;
    Summarizing
  • There are only three basic pointer actions — declaring, assigning (including initializing), and dereferencing.

Correct version of swap

Solution: We have to pass the swap function pointers to the original variables a and b, as it follows below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;
 
void swap(int *x, int *y) {
	int temp = *x; // temp temporarily stores the value that x points to, =3
	*x = *y; // we take the value that y points to, which is the value of b (=4) 
                  //and store that in the value that x points to, namely the variable a
	*y = temp; // we take the temp = 3 and store that into the integer that y points to, 
                    //which is the variable b
}
 
int main() {
	int a = 3;
	int b = 4;
 
	swap(&a, &b);
	cout<<"a = "<< a<< ", b = "<<  b << endl;
	system("pause");
	return 0;
}
  
function swap takes two arguments, x and y which are pointers to integers;
as we access the values of the integers that x and y point to in the code inside swap, we’re going to have to de-reference x and y. And so, that’s why we’ll see these stars (*) in front of x and y throughout the code;
inside the main, instead of passing in a and b, we now have to pass in the address of a and address of b.

A program and memory

  • On a 32-bit machine, where addresses are 32 bits in size, the entire memory space begins at 0x00000000 (in hex, each 0 represents 4 bits of 0) and ends at 0xFFFFFFFF (recall that 0x indicates hexadecimal, and that each F represents four binary 1’s). Every program has this entire address space at its disposal and there is a convention for how a program uses this range of addresses.
  • Let’s look at the picture to understand where in memory a program’s various components are stored.

    Null
  • When we use NULL, we’re going to indicate that it does not point at anything. Whenever we have NULL, we can use the pointer itself (which just has a numeric value of 0), however, we cannot follow the arrow (as it does not point at anything).
  • The NULL pointer has a special type that we have not seen yet — void *. A void pointer indicates a pointer to any type, and is compatible with any other pointer type — we can assign it to an int *, a double*, or any other pointer type we want.

Accessing an Array

  • Accessing an array element using pointer arithmetic works fine, and sometimes is the natural way to access elements. But in the case when we just want the n-th element of an array, it would be cumbersome to declare a pointer, add n to it, then dereference it.
  • Let’s look at an example of a function that prints the elements of an array and uses pointer manipulation to access those elements:
  • // * array : the name of the array is a pointer to its first element, that is 3
    void printArr(int *array, int n) { 
    	int *ptr = array; // *ptr is a pointer to point at the loaction which *array pointer points at
    	for (int i = 0; i < n; i++) {
    		cout << *ptr; // 1st step output 3, 2dt step output 1, 3d step output 7,
                    // to make pointer point at the memory cell of the next element in the array:
                    // example address ptr = 0x00b5f9a0
    		ptr++;  // 1st 0x00b5f9a4, 2nd 0x00b5f9a8, 0x00b5f9ac, 
                            // no element in the array, but there be no error
                            // it would cause the problem if we dereference pointer 
    	}
    }
    int main(){
    	int arr[4] = { 3,1,7,2 };
    	printArr(arr, 4);
    }
  • We can achieve this goal more succinctly by indexing the array. When we index an array, we write the name of the array, followed by square brackets containing the number of the element we want to refer to. It is important to note that in C++, array indexes are zero-based — the first element of the array is myArray[0].
  • // * array : the name of the array is a pointer to its first element, that is 3
    void printArr(int *array, int n) { 
         for (int i = 0; i < n; i++) {
    	 cout << array[i]; // 1st step output 3, 2dt step - 1, 3d step - 7, and then 2
         }
    }
    int main(){
    	int arr[4] = { 3,1,7,2 };
    	printArr(arr, 4);
    }

Labs and tasks

Lab 1:
To do: Create a function to calculate the addition of pointer and a variable of integer type. That is function must return sum of pointer and variable value.

Note 1: The signature of the function should be as follows:

int addP(int var1, int var2);

Expected output:

please, enter the first number (for pointer):
>>>2
please, enter the second number (to add):
>>>500
the result: pointer + 500 = 502

✍ How to do:

  1. To do the lab create empty console application with a name Lesson7. Add files: main7.cpp, string7.cpp, string7.h.
  2. Include all the needed libraries and files.
  3. Open the main7.cpp file in the code editor. Type the code to output a message for the user, and input the value of two variables. The first of them is for pointer to point to the location of it, and the second — to add to that pointer:
  4. cout << "Lab 1:" << endl;
    cout << "please, enter the first number (for pointer): "<< endl;
    int var1; 
    cin >> var1;
    cout << "please, enter the second number (to add): " << endl;
    int var2; 
    cin >> var2;
    
  5. After, let’s turn to string7.h file and include all the needed directives:
  6. #pragma once
    #ifndef STRING7_H
    #define STRING7_H
    
    #include 
    // your code is here
    #endif
    
  7. The signature of the function was recommended in the task text, let’s add that code with a comments of the task text:
  8. //lab 1: Create a function to calculate the addition of pointer and a variable of integer type
    int addP(int var1, int var2);
    
  9. Now, let’s create the implementation of the function. To do this open the string7.cpp file, include all the directives you need, and add the code:
  10. //lab 1: to calculate the addition of pointer and a variable of integer type
    int addP(int var1, int var2) {
    	int* p_var = &var1;
    	return *p_var + var2;
    }
    
    Here p_var is initialized to the location of var1. Function returs a derference operator — *p_var — which means we take the value that p_var points to (that is the value of var1) and add the value of var2 to it.
  11. Now you can call the function we’ve created and print the results. You must do it inside the main7.cpp file:
  12. cout << "Result:" << endl;
    cout << "pointer + " << var2 << " = " << addP(var1,var2) << endl;
    
  13. Add the code to return a value 0 inside the main function. Run the program and check the output.
Task 1:

To do: Create an application with a function that takes two arguments, they are integer numbers (var1 and var2), and prints the following calculations with its arguments, using pointers (p1 and p2):

1) multiplication of pointer and variable: p1 * var1
2) addition of pointers:  p1 + p2
3) changing the value of var1 = 5 using pointer p1
4) changing the address of pointer: p1(address) = p2(address)

Note 1: To change the value of a variable:

int* p1 = &var1; // if p1 is a pointer
*p1 = 1; // 1 is a new value for the variable

Note 2: The signature of the function must be as follows:

void task1(int var1, int var2);

Expected output:

Task 1:
please, enter the first var value:
>>5
please, enter the second var value:
>>10
multiplication of pointer and variable: 25
addition of pointers: 15
the result of changing the value of var1, var1 = 5
the result BEFORE changing the address, p1 = 0098F7E8
the result of changing the address, p1 = 0116FC90

[Solution and Project name: Lesson_7task1, file name L7Task1main.cpp, L7Task1imp.cpp, L7Task1.h]

Accessing an array

Lab 2, Arrays:
To do: An array of integers is given (1, 2, 3, 4, 5, 6, 7, 8, 9). Make every second element being set to 0 (that is even elements must be = 0). You should use indexing the array.

Note 1: The signature of the function should be as follows:

void DelEveryEven(int* array, int n);

Expected output:

Lab 2, Arrays:
The array before lab is done:
1 2 3 4 5 6 7 8 9
Result:
1 0 3 0 5 0 7 0 9

✍ How to do:

  1. To do the lab open the application you've created for lab1 or, if you haven't done it, so make the next: Create empty console application with a name Lesson7. Add files: main7.cpp, string7.cpp, string7.h.
  2. Include all the needed libraries and files (if you didn't do it before).
  3. Open the main7.cpp file in the code editor. Type the code to output a message for the user, and to initialize an array in the same line that you declare it:
  4. cout << "Lab 2, Arrays:\n";
    int my_arr[] = { 1,2,3,4,5,6,7,8,9 };
    
  5. Print the array elements before lab is done:
  6. cout << "The array before lab is done: " << endl;
    for (auto x : my_arr) {
    	cout << x << " ";
    }
    
  7. After, let's turn to string7.h file and include all the needed directives (if you didn't do it before for the lab1):
  8. #pragma once
    #ifndef STRING7_H
    #define STRING7_H
    
    #include 
    
    #endif
    
  9. The signature of the function was recommended in the task text, let's add that code with a comments of the task text:
  10. // lab 2, arrays: An array of integers is given (1, 2, 3, 4, 5, 6, 7, 8, 9). 
    // Make every second element being set to 0
    void DelEveryEven(int* , int);
    
  11. Now, let's create the implementation of the function. To do this open the string7.cpp file, include all the directives you need, and add the code:
  12. //lab 2, arrays:  An array of integers is given. 
    // Make every second element being set to 0 (that is even elements must be = 0).
    void DelEveryEven(int* array, int n) {
    	for (int* p = array + 1; p < array + n; p = p + 2) {
    		*p = 0;
    	}
    }
    
    The * array parameter is initialized to the location of the array, that will be passed on.
    Here, as a loop counter we use a pointer to point at the address of the 1-st array element+1.
    Let's consider the line int* p = array + 1;.

  13. array returns the memory cell of the first element. But we must make the second element being set 0. So, we have array + 1.
  14. Having *p = 0 we dereference the pointer, and we make the second element equal to 0.
  15. To do the same manipulations with the fourth element (even), we can increment the pointer by 2 (p = p + 2).
  16. array + n means the memory cell of the first element plus n, which is 9. This provides an exit from the loop.
  17. Now you can call the function we've created and print the results. You must do it inside the main7.cpp file:
  18. DelEveryEven(my_arr, 9);
    cout << "Result: " << endl;
    for (auto x : my_arr) {
    	cout << x << " ";
    }
    cout << endl;
    
  19. Add the code to return a value 0 inside the main function. Run the program and check the output.
Task 2:

To do: An array of positive and negative integers is given. Create an application with a function that sets its negative elements to positive values.

Note: The signature of the function should be as follows:

void SetNegToPos(int* array, int n);

Expected output:

Task 2:
The array before lab is done:
1 -2 3 4 5 -6 7 8 -9
Result:
1 2 3 4 5 6 7 8 9

[Solution and Project name: Lesson_7task2, file name L7Task2main.cpp, L7Task2imp.cpp, L7Task2.h]

String characters access with pointer indexing

Lab 3:
To do: Reverse the order of characters in the string. To do this, define a pointer to the last character and, moving two pointers from the beginning and end of the line to the middle, swap the corresponding characters.

Note 1: To access the characters of a string with pointer indexing you should use char type for that string:

char str[] = "Hello world";

Note 2: The signature of the function should be as follows:

void reverseString (char * str);

Expected output:

// lab 3:
The string before lab is done:
Hello world
The string after lab is done:
dlrow olleH

✍ How to do:

  1. To do the lab open the application you've created for lab1 or, if you haven't done it, so make the next: Create empty console application with a name Lesson7. Add files: main7.cpp, string7.cpp, string7.h.
  2. Include all the needed libraries and files (if you didn't do it before).
  3. Open the main7.cpp file in the code editor. Type the code to output a message for the user, and to initialize the array of char type (the string will be treated as an array of chars):
  4. cout << "Lab 3:" << endl;
    char str[] = "Hello world"; 
    cout << "The string before lab is done: " << str << endl; 
    
  5. After, let's turn to string7.h file and include all the needed directives (if you didn't do it before for the lab1):
  6. #pragma once
    #ifndef STRING7_H
    #define STRING7_H
    
    #include 
    
    #endif
    
  7. The signature of the function was recommended in the task text, let's add that code with a comments of the task text:
  8. // Lab 3: Reverse the order of characters in the string. 
    void reverseString(char* str);
    
    str is initialized to the location of str.
  9. Now, let's create the implementation of the function. To do this open the string7.cpp file, include all the directives you need, and add the code:
  10. // Lab 3: Reverse the order of characters in the string. 
    void reverseString(char* str) {
    	char* str1 = str;
    	char* res = nullptr;
    	while (*str1) {
    		res = str1; 
    		*(str1++); 
            } // end of while
    // ...
    } // end of function
    
    Here, we define a pointer to string's first character. The line (char* res = nullptr;) returns a "null pointer", that is 0x00000000 address. Then, we use the while loop to iterate over the array's elements addresses. After the loop, the variable res will get the value of the address of the last character of the string, that is can be 0x00cffae6, for example, for "d" character).
  11. Then we're going to assign the value of the characters to the *str variable, moving the pointer from the last character to the middle. To do it we use the temporary variable t. And at the same time we're going to substitude the values of the array elements, beginning from the last element and assigning the value of the first element to it. We should do the dereferencing for this purpose:
  12. 	auto l = res;
    	while ((l) > (str)) {
    		auto t = *l; // temporary variable to store the values, moving from the last, 'd'
    		*l = *str; // dereferencing, we take the value that *str points to, which is the value of str 
                               //and store that in the value that *l points to
    		*str = t; // changes the value that *str points to
    		l--; // moving from the last address to the middle
    		str++; // moving from the first address to the middle
    	}
    
    
  13. Now you can call the function we've created and print the results. You must do it inside the main7.cpp file:
  14. reverseString(str);
    cout << "The string after lab is done: " << str << endl;
    
  15. Add the code to return a value 0 inside the main function. Run the program and check the output.
Task 3:
To do: There is a string that contains the positive integer ('Happy 2021 year to u!'). Create a function to display the string containing this number.

Note 1: Use the following function signature. It returns integer (you should make a number using the digits):

void numbFromStr(char* str);

Note 2: The result must be of string type, so you should include the string library:

#include <string>

Note 3: to check if the character is a digit:

if (isdigit(yourCharacter)) {
   // ...
}

  
Expected output:

Task 3:
The string for the task is: Happy 2021 year to u!
the substring of numbers: 2021

[Solution and Project name: Lesson_7task3, file name L7Task3main.cpp, L7Task3imp.cpp, L7Task3.h]

* Extra Task (complicated):
To do: There is a string that contains the positive integer ('Happy 2021 year to u!'). Return the appropriate number .

Note 1: Use the following function signature. It returns integer (you should make a number using the digits):

int strToInt (char * str);

Note 2: to convert the digital character C to the corresponding number from 0 to 9, you must subtract the zero character code from it: C - '0'.
Expected output:

Extra Task:
The string for the task is: Happy 2021 year to u!
There is a number: 2021

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

*
*


Вставить формулу как
Блок
Строка
Дополнительные настройки
Цвет формулы
Цвет текста
#333333
Используйте LaTeX для набора формулы
Предпросмотр
\({}\)
Формула не набрана
Вставить