const, pointer *, reference & in C++

const, pointer, reference

Article directory

  • const, pointer, reference
    • const modification points to the variable itself
    • Assignment between pointers, numerical compatibility
    • Quote & amp; (alias)
    • Quoted Features
    • The difference between references as formal parameters and pointers
    • The relationship between reference and const
    • Function parameter design
    • Often cited
    • lvalue & amp; rvalue & amp; rvalue reference
    • other citation forms
    • The difference between references and pointers (emphasis)
      • difference in grammatical rules
      • Compilation level difference
    • use of references

const modification points to the variable itself

int main()
{
    const int n=5;//In cpp, n is a constant variable with a name
    int ar[n]={1,2,3,4,5}; //Unable to pass in the .C compilation environment, n is not a constant, #define enum
    
    int b=0;
    int *p = (int*) &n;
    *p=100;
    b=n; //n=5, n has been replaced with 5 during compilation, here should be b=5
    printf("n=%d b=%d *p=%d \\
",n,b,*p);
    return 0;
}

The interpretation of const (constant) is different between the C compilation method and the C++ compilation method.

int main()
{
int a=10,b=20;
    int * p1= &a;
    //*p1=100;a=100;p1= &b;
    const int* p2= &a;
    //int const* p2= & amp;a; is equivalent to the previous line
    //*p2=100; error
    p2 = & b;
    //const is on the left of *, modifying the pointing ability of the pointer, so the value of a cannot be changed through *p2, but p2 itself can be changed
    
    int* const p3= &a;
    //const is on the right side of *, modifying the pointer variable name, making p3 a constant pointer
    *p3=100;
    //p3= & amp; b; error
        
    const int* const p4= & amp;a;//The pointer p4 itself and pointing to are const modified as constant and cannot be modified
    //*p4=100; error
    //p4= & amp; b; error
}
int main()
{
    int a=10;
    const int b=20;
    int *p1= &a;
    //int* p2 = & amp;b; error //Use ordinary pointers to point to constant variables, you can change b by *p2=200;
    const int* p2 = & b;
    int* p3=(int*)b;//unsafe, ambiguous
    *p3=100;
    //The constant variable should use the constant pointer to point to its address const int*, not the same as the ordinary pointer.
}

Assignment between pointers, numerical compatibility

//Mutual assignment between pointers
//Modification capability cannot be extended
int main()
{
    const int a=10; //Constant variable, not allowed to be changed
    const int* s= & amp;a; //s points to a constant, and a constant pointer can point to a constant variable or an ordinary variable, but the value of the variable cannot be changed by dereferencing
    
    int* p1=s; //error can change the value of a through *p1, but cannot change the value of a through *s
    const int* p2 = s;
    int* const p3=s; //error const modified p3 itself cannot be changed, but a can be modified by dereferencing *p3
    const int* const p4 = s;
    return 0;
}
int main()
{
    int a=10,b=10;
    int* const s= & amp;a; //s itself cannot be adapted, but can be changed by dereferencing *s
    
    int *p=s; // do not change s
    const int *p2=s; // can be pointed to but cannot be changed
    int * const p3 = s;
    const int * const p4 = s;
    
    return 0;
}

Reference & amp; (alias)

int main()
{
    int a=10;
    int b=a;
    int & amp; c=a;//type & amp; variable --> reference; & amp; variable --> address
    a + =10;
    cout<<"a="<<a<<"c"<<c<<endl;
    c + =10;
    cout<<"a="<<a<<"c"<<c<<endl;
    
    cout<<" & amp;a: "<< & amp;a<<endl;
    cout<<" & amp;c: "<< & amp;a<<endl;
    //a and c have the same address
    return 0;
}

Characteristics of the citation

  1. Definition references must be initialized
  2. No null references
  3. A reference without a reference (int & amp; & amp; x), cannot be the first so-called second-level reference at a time
int main()
{
    int a=10,b=20;
    //int & amp; x; error definition reference must be initialized, there is no null reference
    //int & amp; & amp; x=a; error cannot define a secondary reference once
    int & x=a;
    int & y=x;
    return 0;
}

The difference between references as formal parameters and pointers

void Swap_Int(int* ap,int* bp)
{
    assert(ap!=NULL & amp; & amp; bp!=NULL);
    int tmp=*ap;
    *ap=bp;
    *bp=tmp;
}

void Swap(int & amp; x, int & amp; y)
{
    //There is no null reference, no assert assertion or null judgment is required
    int tmp=x;
    x=y;
    y=tmp;
}b

int main()
{
    int a=10,b=20;
    cout<<"a="<<a<<"b="<<b<<endl;
    //Swap_Int( &a, &b);
    Swap(a,b);
    cout<<"a="<<a<<"b="<<b<<endl;
    
    return 0;
}

Relationship between reference and const

int main()
{
    int a=10;
    int & b=a;
    b + =10;
    int const & amp; c=a; //cosnt modification & amp;, constant reference, c can read the value of a, but cannot modify the value of a by modifying c
    int & amp; const x=a; //const modifier refers to x itself, the system will ignore this const, and can read and modify x
    cout<<c<<endl;
    //c + =100; error
}
int main()
{
    const int a=10;
    //int & amp; x=a; error The constant variable cannot be modified, and a can be modified by referring to x by using ordinary references
    const int & y=a;
}

Function parameter design

void fun_a(int x)
{}

void fun_b(int & y)
{}

void fun(const int & y)
{}

Common references

int main()
{
    int a=10;
    const int b=20;
    const int & rx=a;
    const int & ry=b;
    const int & rz=100;
    //tmp=100;
    //const int & amp; rz=tmp;
}

lvalue & amp; rvalue & amp; rvalue reference

//Left value left value, which can be used to fetch addresses & amp;a, has nothing to do with the type
//Right value right value, address fetch operation is not allowed, eg: 10, & amp;10 error
int main()
{
    int a=10; // & amp; a, left value
    const int b=20; // & amp; b, left value
    int & amp; x=a; // & amp; x, left value
    const int & amp; y=b; // & amp; y,lvalue
    double dx=12.23; // &dx,lvalue
    int ar[5]{1,2,3,4,5}; // &ar[1],lvalue
    
    //const int & amp; r=b;
    const int & amp; z=10;//Constant references can be used as aliases for constant variables
    //int tmp=10; When referring to a literal constant, a temporary variable needs to be created, which is an alias of the temporary variable tmp when referring to z
    //const int & amp; z=tmp;
    //z + =10; error z is a constant reference and cannot modify the original value
    
    //int & amp; & amp; ra=a; error, a is an lvalue and cannot be referenced by an rvalue
    int & amp; & amp; r=10; //Rvalue reference, r becomes an alias of 10
    //int tmp=10;
    //int & amp; r=tmp;
    r + =10; //Operation can be performed, but not on the literal constant 10, but on the temporary variable tmp
    
    return 0;
}

Other citation forms

//Array reference
int main()
{
    int ar[5]{1,2,3,4,5}; // &ar[1],lvaule
    int & amp; a=ar[1]; //Refer to an element in the array
    
    //int & amp;br[5]; error The array opens up space, reference & amp; does not open up space, a contradiction
    int ( & amp;cr)[5]=ar; //Refer to the entire array, cr is an alias for ar
    
    cout<<"sizeof(ar):"<<sizeof(ar)<<endl;//20
    cout<<"sizeof(cr):"<<sizeof(cr)<<endl;//20
}
//reference of pointer type
int main()
{
    int a=10,b=20;
    int* ip= &a;
    int & x=a;
    int* s=ip;
    int * & amp;ps=ip; //Alias ps refers to the integer pointer ip (int* represents the integer pointer type)
    
    *ps=100; //equivalent to *ip=100
    cout<<"*ps=>"<<*ps<<"*ip=>"<<*ip<<endl;
    ps= & amp;b; //equivalent to ip= & amp;b
    cout<<"*ps=>"<<*ps<<"*ip=>"<<*ip<<endl;
    *ps=200;
    cout<<"*ps=>"<<*ps<<"*ip=>"<<*ip<<endl;
    return 0;
}

The difference between references and pointers (emphasis)

References are syntactic sugar for pointers

Differences in grammatical rules

  1. From the grammatical rules, a pointer variable stores the address of an instance (variable or object); a reference is an alias of an instance.
  2. The program allocates a memory area (32-bit 4-byte x86, 64-bit 8-byte x64) for a pointer variable; it does not allocate a memory area for a reference.
  3. When using pointers and references to instances or aliases, dereferencing means adding “*” in front of pointers; references can be used directly.
  4. The value of the pointer variable can be changed to store the addresses of different instances (modify the pointed address, eg: pointer + + or pointer –); the reference should not be initialized when it is defined, and cannot be changed afterwards (it cannot be another instance references).
  5. A pointer variable can be null (null pointer NULL); there are no null references. eg: The difference between formal parameters, the formal parameter bit pointer variable needs to be null or asserted, and the formal parameter is a reference, which does not need this operation.
  6. When a pointer variable is used as a formal parameter, it needs to be tested for its legality (judging NULL); the reference does not need to be judged as null, which is more secure.
  7. The size of the pointer variable (32-bit 4-byte x86, 64-bit 8-byte x64) when using “”sizeof” for the pointer variable; using “sizeof” for the reference variable The size is the size of the variable being referenced.
  8. Theoretically, there is no limit to the level of pointers; but there is only one level of reference. i.e. there are no references to references, but there can be pointers to pointers. Difference: int & amp; & amp; a; rvalue reference.
  9. The operation on the pointer variable will cause the pointer to point to the address of the next entity (variable or object), without changing the content of the pointed entity (variable or object). Operations on references are directly reflected on the referenced entity (variable or object). eg: + + references have different effects from + + pointers.
  • Supplementary Note: Functions are not allowed to return local variables in the form of references or pointers.
int funa(int* p)
{
    if(p==NULL) //The pointer needs to be null or asserted
        
    {
        return -1;
    }
    *p + = 10;
    return *p;
}
int funb(const int & a)
{
    
}

int main()
{
    int a=10;
    int x=10;
    int & b=a;
    b=x; //4 is to assign x to a
    int=*ip= &a;
    *ip =100;
    b + =200;
    funb(10);
    
    return 0;
}
//The size of pointers and references, the use of sizeof
int main()
{
    double dx=12.25;
    double & amp; rx=dx;
    double* dp= & amp;dx; //double *dp= & amp;rx;
    
    cout<<"sizeof(rx):"<<sizeof(rx)<<endl;
    cout<<"sizeof(dp):"<<sizeof(rx)<<endl;
    return 0;
}
// + + references and + + pointers have different effects
// + + pointer, pointing to the address of the next storage unit; + + reference, directly modify the value of the referenced object
int main()
{
    int ar[5]{1,2,3,4,5};
    int & a=ar[0];
    int* p= & ar[0];
    for(int i=0;i<5; + + i)
    {
        cout<<ar[i]<<" ";
    }
    cout<<endl;
    //1 2 3 4 5
    
     + + a; //value of ar[0] + 1
    a + =10' //The value of ar[0] + 10
    for(int i=0;i<5; + + i)
    {
        cout<<ar[i]<<" ";
    }
    //12 2 3 4 5
    cout<<endl;
    
    cout<<"*p "<<*p<<endl; //*p 12
    
     + + p; //p changed from pointing to ar[0] to pointing to ar[1]
   cout<<"*p "<<*p<<endl; //*p 2
    return 0;
}
//References are the same as pointers. Functions are not allowed to return local variables in the form of references or pointers (static variables and global variables can: after the end of the function, the lifetime is not over or the formal parameters are also references, accepting variables also for reference)
int & amp; funx(int & amp; y)
{
    a + =20;
    return a;
}

int* funa()
{
    int a=10;
    return &a;
}
int & funb()
{
    int a=20;
    return a;
}
void fun()
{
    int ar[10]={1};
}

int main()
{
    int *p=funa();
    fun(); //Clean up the stack space allocated when funa() is called, and the original value is overwritten
    cout<<*p<<endl; //0
    
    int & x=funb();
    fun();
    cout<<x<<endl; //0
    
    int & x=funx(y);
    return 0;
}

Differences at the compilation level

//From the bottom layer, a reference is a pointer that is itself constant
void fun(int & x)
{
    int* ip= &x;
    x=100;
}
int main()
{
    int a=10;
    int & b=a;
    fun(a);
    fun(b);
    return 0;
}

// After the pointer replaces the reference
void fun(int * const x)
{
    int* ip=x;
    *x=100;
}
int main()
{
    int a=10;
    int* const b= &a;
    fun( &a);
    fun(b);
    return 0;
}

Use of citations

//built-in type
int Add_Int(const int x, const int y)
{
    return x + y;//Access x, access memory once
}
int Add_Int_a(int & amp; x, int & amp; y) // pass in the address of a and b (refer to the underlying bit pointer)
{
    return x + y;//Access x needs to be dereferenced, so access twice
}
int Add_Int_b(const int & amp; x, const int & amp; y)
{
    return x + y;//Access x needs to be dereferenced, so access twice
}

/*For built-in types, directly use Add_Int(int x, int y) for value transfer, reducing memory access, not suitable for using references, because there is no need to react to actual parameters through changes in formal parameters
*/

int main()
{
    int a=10,b=20;
    int c=0;
    c=Add_Int(a,b);
    
    cout<<c<<endl;
    return 0;
}

Whether the function needs to react to the actual parameter to change the actual parameter through the change of the formal parameter –> whether to use the reference as the formal parameter

//The type designed by yourself
struct Stud
{
int ar[10];
    int num;
};
void funa(struct Stud s)//Need to assign s1 to s, and s also needs to open up 10 integer spaces when calling
{
    
}
void funb(struct Stud const & amp; s)//alias, calling this function does not need to open up additional space, & amp;s is & amp;s1, which is equivalent to pointer {} //only need to pass 4 bytes, the form The change of parameter s may change the actual parameter s1, plus //const modification, read-only and not modifiable
    
void func(struct Stud* s)
{
    if(s==NULL) return;
    //Need to assert or judge empty
}

int main()
{
    struct Stud s1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10};
    funa(s1);
    funb(s1);//For the type designed by yourself, it is best to use the reference form for the formal parameters, which saves space and saves security checks
    int a=10;
    int & b=a;
    const int & c=a;
    //const int* const c= & amp;a; constant reference, represented as a pointer to a constant at the bottom
    
    return 0;
}

When writing a program, the type parameters designed by oneself can use references instead of pointers.