Pointers and arrays
1.1. Use Pointers to access array elements
An array is a group of continuously stored data of the same type. The arithmetic operation of the pointer can make the pointer point to each element of the array in turn, and then the array can be traversed.
Defines a pointer to an array element
- Definition and assignment
int a[10], *pa;
pa=&a[0]; Or pa = a;Copy the code
- Equivalent form
- After the above definition and assignment
* pa is a [0], * (pa +1) is a [1],... , * (pa + I) is a [I] a [I], * (pa + I), * (a + I), pa [I] are equivalent.Copy the code
Note: you cannot write a++ because a is the beginning of the array and is a constant.
Case 6-7
Let’s say we have an array a of type int that has 10 elements. Output each element in three ways:
- Use array names and subscripts
- Use the array name and pointer operations
- Using pointer variables
Example 6-7 (1) uses array names and subscripts to access array elements
#include
using namespace std;
int main(a) {
int a[10] = { 1.2.3.4.5.6.7.8.9.0 };
for (int i = 0; i < 10; i++)
cout << a[i] << "";
cout << endl;
return 0;
}
Copy the code
Example 6-7 (2) uses array names and Pointers to access array elements
#include
using namespace std;
int main(a) {
int a[10] = { 1.2.3.4.5.6.7.8.9.0 };
for (int i = 0; i < 10; i++)
cout << *(a+i) << "";
cout << endl;
return 0;
}
Copy the code
Example 6-7 (3) uses pointer variables to access array elements
#include
using namespace std;
int main(a) {
int a[10] = { 1.2.3.4.5.6.7.8.9.0 };
for (int *p = a; p < (a + 10); p++)
cout << *p << "";
cout << endl;
return 0;
}
Copy the code
1.2. Pointer arrays
Pointer to an array
- The elements of the array are Pointers
Example 6-8 use pointer arrays to store matrices
#include
using namespace std;
int main(a) {
int line1[] = { 1.0.0 }; // First row of the matrix
int line2[] = { 0.1.0 }; // Second row of the matrix
int line3[] = { 0.0.1 }; // Third row of the matrix
// Define an integer pointer array and initialize it
int *pLine[3] = { line1, line2, line3 };
cout << "Matrix test:" << endl;
// Output matrix
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++)
cout << pLine[i][j] << "";
cout << endl;
}
return 0; } Matrix test:1.0.0
0.1.0
0.0.1
Copy the code
Compare pointer arrays with two-dimensional arrays
- Pairs the scales 6-8 in the pointer array and the following two-dimensional array
int array2[3] [3] ={ { 1.0.0 }, { 0.1.0 }, { 0.0.1}};Copy the code
Pointers and functions
2.1. Use Pointers as function parameters
Example 6-10 reads three floating-point numbers and prints the integer and decimal parts separately
#include <iostream>
using namespace std;
void splitFloat(float x, int *intPart, float *fracPart) {
*intPart = static_cast<int>(x); // Take the integer part of x
*fracPart = x - *intPart; // Take the decimal part of x
}
int main(a) {
cout << "Enter 3 float point numbers:" << endl;
for(int i = 0; i < 3; i++) {
float x, f;
int n;
cin >> x;
splitFloat(x, &n, &f); // The address of the variable is taken as an argument
cout << "Integer Part = " << n << " Fraction Part = " << f << endl;
}
return 0;
}
Copy the code
Example: take a parameter to a pointer to a constant
#include <iostream>using namespace std;
const int N = 6;
void print(const int *p, int n);
int main(a) {
int array[N];
for (int i = 0; i < N; i++)
cin>>array[i];
print(array, N);
return 0;
}
void print(const int *p, int n) {
cout << "{" << *p;
for (int i = 1; i < n; i++)
cout << "," << *(p+i);
cout << "}" << endl;
}
Copy the code
2.2 pointer type functions
If the return value of a function is a pointer, the function is of type pointer.
The definition of a pointer function
Storage Type Data type * Function name () {// Function body statement
}
Copy the code
Wrong example
int main(a){
int* function(a);
int* ptr= function(a); *prt=5; // Dangerous access!
return 0;
}
int* function(a){
int local=0; // The scope and lifetime of non-static local variables are confined to the body of this function
return &local;
}// at the end of the function, the local variable is released
Copy the code
Correct example 1
#include
using namespace std;
int main(a){
int array[10]; // Array defined in the main function
int* search(int* a, int num);
for(int i=0; i<10; i++)
cin>>array[i];
int* zeroptr= search(array, 10); // Pass the first address of the array in the main function to the child function
return 0;
}
int* search(int* a, int num){ // The pointer a points to the array defined in the main function
for(int i=0; i<num; i++)
if(a[i]==0)
return &a[i]; // Return the address to the element defined in the main function
}// the address of a[I] is still there
Copy the code
Correct example 2
#includeusing namespace std;
int main(a){
int* newintvar(a);
int* intptr= newintvar(a); *intptr=5; // Access a valid address
delete intptr; // If you forget to release here, you will cause a memory leak
return 0;
}
int* newintvar (a){
int* p=new int(a);return p; // The returned address points to dynamically allocated space
}// When the function ends, the address in p is still valid
Copy the code
2.3. Pointers to functions
Definition of a function pointer
-
Define the form
Storage type Data type (* function pointer name)();
-
meaning
Function Pointers point to the program code store
A typical use for function Pointers – to implement function callbacks
-
A function called through a function pointer
For example, passing a pointer to a function as an argument allows different methods to be used flexibly when handling similar events.
-
Callers don’t care who is called
The function being called needs to know that there is a specific stereotype and constraint.
Function pointer example
#include <iostream>
#include <thread>
int compare(int a, int b, int(*function)(int a, int b));
int max(int a, int b);
int main(a) {
std::cout << compare(25.16, &max) << std::endl;
}
int compare(int a, int b, int (*function)(int a, int b)) {
return function(a, b);
}
int max(int a, int b) {
return a > b ? a : b;
}
Copy the code
Object pointer
-
Object Pointers define the form
Class name * object pointer name;
Ex. :
Point a(5.10);
Piont *ptr;
ptr=&a;
Copy the code
-
Object members are accessed through Pointers
Object pointer name -> member name
Ex. :
ptr->getx() is equivalent to (* PTR).getx(a);Copy the code
Example 6-12 uses Pointers to access members of the Point class
//6_12.cpp
\#include <iostream>
using namespace std;
class Point {
public:
Point(int x = 0.int y = 0) : x(x), y(y) { }
int getX(a) const { return x; }
int getY(a) const { return y; }
private:
int x, y;
};
int main(a) {
Point a(4.5);
Point *p1 = &a; // Define an object pointer initialized with the address of a
cout << p1->getX() << endl;// Use a pointer to access an object member
cout << a.getX() << endl; // Access object members with object names
return 0;
}
Copy the code
This pointer
- Points to the current object itself
- Implicit in every non-static member function of a class.
- Indicates the object on which the member function operates.
- When a member function is called from an object, the system assigns the address of the object to the this pointer and then calls the member function, which implicitly uses the This pointer when it operates on the data members of the object.
- For example, in the getX function of the Point class:
return x;
Is equivalent to:
return this->x;
Examples of mistakes that have been made
class Fred; // Forward reference declaration
class Barney {
Fred x; // Error: the declaration of class Fred is incomplete
};
class Fred {
Barney y;
};
Copy the code
Correct procedure
class Fred; // Forward reference declaration
class Barney {
Fred *x;
};
class Fred {
Barney y;
};
Copy the code
Dynamic memory allocation
4.1. Dynamically allocate and release memory
Dynamic memory application operator new
- New type name T (initialization parameter list)
- Function: During the execution of the program, apply for memory space for storing T type objects, and assign initial values according to the list of initial values.
- Result value: success: pointer of type T to the newly allocated memory; Failure: Throws an exception.
Release the memory operator delete
- Delete the pointer p
- Frees the memory pointed to by pointer P. P must be the return value of the new operation.
Example 6-16 Example of dynamically creating objects
#include <iostream>
using namespace std;
class Point {
public:
Point() : x(0), y(0) {
cout<<"Default Constructor called."<<endl;
}
Point(int x, int y) : x(x), y(y) {
cout<< "Constructor called."<<endl;
}
~Point() { cout<<"Destructor called."<<endl; }
int getX(a) const { return x; }
int getY(a) const { return y; }
void move(int newX, int newY) {
x = newX;
y = newY;
}
private:
int x, y;
};
int main(a) {
cout << "Step one: " << endl;
Point *ptr1 = new Point; // Call the default constructor
delete ptr1; // The destructor is automatically called when the object is deleted
cout << "Step two: " << endl;
ptr1 = new Point(1.2);
delete ptr1;
return 0;
}
Copy the code
Running results:
Step One:
Default Constructor called.
Destructor called.
Step Two:
Constructor called.
Destructor called.
Copy the code
4.2. Applying for and releasing dynamic arrays
Allocate and release dynamic arrays
- Assignment: new type name T [array length]
- The array length can be any expression that is evaluated at run time
- Release: delete[] array name p
- Releases the array to which the pointer p points. P must be the first address assigned by new.
Example 6-17 Example of dynamically creating an object array
#include<iostream>
using namespace std;
class Point { // class declaration like example 6-16, omitted};
int main(a) {
Point *ptr = new Point[2]; // Create an array of objects
ptr[0].move(5.10); // Access a member of an array element through a pointer
ptr[1].move(15.20); // Access a member of an array element through a pointer
cout << "Deleting..." << endl;
delete[] ptr; // Delete the entire array of objects
return 0;
}
Copy the code
Running results:
Default Constructor called.
Default Constructor called.
Deleting...
Destructor called.
Destructor called.
Copy the code
Dynamically create multidimensional arrays
New type name T'[first dimension length]'[second dimension length]… ;
- If the memory is successfully allocated, the new operation returns a pointer to the first address of the newly allocated memory.
Such as:
char (*fp)[3];
fp = new char[2] [3];
Copy the code
Example 6-19 Dynamically creating a multidimensional array
#include <iostream>
using namespace std;
int main(a) {
int (*cp)[9] [8] = new int[7] [9] [8];
for (int i = 0; i < 7; i++)
for (int j = 0; j < 9; j++)
for (int k = 0; k < 8; k++)
*(*(*(cp + i) + j) + k) =(i * 100 + j * 10 + k);
for (int i = 0; i < 7; i++) {
for (int j = 0; j < 9; j++) {
for (int k = 0; k < 8; k++)
cout << cp[i][j][k] << "";
cout << endl;
}
cout << endl;
}
delete[] cp;
return 0;
}
Copy the code
Encapsulate dynamic arrays as classes
- More concise, easy to manage
- You can check if the subscript is out of bounds before accessing an array element
Example 6-18 Dynamic array class
#include <iostream>
#include <cassert>
using namespace std;
class Point { // Class declaration as in example 6-16... };
class ArrayOfPoints { // Dynamic array class
public:
ArrayOfPoints(int size) : size(size) {
points = new Point[size];
}
~ArrayOfPoints() {
cout << "Deleting..." << endl;
delete[] points;
}
Point& element(int index) {
assert(index >= 0 && index < size);
return points[index];
}
private:
Point *points; // point to the first address of the dynamic array
int size; // Array size
};
int main(a) {
int count;
cout << "Please enter the count of points: ";
cin >> count;
ArrayOfPoints points(count); // Create an array object
points.element(0).move(5.0); // Access a member of an array element
points.element(1).move(15.20); // Access a member of an array element
return 0;
}
Copy the code
Running results:
Please enter the number of points:2
Default Constructor called.
Default Constructor called.
Deleting...
Destructor called.
Destructor called.
Copy the code
Why does the Element function return a reference to an object?
Returns a reference that can be used to manipulate an array element that encapsulates the interior of an array object. If you return a value, you only return a copy, and you cannot manipulate the elements in the original array
5. Smart Pointers
5.1. Smart Pointers
- Explicit management internals are powerful, but error-prone.
- C++11 provides smart pointer data types, some support for garbage collection techniques, and some level of memory management
5.2 C++11 smart pointer
- Unique_ptr: Do not allow multiple Pointers to share resources. You can use the move function in the library to move Pointers
- Shared_ptr: Multiple Pointers share a resource
- Weak_ptr: ShareD_PTR can be copied, but its construction or release has no impact on resources
Vector
Why vector?
- Encapsulate any type of dynamic array, automatically create and delete.
- Array subscript out of bounds check.
- The ArrayOfPoints encapsulated in Examples 6-18 provide similar functionality, but only for one type of array.
The definition of vector
- Vector < element type > The name of the array object (array length);
- Ex. :
vector<int> arr(5)
Copy the code
Create an int array of size 5
The use of vector objects
- A reference to an array element
- Has the same form as normal arrays: vector name [subscript expression]
- The name of the vector object does not indicate the address at the beginning of the array
- Get the array length
- Size, array object name.size()
Example 6-20 Vector application example
#include <iostream>
#include <vector>
using namespace std;
// Calculate the average value of the elements in array ARr
double average(const vector<double> &arr)
{
double sum = 0;
for (unsigned i = 0; i<arr.size(a); i++) sum += arr[i];return sum / arr.size(a); }int main(a) {
unsigned n;
cout << "n = ";
cin >> n;
vector<double> arr(n); // Create an array object
cout << "Please input " << n << " real numbers:" << endl;
for (unsigned i = 0; i < n; i++)
cin >> arr[i];
cout << "Average = " << average(arr) << endl;
return 0;
}
Copy the code
Range-based for loop with auto example
#include <vector>
#include <iostream>
int main(a)
{
std::vector<int> v = {1.2.3};
for(auto i = v.begin(a); i ! = v.end(a); ++i) std::cout << *i << std::endl;for(auto e : v)
std::cout << e << std::endl;
}
Copy the code
Copy and move objects
7.1 Shallow replication and deep replication
- Shallow copy
- Implements one-to-one copy of data elements between objects.
- Deep copy
- When the object data member to be copied is of a pointer type, instead of copying the pointer member itself, the object to which the pointer points is copied.
Example 6-21 Shallow copy of objects
#include <iostream>
#include <cassert>
using namespace std;
class Point {
// Class declaration as in example 6-16
/ /...
};
class ArrayOfPoints {
// Class declaration as in example 6-18
/ /...
};
int main(a) {
int count;
cout << "Please enter the count of points: ";
cin >> count;
ArrayOfPoints pointsArray1(count); // Create an array of objects
pointsArray1.element(0).move(5.10);
pointsArray1.element(1).move(15.20);
ArrayOfPoints pointsArray2(pointsArray1); // Create a copy
cout << "Copy of pointsArray1:" << endl;
cout << "Point_0 of array2: " << pointsArray2.element(0).getX() < <","
<< pointsArray2.element(0).getY() << endl;
cout << "Point_1 of array2: " << pointsArray2.element(1).getX() < <","
<< pointsArray2.element(1).getY() << endl;
pointsArray1.element(0).move(25.30);
pointsArray1.element(1).move(35.40);
cout<<"After the moving of pointsArray1:"<<endl;
cout << "Point_0 of array2: " << pointsArray2.element(0).getX() < <","
<< pointsArray2.element(0).getY() << endl;
cout << "Point_1 of array2: " << pointsArray2.element(1).getX() < <","
<< pointsArray2.element(1).getY() << endl;
return 0;
}
Copy the code
The running results are as follows:
Please enter the number of points:2
Default Constructor called.
Default Constructor called.
Copy of pointsArray1:
Point_0 of array2: 5.10
Point_1 of array2: 15.20
After the moving of pointsArray1:
Point_0 of array2: 25.30
Point_1 of array2: 35.40
Deleting...
Destructor called.
Destructor called.
Deleting...
Copy the code
Then the program runs incorrectly.
Example 6-22 Deep copy of an object
#include <iostream>
#include <cassert>
using namespace std;
class Point { // Class declaration as in example 6-16
};
class ArrayOfPoints {
public:
ArrayOfPoints(const ArrayOfPoints& pointsArray);
// For other members, see example 6-18
};
ArrayOfPoints::ArrayOfPoints(const ArrayOfPoints& v) {
size = v.size;
points = new Point[size];
for (int i = 0; i < size; i++)
points[i] = v.points[i];
}
int main(a) {
/ / 6 to 20 with example
}
Copy the code
The running results of the program are as follows:
Please enter the number of points:2
Default Constructor called.
Default Constructor called.
Default Constructor called.
Default Constructor called.
Copy of pointsArray1:
Point_0 of array2: 5.10
Point_1 of array2: 15.20
After the moving of pointsArray1:
Point_0 of array2: 5.10
Point_1 of array2: 15.20
Deleting...
Destructor called.
Destructor called.
Deleting...
Destructor called.
Destructor called.
Copy the code
7.2. Mobile Structure
There are many examples in real life, we move money from one account to another, we move mobile SIM cards to another phone, we cut files from one location to another… Mobile construction can reduce unnecessary replication, resulting in performance improvements.
- A new constructor is provided in the C++11 standard, the move construct.
- Prior to C++11, you could only transfer the state of a source object to a target object by copying it. In some cases, we don’t need to copy objects — we just need to move them.
- C++11 introduces mobile semantics:
- All control of the source object resource is given to the target object
- Move constructor
Problems and Solutions
- When a temporary object is copied, it is no longer used. We can simply move the resources of temporary objects directly, thus avoiding redundant copying operations.
Mobile structure
-
When should a move construct be triggered?
- There are temporary objects that can be exploited
-
Move constructor:
class_name ( class_name && )
Example: Function returns object with pointer member (version 1)
- Use the deep copy constructor
A temporary object is constructed on return, and dynamic allocation returns the temporary object to the calling function, then deletes the temporary object.
#include<iostream>
using namespace std;
class IntNum {
public:
IntNum(int x = 0) : xptr(new int(x)){ // constructor
cout << "Calling constructor..." << endl;
}
IntNum(const IntNum & n) : xptr(new int(*n.xptr)){// Copy constructor
cout << "Calling copy constructor..." << endl;
};
~IntNum() {// destructor
delete xptr;
cout << "Destructing..." << endl;
}
int getInt(a) { return *xptr; }
private:
int *xptr;
};
// Return an IntNum object
IntNum getNum(a) {
IntNum a;
return a;
}
int main(a) {
cout<<getNum().getInt()<<endl;
return 0;
}
Copy the code
Running results:
Calling constructor...
Calling copy constructor...
Destructing...
0
Destructing...
Copy the code
Example: Function returns object with pointer member (version 2)
- Use the move constructor
Local objects to be returned are moved to the calling function, eliminating the need to construct and delete temporary objects.
#include<iostream>
using namespace std;
class IntNum {
public:
IntNum(int x = 0) : xptr(new int(x)){ // constructor
cout << "Calling constructor..." << endl;
}
IntNum(const IntNum & n) : xptr(new int(*n.xptr)){// Copy constructor
cout << "Calling copy constructor..."<< endl; Note: •&& is an rvalue reference • The temporary variable returned by the function is an rvalue}IntNum(IntNum && n): xptr( n.xptr){ // Move the constructor
n.xptr = nullptr;
cout << "Calling move constructor..." << endl;
}
~IntNum() {// destructor
delete xptr;
cout << "Destructing..." << endl;
}
private:
int *xptr;
};
// Return an IntNum object
IntNum getNum(a) {
IntNum a;
return a;
}
int main(a) {
cout << getNum().getInt() << endl; return 0;
}
Copy the code
Running results:
Calling constructor...
Calling move constructor...
Destructing...
0
Destructing...
Copy the code
8. String
8.1. String Constants
- Example: “the program”
- Characters are stored consecutively and sequentially, each character is a byte, ending with ‘\0’, and is equivalent to an implicitly created array of character constants
- “Program” appears in the expression and represents the beginning address of the char array
- The first address can be assigned to the char constant pointer:
const char *STRING1 = "program";
Copy the code
Storing strings with character arrays (C-style strings)
- For example,
char str[8] = { 'p'.'r'.'o'.'g'.'r'.'a'.'m'.'\ 0' };
char str[8] = "program";
char str[] = "program";
Copy the code
Disadvantages of representing strings with character arrays
- Connecting, copying, comparing, and so on all require explicit calls to library functions, which can be cumbersome
- When the length of the string is uncertain, you need to use new to dynamically create the array of characters, and finally use delete, which is tedious
- An out-of-bounds array subscript error occurs when the actual length of the string is greater than the space allocated for it
8.2, the string class
- Use the string class string to represent a string
- A string is really a wrapper around a character array operation
A common constructor for the string class
-
string(); // The default constructor creates a string of length 0
Example: the string s1;
-
string(const char *s); // Initialize a string with the string constant pointed to by the pointer s
Example: string s2 = “ABC”;
-
string(const string& rhs); // Copy constructor
Example: string s3 = s2;
Common string operations
-
S + t joins strings S and T into a new string
-
S = t update s with t
-
S == t determine whether s is equal to t
-
s ! = t to determine whether s and t are equal
-
S < t determine whether S is less than t
-
S <= t determine whether S is less than or equal to t
-
S > t determine whether S is greater than t
-
S >= t determine whether S is greater than or equal to t
-
S [I] accesses the subscript I character in the string
Ex. :
string s1 = "abc", s2 = "def";
string s3 = s1 + s2; // result is "abcdef"
bool s4 = (s1 < s2); // The result is true
char s5 = s2[1]; // The result is 'e'.
Copy the code
Example 6-23 Example of string application
#include <string>
#include <iostream>
using namespace std;
// Prints true or false based on the value of value
//title is the prompt text
inline void test(const char *title, bool value)
{
cout << title << " returns "
<< (value ? "true" : "false") << endl;
}
int main(a) {
string s1 = "DEF";
cout << "s1 is " << s1 << endl;
string s2;
cout << "Please enter s2: ";
cin >> s2;
cout << "length of s2: " << s2.length() << endl;
// Compare operator tests
test("s1 <= \"ABC\"", s1 <= "ABC");
test("\"DEF\" <= s1"."DEF" <= s1);
// Test the connection operator
s2 += s1;
cout << "s2 = s2 + s1: " << s2 << endl;
cout << "length of s2: " << s2.length() << endl;
return 0;
}
Copy the code
Consider: How to enter a full line of strings?
- Entering a string with the >> operator of CIN will be delimited by a space, which will be read the next time it is typed
Enter a full line of strings
- Getline can input a whole line of strings (including the string header), for example:
getline(cin, s2);
- When entering a string, you can use other delimiters (such as a comma, semicolon) to indicate the end of the string. You can use the delimiter as the third argument to getLine, for example: getLine (cin, s2, ‘,’);
Example 6-24 enter a string using getline
#include <iostream>
#include <string>
using namespace std;
int main(a) {
for (int i = 0; i < 2; i++){
string city, state;
getline(cin, city, ', ');
getline(cin, state);
cout << "City:"<< city << "State:" << state << endl; return 0; }Copy the code
Running results:
Beijing,China
City: Beijing State: China
San Francisco,the United States
City: San Francisco State: the United States
Copy the code