C + + array and array name problems (pointer, dereference)

Posted by MarcAndreTalbot on Fri, 17 Sep 2021 04:52:07 +0200

1, Pointer

1.1 difference between pointer variable and ordinary variable

Pointer: the essence of pointer is a variable. It has no essential difference from ordinary variables. Pointer integrity should be called pointer variable, referred to as pointer. It means pointing. The pointer itself is an object, and the pointer does not need to be assigned at the time of definition.

1.2 why do I need a pointer

Pointers appear for indirect access. There is indirect access in the assembly, which is actually the indirect access in the addressing mode of the CPU.

Indirect access (indirect addressing of CPU) is determined by CPU design, which determines that assembly language must be able to realize query and seek, and C language above assembly must also realize brief addressing.

1.3 Pointer use Trilogy

Trilogy: defining pointer variables, associating pointer variables, and dereferencing

(1) When we define a pointer variable p by int *p, because P is a local variable, we also follow the general law of local variables in C language (if a local variable is defined and uninitialized, the value is random), so at this time, a random number is stored in the P variable.

(2) At this time, if we dereference p, it is equivalent to that we have accessed the memory space with the random number as the address. I don't know whether this space can be accessed or not (maybe not), so if you directly define a pointer variable without binding a valid address, you will die if you dereference it.

(3) Defining a pointer variable to dereference without binding a valid address is like taking a boring gun and turning it around at will and then firing it.

(4) The meaning of pointer binding is to make the pointer point to a place that can be accessed and should be accessed (just like the process of aiming and marking with a gun). The dereference of the pointer is to indirectly access the target variable (just like shooting to hit the target)

int val = 43;
int * p = &val;   // &The right value is the value character
cout << *p << endl;

//output
43

2, Integer, floating point array

preface

  • In many places where array names are used, the compiler will automatically replace them with a pointer to the first element of the array.
  • Therefore, in most expressions, using an array name is actually using a pointer to the first element of the array.

2.1 array names are actually special pointers

int main()
{
	int a[] = { 0,1,2,3,4 };
	printf("%x\n", a);
	printf("%x\n", &a);
	printf("%x\n", &a[0]);
}

  1. As can be seen from the local variable table, the composition of array A and pointer p is very similar. They actually store an address and point to an object (or the first object of multiple objects). So the array name is actually a special pointer.
  2. Why is it special?

One dimensional array

    int a[] = { 0,1,2,3,4 };
    int * p1 = a;
    int *p = &a[0];
    //The pointer p is int * and the first element has an address, so addressing is allowed
    
	//int * p1 = &a;    // error
	//Understanding: int (* P1) [5] = & A// correct
	/*
	But they are different in themselves:
	The pointer p1 itself is an object for which space is allocated in memory;
	Array name a is not allocated space in memory space (this will cause the effect of &a operation to be different from expected).
	It can be understood that a points to an array containing 5 integers, so the type of & A is int(*)[5], which cannot be used to initialize int */	

arrangement:

Pointertype
aint *
&aint (*) [5]

Two dimensional array

       int ia[3][4];
       int (*p)[4] = ia;      //The type of ia is int(*)[4]
       int (*p)[3][4] = &ia;  //&The type of IA is int(*)[3][4]

arrangement:

Pointertype
iaint (*) [4]
&1aint (*) [3] [4]

2.2 understanding complex array declarations

The array name mentioned above is a pointer to an array, so explain some complex array declarations. acquire a better understanding

   int * ptr[10];             //ptr is an array of 10 integer pointers
   int & ref[10]  = /* ? */   //Error, no referenced array exists
   int (*parray) [5] = &a;   //parray points to an array of 5 integers
   /*
   It is also the explanation of the above array name
   *parray Means that parray is a pointer;
   On the right is [5], indicating that it points to an array of size 10;
   Int on the left indicates that the elements in the array are int
   */
   
   int (&array)[5] = a;      //Array refers to an array containing 5 integers

   int * (&array) [10]  = ptrs;
   //Array is a reference to an array that contains 10 pointers

2.3 array name a, array name address & A, array first element address & A [0], pointer to array first element * p

int main()
{
	int a[] = { 0,1,2,3,4 };
	printf("%x\n", a);
	printf("%x\n", &a);
	printf("%x\n", &a[0]);

	int *p = &a[0];
	
	decltype(a) t;
	decltype(&a) tt;

	cout << p << endl;
	printf("%x,%x\n", a + 1, p + 1);
	printf("%x\n", &a + 1);

	cout << sizeof(a) << " " << sizeof(&a) << endl;
}

output

  1. Since a is a special pointer, it will be the stored address when printing.
  2. &The type of a is int(*)[5] (the reading method is to go out from the small brackets, first the pointer, then the array with size 5, and then the array element type is int). From the local variable, its type can also be written as int[5] *: that is, the pointer to the int array with size 5. Because the array name has no memory allocation space, so &a the address is the address of the first element of the array.
  3. &A [0] is the address of an int object, which is the first element of the array. To sum up, the printed addresses of a & A & A [0] are the same.
  4. p. Pointer to the first element of the array.
  5. Both a + 1 and P + 1 are increased by 4 according to the number of bytes (4 bytes) of the element size.
  6. &A + 1, as mentioned earlier, the type of & A is a pointer to an int array of size 5. The int array of size 5 occupies 20 bytes, so & A + 1 should be increased by 20.
  7. sizeof(a) is 20 because the total byte size of the array is 20. Sizeof & A is 4 because & A is a pointer that occupies 4 bytes in a 32-bit system.

