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