Pointer: Memory address of the storage, which can only be an address, pointing to a region of memory

The CPU needs addresses to access memory, not variable and function names! Variable and function names are just mnemonics for addresses, and they will be replaced with addresses when the source file is compiled and linked into an executable program. An important part of the compilation and linking process is finding the addresses that these names correspond to.

The location of data in memory is also called a pointer. If a variable stores a pointer to a piece of data, it is called a pointer variable.

In C, it is possible to store a pointer in a variable called a pointer variable. The value of a pointer variable is the address of a piece of data. Such a piece of data can be an array, a string, a function, or another ordinary variable or pointer variable.

Understanding a single pointer variable:

A single pointer variable, p, stores the memory address of variable A,*p gets the value of the memory address stored, which is 10

    int a = 10;// Entity variables
    p = &a;// the memory address assigned to a by the pointer p
    // Check the address of a
    printf("&a = %p\n", &a);//&a = 000000000061FDE4
    // the memory address of a is stored in the pointer variable p
    printf("p=%p\n", p);//p=000000000061FDE4
    // The pointer variable p also has an address because the variable also has an area of memory. *p takes the entity with the address changed, that is, the stored value
    printf("p=%p,*p=%d\n", &p, *p);//p=000000000061FDE8,*p=10
Copy the code

If I change p = 100 does the value of variable A change? The answer is: what will change because of P is the memory address of A, so the value of A will also change

    // If you change the value of *p, the original value will also change, because it is the same address. This is equivalent to changing the memory address 000000000061FDE4
    *p = 100;
    printf("a=%d,*p=%d\n", a, *p);//a=100,*p=100
Copy the code

Type of pointer

Pointers are typed, but the size of the pointer is fixed (the size of the underlying type is different). The type of the pointer comes first and the type to which the pointer points comes later. int *p; // Pointer type -> int *, pointer type -> int

int **p; // Pointer type -> int **, pointer type -> int *

 	printf("sizeof p = %llu\n".sizeof p);Sizeof p = 8

    char b = 'c';
    char *c = &b;
    char d = *c;// Retrieve the pointer variable c to store the actual value of the address
    printf("sizeof c = %llu\n".sizeof c);//char *p sizeof c = 8
    printf("d=%c\n", d);//d=c
Copy the code

The size of both int * and char * Pointers is fixed regardless of type

The size of a pointer is a fixed 8 bytes (64 is 8 bytes, 32 is 4 bytes). The size of a pointer is constant regardless of the type of pointer. Addresses are not long or short.

Note: Pointers have types. Pointers to int cannot store types of char

    // Note that Pointers are typed, not char Pointers, but int Pointers
    // The variable a is of type int
    char *e = &a;//Incompatible pointer types initializing 'char *' with an expression of type 'int *'
Copy the code
  1. The step size of the pointer

The step size of the pointer is determined by the type of the pointer. The step size of the int type is 4 bytes and the step size of the char type is 1 byte

    int aa = 0xaabbccdd;
    int *p1 = &aa;
    char *p2 = &aa;
    printf("p1=%x\n",*p1);//p1=aabbccdd
    printf("p2=%x\n",*p2);//p2= FFFFFFDD *p2 finds the value stored at aa's address and uses it as a char

    // both p1 and p2 are the same address
    printf("p1=%p\n",p1);//p1=000000000061FDBC

    printf("p2=%p\n",p2);//p2=000000000061FDBC

    printf("p1=%p\n",p1+1);//p1=000000000061FDC0 + 4 bytes int type = 4 bytes

    printf("p2=%p\n",p2+1);//p2=000000000061FDBD + 1 byte Char type = 1 byte
Copy the code

The following code:

Int **p, note that *p refers to a pointer variable, and the size of the pointer type is always 8 bytes (64 bits), whereas **p is the value of the specific base variable, depending on the base type.

	int p = 10;
	int* p1 = &p;
	int** p4 = &p1;
	printf("Size :%d, size 2 :%d \n".sizeof(*p4),sizeof(**p4));// Size :8, size 2:4
Copy the code

Pointer arrays and array Pointers

At the beginning of learning C language, often can not distinguish the pointer array and ** array pointer, ** they two have what difference? Let me show you once and for all

() > [] > ***

P2 is an array of Pointers.

  • The priority of [] is greater than *
  • So P2 [4] presupposes an array of four Spaces
  • Int * indicates that the array holds a pointer to int
  • An array of Pointers must be an array of Pointers
	int* p2[4];// array p2[4] is an array, int * stores Pointers to int
Copy the code

Let’s look at the following code:

  • The precedence of parentheses is first combined with parentheses *p3 pointer
  • [4] points to the following array
  • The array is of type int

A pointer to an array of type int is a pointer to an array of type int

int(*p3)[4];// Array pointer
Copy the code

Pointer arrays are used as follows:

