C language has an in-depth understanding of pointers (very detailed) (1)

memory and address

Memory

When comparing memory and address, let’s give an example in life:
Suppose there is a dormitory building, and you are placed in the building. There are 100 rooms upstairs, but the rooms are not numbered. One of your friends comes to play with you. ,
if you want to find you, you have to look for each house one by one, which is very inefficient, but if we number each room according to the floor and the room on the floor, such as:

⼀楼:101102103...
⼆楼:201202203...

With the room number, if your friend gets the room number, he can quickly find the room and find you.

The same goes for our names. If we don’t have a name, it’s still difficult to quickly find someone we don’t know.

Therefore, it can be seen that in some cases, numbering can improve the efficiency of work.

We know that memory stores data. When we need to calculate this data, we will use the CPU (central processing unit). When the CPU needs to use the data, it will read it from the memory, and then the processed data will be put back into the memory
. When buying a computer, you often see 8GB/16GB/32GB... So how to manage these memory spaces efficiently?
In fact, the memory is divided into memory units. The size of each memory unit is 1 byte.
Let’s add some common units of computers.

bit - ⽐特位     1byte = 8bit
byte - 字节      1KB = 1024byte
KB               1MB = 1024KB
MB               1GB = 1024MB
GB               1TB = 1024GB
TB               1PB = 1024TB
PB

Among them, each memory unit is equivalent to a student dormitory. One byte space can hold 8 bits, just like the eight-person room where classmates live. Each person has one bit and each memory unit also has one
. number (this number is equivalent to the house number of a dormitory room), with the number of this memory unit, the CPU can quickly find a memory space.
In life, we also call the house number an address, and in a computer, we also call the number of a memory unit an address. In the C language, a new name is given to the address: pointer.
So we can understand it as:
the number of the memory unit is both an address and a pointer.
The memory storage method is as shown in the figure.
insert image description here

addressing understanding

When the CPU accesses a certain byte space in the memory, it must know where the byte space is in the memory. Since there are many bytes in the memory, the memory needs to be addressed (just like there are many dormitories and the dormitories need to be numbered) . ).

Addressing in computers does not record the address of each byte, but is done through hardware design.

There are many hardware units in a computer, and the hardware units must work together. The so-called collaboration must at least be able to transmit data between each other. But hardware and hardware are independent of each other, so how to communicate? The answer is simple, connect them with "lines".
There is also a large amount of data interaction between the CPU and memory, so the two must be connected with lines. However, today we are concerned with a group of lines called the address bus

We can simply understand that a 32-bit machine has 32 address buses, and each line has only two states, indicating 0 and 1 [the presence or absence of electrical pulses]. Then one line can represent 2 meanings, and 2 lines can represent 4 meanings, and so on. 32 address lines can represent 2^32 meanings, each meaning represents an address.
The address information is sent to the memory. In the memory, the data corresponding to the address can be found, and the data is transferred to the CPU internal register through the data bus.

insert image description here
Therefore, in the x86 environment, the char* pointer variable and the int* pointer variable are both 4 bytes. There are
32 address lines on a 32-bit machine. Therefore, the electrical signals transmitted on the address lines are converted into digital signals, resulting in 32 The additional sequence composed of 0/1 is the address.
In the x64 environment, there are 64 address lines, so the address is a binary sequence composed of 64 0/1. To store such an address, 8 bytes are needed.

Pointer variables and addresses

Get address operator (&)

After understanding the relationship between memory and address, let's go back to C language. Creating variables in C language is actually applying for space in memory , such as:

#include <stdio.h>
int main()
{
    
    
int a = 10;
return 0;
}

The above code creates an integer variable a, and applies for 4 bytes in the memory to store the integer 10. Each byte has an address. The addresses of the 4 bytes in the above figure are:

0x006FFD70
0x006FFD71
0x006FFD72
0x006FFD73

So how can we get the address of a?

Here you have to learn an operator (&)-address operator # const modified pointer

#include <stdio.h>
int main()
{
    
    
int a = 10;
&a;//取出a的地址
printf("%p\n", &a);
return 0;
}

According to the example in the picture above, it will be printed and processed: 006FFD70&a takes out the address of the smaller byte among the 4 bytes occupied by a.
insert image description here
Although the integer variable occupies 4 bytes, we only need to know the first byte. Address, it is also feasible to follow the clues to access 4 bytes of data.

Pointer variable dereference operator (*)

pointer variable

Then the address we get through the address operator (&) is a value, such as: 0x006FFD70. Sometimes this value needs to be stored for later use. So where do we store such an address value? The answer is: pointer variable

#include <stdio.h>
int main()
{
    
    
int a = 10;
int* pa = &a;//取出a的地址并存储到指针变量pa中
return 0;
}

Pointer variables are also a kind of variables. This type of variable is used to store addresses. The value stored in the pointer variable will be understood as an address.

How to disassemble pointer types

We see that the type of pa is int*, how should we understand the type of pointer?

int a = 10;
int * pa = &a;

Here p a is written on the left side of int*, * is indicating that pa is a pointer variable, and the previous int is indicating that what pa points to is an object of type integer (int). Similarly, if there is
a variable ch of type char, ch What type of pointer variable should the address be placed in?

char ch = 'w';
char *pc = &ch;

dereference operator

