The strongest C language tutorial in history -- pointer (Preliminary)

Posted by jsim on Tue, 04 Jan 2022 17:24:44 +0100

catalogue

1. What is the pointer?

2. Pointer and pointer type

2.1 pointer + - integer

2.2 dereference of pointer

3. Field pointer

3.1 cause of formation

3.2 how to avoid wild pointer

4. Pointer operation

4.1 pointer + - integer

4.2 pointer - pointer

4.3 pointer relation operation

5. Pointers and arrays

6. Secondary pointer

7. Pointer array

1. What is the pointer?

What is the pointer?

Two key points of pointer understanding:

• 1. Pointer is the number of the smallest unit in memory, that is, the address, that is, the pointer we often say is the address
• 2. The pointer in spoken English usually refers to the pointer variable, which is the variable used to store the memory address, that is, the pointer is the variable

Conclusion: pointer is the address. In colloquial language, pointer usually refers to pointer variable.

Then we can understand it this way:

Memory Pointer variable

We can get the memory address of the variable through & (address operator), and store the address in a variable, which is a pointer variable.

#include <stdio.h>
int main()
{
int a = 10;//Open up a space in memory
int* p = &a;//Here we take the address of variable a, and we can use the & operator.
//The a variable occupies a space of 4 bytes. Here, the address of the first byte of the 4 bytes of a is stored in the p variable
In, p Is a pointer variable.
return 0;
}

Summary:

Pointer variable, a variable used to store the address. (the values stored in the pointer are treated as addresses).

The problem here is:

• How big is a small unit? (1 byte)

After careful calculation and trade-off, we find that it is more appropriate to give a corresponding address to a byte.

For a 32-bit machine, if there are 32 address lines, it is assumed that the high level (high voltage) and low level (low voltage) generated by each address line during addressing are (1 or 0);

00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000001

...

11111111 11111111 11111111 11111111

There are 32 addresses to the power of 2.

Each address identifies a byte, so we can address the idle 4G (2^32Byte == 2^32/1024KB ==2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB).

In the same way, if you give 64 address lines to the 64 bit machine, you can calculate how much space it can address. The calculation method is as shown above, and it will not be calculated here.

Here we know: on a 32-bit machine, the address is 32 zeros or 1s to form a binary sequence, and the address must be stored in 4 bytes, so the size of a pointer variable should be 4 bytes. On a 64 bit machine, if there are 64 address lines, the size of a pointer variable is 8 bytes to store an address.

Summary: pointers are used to store addresses, which uniquely identify an address space. The size of the pointer is 4 bytes on 32-bit platforms and 8 bytes on 64 bit platforms.

2. Pointer and pointer type

Here we are discussing: we all know the types of pointers. Variables have different types, such as integer, floating point, etc.

Does the pointer have a type? To be exact: Yes. When there is such a code:

int num = 10;
p = &num;

To save & num (the address of Num) to p, we know that p is a pointer variable. What is its type? We give the pointer variable the corresponding type.

char  *pc = NULL;
int   *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL;

As you can see here, the pointer is defined as type + *.

In fact, a pointer of type char * is used to store the address of a variable of type char.

A pointer of type short * is used to store the address of a variable of type short.

Pointer of type int * is used to store the address of variable of type int. What is the meaning of pointer type? Next we will explain!

2.1 pointer + - integer

#include <stdio.h>
int main()
{
int n = 10;
char *pc = (char*)&n;
int *pi = &n;

printf("%p\n", &n);
printf("%p\n", pc);
printf("%p\n", pc+1);
printf("%p\n", pi);
printf("%p\n", pi+1);
return  0;
} Summary: the type of pointer determines how far the pointer moves forward or backward.

2.2 dereference of pointer

#include <stdio.h>
int main()
{
int n = 0x11223344;
char* pc = (char*)&n;
int* pi = &n;
*pc = 0;   //Focus on observing memory changes during debugging.
*pi = 0;   //Focus on observing memory changes during debugging.
return 0;
}

The followi n g figure shows the memory space after * pc = 0 is executed As can be seen from the figure, after executing the statement, we only changed the value corresponding to the space of one byte!

The following figure shows the memory space after * pi = 0 is executed, which is consistent with the pointer type we defined, because the pc we defined is a pointer variable of char type, and char only occupies four bytes of memory space. As can be seen from the figure, we changed the value corresponding to the four byte space this time, which is consistent with the pointer type we defined, because pi is a pointer variable of type int, and int occupies four bytes of space in memory.

Summary:

The type of pointer determines how much permission (several bytes can be operated) you have when dereferencing the pointer.

For example, the dereference of char * pointer can only access one byte, while the dereference of int * pointer can access four bytes.

3. Field pointer

Concept: a wild pointer means that the position pointed to by the pointer is unknown (random, incorrect, and without explicit restrictions)

3.1 cause of formation

1. Pointer not initialized

#include <stdio.h>
int main()
{
int* p;//Local variable pointer is uninitialized and defaults to random value
*p = 20;
return 0;
}