int main(a) {
    // Array of Pointers
    int a[] = {10.11};
    int b[] = {20};
    int c[] = {30};

    //a = &a[0] is a pointer to int
    int * d[] = {a, b, c};/ / is the address of a pointer array stored * d = = & a * * d = * (& a) & a = & a [0] * (& a [0])
    printf("&a[0]=%p,&d[0]=%p,d[0]=%d,*(&a[0])=%d\n",&a,*d,**d,*(&a[0]));
    //&a=000000000061FE1C,&d[0]=000000000061FE1C,d[0]=10,*(&a[0])=10

    //*d+1 *d = &a[0] *d+1 = &a[0]+1
    printf("&a[1]=%p,&d[0]=%p,a[1]=%d\n",&a+1,*d+1,*(*d+1));
    //&a[1]=000000000061FE20,&d[0]=000000000061FE1C,a[1]=11

    *(&a[0]) *(&a[0])
    printf("%d,&a[0]=%p,&a=%p\n",*(&a[0] +1),&a[0],&a);
    //11 &a[0]=000000000061FE18,&a=000000000061FE18

    // Infer that *d[0] = **d *d[1] = **(d+1) *d = &a
    printf("d[0]=%d,%d,d[1]=%d,%d\n",*d[0],**d,**(d+1),*d[1]);
    [1] / / d = 20, 20

    //**(d+1) == *(*(d+1))
    printf("%d\n",*(*(d+1)));

    return 0;
}
Copy the code

Wild pointer, null pointer, dangling pointer

Note the difference between wild, null, and dangling Pointers

  • Wild pointer

Wild pointer: an uninitialized pointer whose content is a garbage number

	int* p7;// There is no initialization to point to any address, so it is a wild pointer
	//printf("p:0x%x\n",p7);
Copy the code
  • Null pointer

NULL == 0, the NULL pointer does not point to any instance of an object or function. On the other hand, the address of any object or function cannot be a NULL pointer. The region allocated by the NULL pointer from 0x00000000 to 0x0000FFFF is free and has no corresponding physical memory. For this space, any read or write operation will cause an exception. A null pointer is an address to which the program has no physical memory at any time.

int* p8 = NULL;// A pointer that is not initialized and assigned to NULL is NULL
Copy the code
  • Dangling Pointers

Dangling pointer: a pointer is normally initialized. The layer points to a normal object, but the object is destroyed. The pointer is not null and becomes a dangling pointer.

	int* p8 = NULL;// A pointer that is not initialized and assigned to NULL is NULL

	{
		int i = 6;
		p8 = &i;
		*p8 = 7;
		printf("----%p,%p\n",&i,p8);/ / - 0000004 a9d9df914, 0000004 a9d9df914
	}
	// It is important to note that the variable I is destroyed when the block is finished, but its memory is not cleared and still exists so *p8 can still get 7
	P8 is already a dangling pointer, because the memory address it points to is not held by any variable. The variable is destroyed, but the information stored in the memory address is not cleared
	int b = *p8;
	printf("b=%d\n",b);//b=7
Copy the code

Pointer expression

Understand common pointer expressions and the results of operations

	/ * * pointer expressions cp & ch ch * * * & cp cp * * * * cp + 1 (cp + 1) * * * + + cp * cp++ cp++ + + cp * * * * * + + cp * * (* cp) cp + + + + + + * * * ++*cp++ */
Copy the code
	char ch = 'a';
	char name = ch;//ch as an rvalue will fetch the stored value

	char* cp = &ch;//cp as an lvalue will store the memory address pointed to, and cp has its own address, but its value is stored also address.

	char* cp1 = cp;//cp as an rvalue will take the stored value: &ch

	printf("cp:%p,cp1:%p\n", cp, cp1);//cp:00000067C21FFA14,cp1:00000067C21FFA14

	printf("& cp: % p, & ch: % p/n",&cp,&ch);&ch: 00000067C21FFA38, &ch:00000067C21FFA14
	*cp = 'b';// The value of ch also changes
	printf("%c,%c\n",ch,*cp1);//b,b

	char** cp2 = &cp;
	printf("&ch:%p,ch:%c\n",*cp2,**cp2);//&ch:000000E9984FFD24,ch:b

	char name1 = *cp;/ / reference solution
	printf("name1:%c\n", name1);//name1:b

	// cp+1 ==> * > + (* will precede +)
	char name2 = *cp + 1;//b (*cp) + 1 == a + 1 == b

	//*(cp+1) ==> cp (cp+1) ==> cp (cp+1) ==> cp (cp+1
	printf("%c\n", *(cp + 1));/ / random value

	printf("%p,%p\n", ++cp, cp++);/ / 00000067 c21ffa16, 00000067 c21ffa14
Copy the code

Memory management

C has the final say in memory management. Unlike The Java language, which automatically manages memory, C requires manual memory allocation and release

In computer, memory is generally divided into stack area and heap area (in fact, only Java language will have a method area). In C, variables are generally defined in the stack area. If you want to define in the heap area, you need to apply for memory space from the heap area.

	// The heap allocates memory
	int* arr = malloc(16);
Copy the code