After we save the address in the pointer variable, how do we use it? Since only the address is saved, we need to find the corresponding data based on the address. How to find the corresponding data requires the use of the dereference operator (*).

 #include <stdio.h>
 int main()
{
    
    
int a = 100;
int* pa = &a;
*pa = 0;
return 0;
}

* pa means to find the space pointed to by the address stored in pa, pa is actually a variable; so pa=0, this operator changes a to 0
, but there is a question here, why use pointers to What about modifying variables? Why not just a=0,?
In fact, in some cases, it is more convenient to use pointers, for example:
insert image description here
we can see that the printed a value and b value are different, the reason is that we pass in different ways, one is passed in the address, the other is not passed in, and the other is not passed in Even if b in the address is modified in the function, the modified value cannot be retained when the function exits. However, a in the address passed in can be retained after being modified.
For example (the example may not be very good, but it is almost the meaning): You have a house that is being renovated, and the address of the house has not changed after the renovation, but the house has changed

size of pointer variable

We learned from the previous content that a 32-bit machine assumes 32 address buses. The electrical signal from each address line is converted into a digital signal and is 1 or 0. Then we regard the binary sequence generated by the 32 address lines as a Address, then an address is 32 bits, which requires 4 bytes to store.
If the pointer variable is used to store the address, then the size of the pointer variable must be 4 bytes of space.
Similarly, for a 64-bit machine, assuming there are 64 address lines, an address is a binary sequence composed of 64 binary bits. It requires 8 bytes of space to store, and the size of the pointer is 8 bytes. Conclusion: •

insert image description here
insert image description here
32
bits The address on the platform is 32 bits, and the pointer variable size is 4 bytes. The
address on the 64-bit platform is 64 bits, and the pointer variable size is 8 bytes
. Note that the size and type of the pointer variable are irrelevant, as long as Variables of pointer type have the same size on the same platform

The meaning of pointer variable types

The size of a pointer variable has nothing to do with its type. As long as it is a pointer variable, the size is the same under the same platform. Why are there various pointer types?

pointer dereferencing

//代码1
#include <stdio.h>
int main()
{
    
    
int n = 0x11223344;
int *pi = &n;
*pi = 0;
return 0;
}
//代码2
#include <stdio.h>
int main()
{
    
    
int n = 0x11223344;
char *pc = (char *)&n;
*pc = 0;
return 0;
}

Debugging we can see that code 1 will change all 4 bytes of n to 0, but code 2 only changes the first byte of n to 0.
Conclusion: The type of the pointer determines how much authority you have when dereferencing the pointer (how many bytes can be manipulated at a time).
For example: the dereference of the pointer of char * can only access one byte, and the dereference of the pointer of int* can access four bytes

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;
}

insert image description here
We can see that the pointer variable +1 of type char * skips 1 byte, and the pointer variable +1 of type int skips 4 bytes. This is the change brought about by the type difference of pointer variables.
Conclusion: The type of pointer determines how far
(distance) the pointer moves forward or backward.

const modified pointer

const modified variable

Variables can be modified. If the address of the variable is given to a pointer variable, the variable can also be modified through the pointer variable .
But what if we want a variable to have some restrictions and not be modified? This is what const does

#include <stdio.h>
int main()
{
    
    
int m = 0;
m = 20;//m是可以修改的
const int n = 0;
n = 20;//n是不能被修改的
return 0;
}

In the above code, n cannot be modified. In fact, n is essentially a variable, but after being modified by const, there are grammatical restrictions. As long as we modify n in the code, it does not conform to the grammatical rules, and an error will be reported, resulting in There is no way to modify n directly. But if we bypass n, use the address of n, and modify n, we can do it.

#include <stdio.h>
int main()
{
    
    
const int n = 0;
printf("n = %d\n", n);
int*p = &n;
*p = 20;
printf("n = %d\n", n);
return 0;
}

insert image description here
We can see that one here has indeed been modified, but we still have to think about why n is modified by const? Just so that it cannot be modified, if p gets the address of n, it can modify n, which breaks the restriction of const, which is unreasonable, so it should let p get the address of n and not modify n

const modified pointer variable

#include <stdio.h>
//代码1
void test1()
{
    
    
int n = 10;
int m = 20;
int *p = &n;
*p = 20;
p = &m; 
}
void test2()
{
    
    
//代码2
int n = 10;
int m = 20;
const int* p = &n;
*p = 20;   x
p = &m; 
}
void test3()
{
    
    
int n = 10;
int m = 20;
int *const p = &n;
*p = 20; 
p = &m;    x
}
void test4()
{
    
    
int n = 10;
int m = 20;
int const * const p = &n;
*p = 20;   x
p = &m;    x
}
int main()
{
    
    
//测试⽆const修饰的情况
test1();
//测试const放在*的左边情况
test2();
//测试const放在*的右边情况
test3();
//测试*的左右两边都有const
test4();
return 0;
}

Conclusion: When const modifies a pointer variable
• If const is placed on the left of *, it modifies the content pointed to by the pointer, ensuring that the content pointed to by the pointer cannot be changed through the pointer. But the content of the pointer variable itself is mutable.
• If const is placed on the right side of *, it modifies the pointer variable itself, which ensures that the content of the pointer variable cannot be modified, but the content pointed to by the pointer can be changed through the pointer
.

Guess you like

Origin blog.csdn.net/2301_79178723/article/details/132446707