Содержание:
Theory
1. Pointer Basics
- Pointers are a way to specify the location of a variable. Instead of storing a value such as
5
or thec
character, the pointer value is the location of another variable. - Pointer variables have a size (the number of bytes in memory), a name, and a value. They must be declared and initialized.
- «Pointer» (by itself) it is not a type. This is a type constructor — a language construct that, when applied to another type, gives us a new type. In particular, adding an asterisk (
*
) after any type names the type that is a pointer to that type. For example: - The pointer declaration tells us the name of the variable and the type of the variable that this pointer will point to.
- 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 (this 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. - the
x
is initialized to5
in the same line in which it is declared; - the value of
xPtr
is initialized to the location ofx
; - after it is initialized,
xPtr
points to the variablex
. - 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. - 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 the pointer. - Note that the green arrow indicates that this line has not been executed yet, hence
x
still has the value5
in the conceptual representation. Once line7
is executed, however, the value will be6
. - When you work with pointers, you will use the asterisk first to declare the variable and then later to dereference it. Only variables that are of a pointer type may be dereferenced.
- There are only three basic pointer actions — declaring, assigning (including initializing), and dereferencing.
/* declares a variable named my_char_pointer with the type - pointer to char (a variable pointing to a character) */ char * my_char_pointer; // pronounced "char star my char pointer" |
/* 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 |
6 7 | // An example of the use of the derference operator: *xPtr = 6; // changes the value that xPtr points at 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 asterisk 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 asterisk 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
.
int * q = &y; // is the same as the two statements: int *q; q = &y; |
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 at, =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 at, //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; } |
— the
swap
function 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 asterixes (*
) before 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 starts with
0x00000000
(in hexadecimal format, each 0 represents 4 bits of 0) and ends at0xFFFFFFFF
(recall that 0x indicates hexadecimal, and that each F represents four binary 1’s). Each program has this entire address space at its disposal and there is a convention for how a program uses this range of addresses. - When we use
NULL
, we’re going to indicate that it does not point at anything. Whenever we haveNULL
, we can use the pointer itself (which just has a numeric value 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.
Let’s look at the figure to understand where the various components of the program are stored in memory.
2. 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:
- 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) { 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); } |
// * 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); } |
int a[] {1,3,5,7,9}; int* p = a; // shift the pointer to the second element: p++; p++; |
int a[] {1,3,5,7,9}; int* p = a; cout << *(p + 1) << endl; // = a[1]=3 cout << *(p + 2) << endl; // = a[2]=5 |
Labs and tasks
1. Pointer Basics
To do: Create a function to calculate the addition of pointer and a variable of integer type. That is, function should return the sum of the pointer and the variable value.
Note: The signature of the function must 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:
- To do the lab create empty console application with a name
Lesson7
. Add files:main7lab0.cpp
,L7lab0.cpp
,L7lab0.h
. - Include all the needed libraries and files.
- Open the
main7.cpp
file in the code editor. Type the code to output a message to the user, and enter the value of two variables. The first of them is for pointer to point to the location of it, and the second for adding to that pointer: - After that, let’s turn to the
string7.h
file and include all the necessary directives: - The signature of the function was recommended in the task text, let’s add that code with a comments of the task text:
- 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: - Now you can call the function we’ve created and print the results. You should do this inside the
main7.cpp
file: - Add the code to return a value
0
inside the main function. Run the program and check the output.
cout << "Lab 0:" << 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;
#pragma once
#ifndef STRING7_H
#define STRING7_H
#include
// your code is here
#endif
//lab 0: Create a function to calculate the addition of pointer and a variable of integer type int addP(int var1, int var2);
//lab 0: 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; }
p_var
is initialized with the location of var1
. The 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.
cout << "Result:" << endl; cout << "pointer + " << var2 << " = " << addP(var1,var2) << endl;
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 ofvar1 = 5
using pointerp1
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
]
2. Accessing an array
To do: Create a function to calculate the addition of array elements. The task should be done using two functions. The first function shouldn't use a pointer accessing the array element by index, but the second function should use.
Note 1: The signature of the functions must be the same except the names:
int sumArray1(int * array, int n); int sumArray2(int * array, int n); |
Expected output:
array: 1 2 3 4 5 the result of the first function: sum = 15 the result of the second function: sum = 15
✍ How to do:
- At first, let's create a function which iterates over the array elements without using a pointer accessing the array element by index:
- Consider memory location:
- Now, let's create a function which iterates over the array elements using a pointer accessing the array element by index:
- Call the function within the
main
and run the program.
int sumArray1(int * array, int n) // array points at the value 1 { // start with sum being 0 int AnswerSum = 0; // count from 0 to n for (int i = 0; i < n; i++) { // update sum by adding array[i] AnswerSum += array[i]; } // give sum as your answer return AnswerSum; } int main() { int data[] = { 1,2,3,4,5 }; cout << "array: " << endl; for (auto x : data) { cout << x << " "; } cout << endl; int sum= sumArray1(data, 5); cout << "the result of the first function: sum = " << sum<< endl;
1. The first loop iteration: |
2. The second loop iteration: |
3. The third loop iteration: |
4.The last loop iteration: |
Back to main function and destroying the frame of sumArray1 : |
int sumArray2(int * array, int n) // array points at the value 1 { // start with sum being 0 int AnswerSum = 0; // loop counter is a pointer to point at the address of the 1-st array element for (int *p = array; p < array + n; p++) { // update sum by adding redereference of p AnswerSum += *p; } // give sum as your answer return AnswerSum; }
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:
- 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
. - Include all the needed libraries and files (if you didn't do it before).
- Open the
main7.cpp
file in the code editor. Type the code to output a message to the user, and to initialize an array in the same line in which you declare it: - Print the array elements before the lab is done:
- After that, let's turn to
string7.h
file and include all necessary directives (if you didn't do it before for the lab1): - The signature of the function was recommended in the task text, let's add that code with a comments of the task text:
- 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: array
returns the memory cell of the first element. But we must make the second element being set to 0. So, we havearray + 1
.- Having
*p = 0
we dereference the pointer, and we make the second element equal to 0. - To do the same manipulations with the fourth element (even), we can increment the pointer by 2 (
p = p + 2
). array + n
means the memory cell of the first element plusn
, which is 9. This provides an exit from the loop.- Now you can call the function we've created and print the results. You must do it inside the
main7.cpp
file: - Add the code to return a
0
value inside the main function. Run the program and check the output.
cout << "Lab 2, Arrays:\n"; int my_arr[] = { 1,2,3,4,5,6,7,8,9 };
cout << "The array before lab is done: " << endl; for (auto x : my_arr) { cout << x << " "; }
#pragma once
#ifndef STRING7_H
#define STRING7_H
#include
#endif
// 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);
//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; } }
* array
parameter is initialized to the location of the array, that will be passed on.Let's consider the line
int* p = array + 1;
.
DelEveryEven(my_arr, 9); cout << "Result: " << endl; for (auto x : my_arr) { cout << x << " "; } cout << endl;
To do: An array of integers is given. Create an application with two functions which return a value of the largest element of the array. One of the functions should be without using of a pointer accessing the array element by index, another one should use the pointer.
Note: The signature of the functions should be the same:
int maxArray1(int * array, int n); int maxArray2(int * array, int n); |
Expected output:
array: 1 2 3 4 5 the result of the first function: max = 5 the result of the second function: max = 5
[Solution and Project name: Lesson_7task2_0
, file name L7Task2_0main.cpp
, L7Task2_0imp.cpp
, L7Task2_0.h
]
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
]
To do: An array of integers is given. Create a function that returns an index of the largest element of the array.
Note 1: The signature of the function should be as follows:
int findLargestInd(int * array, int n); |
Note 2: Withitn the function you should make the comparison:
if (array[i] > array[largestIndex]) { ... } |
Expected output:
Task 3: array: 1 5 3 2 1 index of the largest element = 1
[Solution and Project name: Lesson_7task3
, file name L7Task3main.cpp
, L7Task3imp.cpp
, L7Task3.h
]
3. String characters access with pointer indexing
To do: Two strings are given. Create the function which returns
1
if the strings are equal, and returns 0
otherwise.
Note 1: To access the characters of a string with pointer indexing you should use char
type for that string:
char str1[] = "Apple"; |
Note 2: The signature of the function should be as follows:
int stringEqual(const char * str1, const char * str2); |
Expected output:
// lab 3: the result for 'apple' and 'apple' is: 1 ++++ // lab 3: the result for 'apple' and 'apples' is: 0
✍ How to do:
- Let's declare a function with two arguments, they are constant char pointers to the strings:
- Then, we're going to declare the pointers pointing at the first letter of
str1
and the first letter ofstr2
. Add the code into the function: - Then, we're going to create a loop to be repeated as long as what
p1
points at is the same as whatp2
point at. We should use dereference operator to take the values, that is to take the characters of the strings: - Then, we need to check if
p1
is equaled to\0
, that is the last character which means a termination of a string. In this case the function must return1
(that is answer "yes"): - After, we advance
p1
andp2
to the next letter: - After the loop we need to return answer "no", that is in our function means
0
: - Now, we're going to return to the
main
function and create two c-string. And then to call the function: - Run the program and check the output.
int stringEqual(const char * str1, const char * str2){ ... }
const char* p1 = str1; const char* p2 = str2;
while (*p1 == *p2) {
}
if (*p1 == '\0') { return 1; }
p1++; p2++;
return 0;
char str1[] = "apple"; char str2[] = "apples"; cout << "the result for \'"<< str1 <<"\' and \'"<< str2 <<"\' is: " << stringEqual (str1,str2) << endl;
To do: Create a function to check if c-string contains a combination of letters
'mo'
. Return 1
(if found) or 0
(if not found). It is not allowed to use any standard functions. You should use pointer.
Note 1: The signature of the function must be as following:
bool findMo(const char * str); |
Note 2: To check if this is not an end of the string, you can use the following loop condition:
while (*str != '\0') |
Expected output:
Task 4:
the result for 'the movie was nice' is: 1
[Solution and Project name: Lesson_7task4
, file name L7Task4main.cpp
, L7Task4imp.cpp
, L7Task4.h
]
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 4: The string before lab is done: Hello world The string after lab is done: dlrow olleH
✍ How to do:
- 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
. - Include all necessary libraries and files (if you didn't do it before).
- Open the
main7.cpp
file in the code editor. Type the code to output a message to the user, and to initialize an array of char type (the string will be treated as an array of chars): - After that, let's turn to
string7.h
file and include all the needed directives (if you didn't do it before for the lab1): - The signature of the function was recommended in the task text, let's add that code with a comments of the task text:
- 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: - 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 variablet
. And at the same time we're going to substitute 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: - Now you can call the function we've created and print the results. You must do it inside the
main7.cpp
file: - Add the code to return a
0
value inside the main function. Run the program and check the output.
cout << "Lab 4:" << endl; char str[] = "Hello world"; cout << "The string before lab is done: " << str << endl;
#pragma once
#ifndef STRING7_H
#define STRING7_H
#include
#endif
// Lab 4: Reverse the order of characters in the string. void reverseString(char* str);
str
is initialized to the location of str
.// Lab 4: 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
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). 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 }
reverseString(str); cout << "The string after lab is done: " << str << endl;
To do: There is a string that contains the positive integer ('
Happy 2021 year to u!
'). Create a function to display a substring 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); |
To understand where the end of the string is, you can use the following loop:
while (*str1) { pLast = str1; // the address of the last character *(str1++); } |
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, you should create a function:
bool isdigit(char c) { if ((c <= '9') && (c >= '0')) { return true; } else return false; } |
Expected output:
Task 5: The string for the task is: Happy 2021 year to u! the substring of numbers: 2021
[Solution and Project name: Lesson_7task5
, file name L7Task5main.cpp
, L7Task5imp.cpp
, L7Task5.h
]
To do: A string of characters is given. Convert all uppercase Latin letters to lowercase in it. The function should return the number of substitutions performed.
Note 0: You should use the character string type:
char s[] ="..."; |
Note 1: Use the following function signature. It returns an integer (the number of substitutions):
int to_lower(char * str); |
Note 2: To check if this is not an end of the string, you can use the following loop condition:
while (*str != '\0') |
Note 3: To check if a letter is uppercase letter, you should use the following function:
bool isCappital(char ch) { return (ch >= 'A' && ch <= 'Z'); } |
Note 4: To convert a letter to lowercase, you should use the standard tolower(ch)
function.
Expected output:
Task 6: The string for the task is: HelLo wOrLD The result is: hello world
[Solution and Project name: Lesson_7task6
, file name L7Task6main.cpp
, L7Task6imp.cpp
, L7Task6.h
]
To do: A string of characters is given representing an arithmetic expression of the form "<digit>±<digit>±...±<digit>"
, where the arithmetic operator "+
" (plus) or "−
" (minus) is located in place of the operation sign "±
" (for example, "4+7-2-8
"). Calculate the result of this expression (an integer).
Note 1: Use the following function signature. It returns an integer (the number of substitutions):
int eval(char * expr); |
Note 2: To find the first operand (digit) you can use the following code:
int res = *expr++ - '0'; // here *expr++ is the first character in the string |
or a function:
char r = *expr; //*expr is a code in ascii-table int res = atoi(&r); // converts code to digit |
Note 3: To store the operation or a digit you can use the following concept:
char ch1 = *expr++; //arithmetic operator or digit |
ch1
will be set to 53'9'
- 53 is an address and 9 is a digit stored.
// to take the digit only insted of ch1 you must use : ch1-'0'; |
Expected output:
Task 7: The string for the task is: 9+4-2-0 The result is: 11
[Solution and Project name: Lesson_7task7
, file name L7Task7main.cpp
, L7Task7imp.cpp
, L7Task76.h
]