In the above code, Pointersarr16 bytes of memory space is applied, and the pointer type is int. The memory model is as follows:

#include <stdio.h>
#include <malloc.h>
#include <memory.h>

int main(a) {
	// The heap allocates memory
	int *arr = malloc(16);
	/ / set the value
	memset(arr,1.16);
	//i:0 value:0,
	//i:1 value : 0,
	//i : 2 value : 0,
	//i : 3 value : 0,
	for (int i = 0; i < 4; i++) {
		printf("i:%d value:%d,\n",i,*(arr+i));
	}

	free(arr);// The arR pointer must be set to NULL
	arr = NULL;

	//malloc(size): allocates a contiguous area of size bytes in the dynamic storage area of memory, returning the first address

	//calloc(n,size) allocates n contiguous size bytes in the dynamic storage area of memory and zeros them out
	int* a = calloc(2.8);//2*8 is also 16 bytes of memory
	/* i:0 value:0 p:000001E669A6B9E0 i:1 value:0 p:000001E669A6B9E4 i:2 value:0 p:000001E669A6B9E8 i:3 value:0 p:000001E669A6B9EC */
	for (int i = 0; i < 4; i++) {
		printf("i:%d value:%d p:%p\n", i, *(a + i),(a+i));
	}

	// Free the requested memory
	free(a);
	a = NULL;

	return 0;
}
Copy the code

The following code, to achieve a data exchange function: this can exchange success? In fact, it can not, according to memory can think about it.

It didn’t work out. Why? Because passes are values, x and y are in the swap stack frame, and both x and y are destroyed after swap

int swap(int x, int y) {
	printf("swap before x:%d,y:%d\n",x,y);
	int tmp = x;
	x = y;
	y = tmp;
	printf("swap after x:%d,y:%d\n",x,y);
}

int main(a) {
	int x = 2;
	int y = 4;
	swap(x, y);// Swap x and y
	// But will the exchange succeed? The answer is no
	/* swap before x:2,y:4 swap after x:4,y:2 swap main:x:2,y:4 */
	printf("swap main:x:%d,y:%d\n",x,y);
}
Copy the code

As shown in the following figure, x and y in main are not the same memory address as x and y in swap. They are only passed values. Therefore, x and y in main cannot be swapped.

So how do you exchange the values of two variables? In this case, we need to use Pointers, because Pointers are to the memory address, through the above understanding to use the same memory address to achieve the exchange of values.

/* Passes the memory address */
int swap2(int *x, int *y) {
	printf("swap before x:%d,y:%d\n", *x, *y);
	int tmp = *x;
	*x = *y;
	*y = tmp;
	printf("swap after x:%d,y:%d\n", *x, *y);
}
Copy the code

The actual execution mode is shown in the following figure:

The exchange of values takes place by passing addresses

	/* swap before x:2,y:4 swap after x:4,y:2 swap2 main:x:4,y:2 */
	swap2(&x, &y);

Copy the code

Now, if ordinary variable values are swapped, can Pointers also be swapped? Take a look at this code

	int* a = &x;
	int* b = &y;
	printf("swap2 before ---- main:a:%p,b:%p\n", a, b);
	// Implement the exchange between Pointers
	swap2(a, b);// If a and B are passed, x and y swap but a and B's addresses do not swap
	printf("swap2 ---- main:x:%d,y:%d\n", x, y);
	printf("swap2 after ---- main:a:%p,b:%p\n", a, b);

/* Pass the memory address, data exchange must pass the address */
int swap2(int *x, int *y) {
	printf("swap before x:%d,y:%d\n", *x, *y);
	int tmp = *x;
	*x = *y;
	*y = tmp;
	printf("swap after x:%d,y:%d\n", *x, *y);
}
Copy the code

The result is as follows: A and B do not swap values (note the value: the address to which the pointer is stored), but instead the x and y to which the pointer is pointing are swapped.

	/* swap2 before ---- main:a:00000060BC5FF634,b:00000060BC5FF654 swap before x:2,y:4 swap after x:4,y:2 swap2 ---- main:x:4,y:2 swap2 after ---- main:a:00000060BC5FF634,b:00000060BC5FF654 */
Copy the code

Think about it. Why is that? First, we need to think about the overall memory modelThere are also two Pointers a and B in swap, which are completely different from the two Pointers A and B in main. Suppose that (a, B) passed to swap is actually the memory address of x and y, so x and Y are swapped.So how do you switch the storage addresses of A and B? In fact, we need to pass a and B their own addresses (&a & B), thus implementing the exchange of Pointers

It is important to remember that the exchange of two values must pass the address, whether it is a normal variable or a pointer variable (Pointers are just special ordinary variables).

swap2(&a, &b);
	/* swap2 before ---- main:a:00000057EB0FF634,b:00000057EB0FF654 swap before x:-351275468,y:-351275436 swap after x:-351275436,y:-351275468 swap2 ---- main:x:2,y:4 swap2 after ---- main:a:00000057EB0FF654,b:00000057EB0FF634 */
Copy the code