2. Pointer cross-border access

#include <stdio.h>
int main()
{
int arr = { 0 };
int* p = arr;
int i = 0;
for (i = 0; i <= 11; i++)
{
//When the range pointed to by the pointer exceeds the range of array arr, p is a wild pointer
*(p++) = i;
}
return 0;
}

3. Release of the space pointed to by the pointer (will be discussed later, not here for the time being)

3.2 how to avoid wild pointer

• 1. Pointer initialization
• 2. Be careful that the pointer is out of range
• 3. The pointer points to the space, even if it is set to NULL
• 4. Avoid returning the address of local variables
• 5. Check the validity of the pointer before use
#include <stdio.h>
int main()
{
int* p = NULL;
//....
int a = 10;
p = &a;
if (p != NULL)
{
*p = 20;
}
return 0;
}

4. Pointer operation

4.1 pointer + - integer

#include<stdio.h>
int main()
{
int x = 0;
int* p = &x;
printf("%p\n", p);
printf("%p\n", p + 1);
char* p2 = (char*)&x;
printf("%p\n", p2);
printf("%p\n", p2+1);
return 0;
} The pointer + - integer is actually the number of bytes across the variable type indicated by the pointer multiplied by the number we added. For example, in the above example, we first performed the + 1 operation on the integer pointer p, and then printed p+1 in the form of address, adding 4 bytes compared with the original p. similarly, p2 is a pointer of char type. After we performed the + 1 operation on it, Compared with the original p2 address, it is increased by 1 byte.

4.2 pointer - pointer

#include<stdio.h>
int main()
{
int arr = { 1,2,3,4,5 };
int* p1 = &arr;
int* p2 = &arr;
printf("%d", p1 - p2);
return 0;
} The result of subtraction above is 4. Why do you get 4? Because there are four integer elements between p1 and p2, why should we emphasize that it is an integer element in this place? Because the pointer types on both sides of the operator are integer pointers. In fact, the subtraction of pointer type variables is the subtraction of the address represented by the pointer, dividing the obtained value by the number of bytes occupied by the space pointed to by the pointer. This is not easy for you to understand. It is a little abstract. Let me give you a simple example, For example, in the above example, the address value stored in p1 is 16 and the value stored in p2 is 0. Then we divide the 16 obtained by subtracting p1 from p2 by the data type pointed to by p1 and p2, that is, the integer type. The number of bytes occupied by each integer element is 4, so the result after dividing 16 by 4 is 4, that is, the final output result on the screen is 4, so many small partners ask, In the above example, after we cast the type of two pointers to char type, will the result change to 16, because the reasoning method given by me above should be like this, because the number of bytes occupied by char type is 1, and the result after dividing 16 by 1 is still 16, Next, let's show whether the code is like our reasoning. The result is 16 Like our derivation, this confirms that our derivation is correct!

4.3 pointer relation operation

Since the address stored in the pointer variable is essentially just a string of data, the size can also be compared! There are no more examples here to show you, because it is not difficult to understand, but we will emphasize a key point below!

Standard provisions:

A pointer to an array element is allowed to be compared with a pointer to the memory location after the last element of the array, but it is not allowed to be compared with a pointer to the memory location before the first element.

5. Pointers and arrays

Let's take an example:

#include <stdio.h>
int main()
{
int arr = { 1,2,3,4,5,6,7,8,9,0 };
printf("%p\n", arr);
printf("%p\n", &arr);
return 0;
}

Operation results: It can be seen that the array name and the address of the first element of the array are the same.

Conclusion: the array name represents the address of the first element of the array. (except for the two cases, which are explained in the array chapter)

Then it is feasible to write code like this:

int arr = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p stores the address of the first element of the array

Since the array name can be stored as an address in a pointer, it is possible for us to use the pointer to access one.

For example:

#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,0 };
int* p = arr; //Pointer to the address of the first element of the array
int sz = sizeof(arr) / sizeof(arr);
for (int i = 0; i < sz; i++)
{
printf("&arr[%d] = %p   <====> p+%d = %p\n", i, &arr[i], i, p + i);
}
return 0;
} So p+i actually calculates the address of array arr subscript i.

Then we can access the array directly through the pointer.

As follows:

int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int* p = arr; //Pointer to the address of the first element of the array
int sz = sizeof(arr) / sizeof(arr);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", *(p + i));
}
return 0;
} 6. Secondary pointer

Pointer variable is also a variable. If it is a variable, it has an address. Where is the address of pointer variable stored? This is the secondary pointer. The operations of the secondary pointer are:

• *ppa finds pa by dereferencing the address in ppa, * ppa actually accesses PA
int b = 20;
*ppa = &b;//Equivalent to PA = & B;
• **ppa first finds pa through * ppa, and then dereferences PA: * PA, it finds a
**ppa = 30;
//Equivalent to * pa = 30;
//Equivalent to a = 30;

7. Pointer array

Is a pointer array a pointer or an array?

Answer: array. Is an array of pointers.

Array, we already know integer array, character array.

int arr1;
char arr2;  