2.4 understanding of array name and value character &

Each element in the array is an object, that is, it occupies a specific type of memory space. (an object occupies a memory space of array type, because an object refers to a memory space that can store data and has a certain type.)

The array name can be converted to the address of the first element of the array object.

Let's not discuss one-dimensional arrays here, but start with two-dimensional arrays. The so-called two-dimensional array is also an array, but its elements are also an array.

First, we write a two-dimensional array for use

#include<iostream>
using namespace std;
int a[][10]={
    {1,2,3,4,5,5,6,7,8,8},
    {10,12,32,42,51,15,16,71,121,18}
};

Briefly explain the array: array a is an array containing 2 elements, and each element is an array containing 10 int s.
Since the array name is the address of the first object, let's verify it. Test the array name and find the address for the array name:

void test01(){
    cout << (long long)a << endl;         // 140273290059808
    cout << (long long)(a+1) << endl;     // 140273290059848
    // Difference of 40 bytes
   }

(40 bytes can be seen at a glance by using long long)

The difference between a and a + 1 is exactly 40 bytes. Description:

(1) Array name a is the address of the whole line of objects (first element {1,2,3,4,5,5,6,7,8,8}), that is, the address of the first element;

(2) Therefore, an element size of 40 bytes is offset at a+1.

void test01(){
    cout << (long long)&a << endl;        // 140273290059808
    cout << (long long)(&a+1) << endl;    // 140273290059888
    // Difference of 80 bytes
   }

&A is exactly 80 bytes different from & A + 1. Description:

(1) The address fetcher obtains the address of the whole object, &a which addresses the two-dimensional array and aims at the whole object;

(2) & A + 1 offset by one bit becomes the tail address of the whole two-dimensional array. The tail address in c + + is the next bit of the address where the object is located& A + 1 is exactly 80 bytes more than a.

It is also mentioned above that the array name will be automatically converted into a special pointer (the summary in the two tables). Next, we will understand what this pointer is?

  1. Understand from pointer dereference:

    void test03(){
        cout << *a << endl;     // 0x7f051ce02020
        //For verification, let's offset
        cout << *(a + 1) << endl; // 0x7f051ce02048
        // Exactly 40 bytes apart
    }
    

    *A after dereferencing the array name is the first element (because the array name is a special pointer to the first element), and the first element is also an array with 10 elements. Now * a represents this object, and the output is the address of the first element of this array - 1.

     cout << *(*a) << endl; //1 * * a	
    

    The second layer is solved: * (* a) is naturally the first int element.

     cout << *a[0] << endl; //   1
    

    Because when the pointer points to the array object, you can use the subscript to access the next position. A is that the pointer points to the array, and the next offset is 0, that is, * a = * (a + 0)

     // cout << (a[0])[0] << endl; 
     cout << a[0][0] << endl;//   1
    

    Based on the above, * a, that is, a[0], will also be automatically converted into a pointer to its first object (the position of the first element of 10 elements). Therefore, a[0] can use subscripts to access other elements in the array object (10 elements): a[0][0] == 1

    Let's do a few more cases:

        // What about accessing the next element of the current row? Put this first address
        cout << *(*a + 1) << endl;// 2 i.e. * (* a) + 1) 
        // Note that the pointer here is (* a),
        cout << (*a)[1] << endl; //    2
        // Similarly (* a) is equivalent to * (a + 0), i.e. a[0] 
        cout << a[0][1] << endl; //2
        
        // What if you visit the next line?
        cout << **(a+1) << endl;
        cout << *a[1] << endl; 
        cout << a[1][0] << endl; // *(a[1] + 0)
        
        // What about the second element in the second line?
        cout << *(*(a+1) +1 ) << endl;
        cout << *(a[1] +1) << endl;
        cout << a[1][1] << endl;
    
    
  2. View array name type understanding

    cout << typeid(*a).name()<< endl;  // A10_i
    cout << typeid(&a[0]).name()<< endl; // PA10_i
    

    A10_i: Is an array of 10 int s
    PA10_i: Is a pointer type that points to an array object that has 10 int objects. The compiler recognizes it as int(*)[10]

    cout << typeid(a).name()<< endl; // A2_A10_i
    cout << typeid(&a).name()<< endl; // PA2_A10_i	
    

    A2_A10_i: The multidimensional array is an array of arrays. A indicates that this is an array type, and 2 indicates that it is an array composed of two objects. Each object (A10_i) is an array with 10 objects, which are of type int.

    PA2_A10_i: Is a pointer type, pointing to an array object, which has 2 array objects. The compiler recognizes it as int(*)[2][10]

3, Character array name

c + + does not output the address of the character array name, but directly outputs the characters

#include <iostream>
using namespace std;
 
int main()
{
	//int a[5]={1,2,34,4,5};   // If not char type, cout < < a = "< < a < < endl;
	// The output is the first address of the int array. The values in the array are not output.
	char a[5]="aaaa";         //cout overloads char [], which can output the whole string array
	cout<<"a="<<a<<endl;
	return 0;
}

Detailed reference This blog

Topics: C C++