pointer four
array of pointers
What is an array of pointers
First review the previous knowledge about arrays:
The so-called array is used to store the collection of the same data type
Combined with the previous knowledge about pointers: the essence of pointers is also a data type
So when the data type of the members stored in the array is a pointer, the array can be called a pointer array (essentially an array)
the code
#include "stdafx.h"
void function(){
int** arr[5]={
(int**)1,(int**)2,(int**)3,(int**)4,(int**)5};
}
int main(int argc, char* argv[])
{
function();
return 0;
}
disassembled code
9: int** arr[5]={
(int**)1,(int**)2,(int**)3,(int**)4,(int**)5};
00401038 mov dword ptr [ebp-14h],1
0040103F mov dword ptr [ebp-10h],2
00401046 mov dword ptr [ebp-0Ch],3
0040104D mov dword ptr [ebp-8],4
00401054 mov dword ptr [ebp-4],5
small summary
- It can be seen that there is nothing special about the pointer array, except that the data type of the stored array members is a pointer
- The assignment of an array of pointers is also no different from the previous assignment of pointers
structure pointer
What is a structure pointer
The so-called structure pointer is to add several * after the structure to make it a pointer type
the code
#include "stdafx.h"
#include <typeinfo>
struct S1{
int a;
};
void function(){
S1* s1=(S1*)0x12345678;
printf("%x\n",s1);
}
int main(int argc, char* argv[])
{
function();
return 0;
}
operation result
Result analysis
It can be seen that the use of structure pointers here seems to be no different from ordinary pointers, but at this time you will find that there are no members inside the structure yet.
So the actual use of the structure pointer is not like this, let's look at a wrong example
error code
void function(){
S1* s1=(S1*)0x12345678;
int a=s1->a;
}
Just add a statement to read the members of the structure on the basis of the above code, and check the running results
operation result
The result of the operation went wrong as expected, and the cause of the error began to be analyzed
disassembled code
14: S1* s1=(S1*)0x12345678;
00401038 mov dword ptr [ebp-4],12345678h
15: int a=s1->a;
0040103F mov eax,dword ptr [ebp-4]
00401042 mov ecx,dword ptr [eax]
00401044 mov dword ptr [ebp-8],ecx
Disassembly analysis
0. The state of s1 and s1->a before execution
s1:
s1->a:
1. Assign a value to the structure pointer s1
14: S1* s1=(S1*)0x12345678;
00401038 mov dword ptr [ebp-4],12345678h
Now look at s1->a:
It can be found that the assignment operation to s1 does not change the value of s1->a, but changes the address of s1->a
In fact, it can be seen from the state of s1 and s1->a before execution that the content stored in s1 is not directly storing the content of the structure member, but storing the address pointing to the structure member
So here, only the address of the member is changed for the previous assignment operation of s1, but the value of the member is not changed
And at the beginning, the structure members were not assigned the corresponding memory address
2. Visit s1->a
15: int a=s1->a;
0040103F mov eax,dword ptr [ebp-4]
00401042 mov ecx,dword ptr [eax]
00401044 mov dword ptr [ebp-8],ecx
The reason for the error is obvious at this time. The previous assignment operation to s1 modified the address of s1->a, making it point to an inaccessible address, resulting in an error
correct code
We already know that the reason for the error is that the access to an inaccessible address caused an error, and the structure members were not assigned the corresponding memory address at the beginning
So you just need to manually allocate the memory address for the structure members, here we will use the malloc function to allocate the memory address
malloc function
void *malloc(size_t size)
Parameters: size, the size of the memory block, in bytes
Return value: Returns a pointer to the memory of the allocated size. Returns NULL if the request fails
Related header files: malloc.h, alloc.h, stdlib.h
After a general understanding of the malloc function, let's look at the code:
#include "stdafx.h"
#include <malloc.h> //这里使用了malloc.h
struct S1{
int a;
int b;
int c;
};
void function(){
S1* s1=(S1*) malloc(sizeof(S1)); //申请一块空间大小正好为S1大小的内存
s1->a=610;
s1->b=666;
s1->c=52;
printf("%d\n",s1->a);
printf("%d\n",s1->b);
printf("%d\n",s1->c);
}
int main(int argc, char* argv[])
{
function();
return 0;
}
operation result
You can see that the members of the structure can be rewritten and accessed normally
disassembled code
15: S1* s1=(S1*) malloc(sizeof(S1));
0040D778 push 0Ch
0040D77A call malloc (00401150)
0040D77F add esp,4
0040D782 mov dword ptr [ebp-4],eax
16: s1->a=610;
0040D785 mov eax,dword ptr [ebp-4]
0040D788 mov dword ptr [eax],262h
17: s1->b=666;
0040D78E mov ecx,dword ptr [ebp-4]
0040D791 mov dword ptr [ecx+4],29Ah
18: s1->c=52;
0040D798 mov edx,dword ptr [ebp-4]
0040D79B mov dword ptr [edx+8],34h
Disassembly analysis
1. First look at this malloc function
15: S1* s1=(S1*) malloc(sizeof(S1));
0040D778 push 0Ch
0040D77A call malloc (00401150)
0040D77F add esp,4
0040D782 mov dword ptr [ebp-4],eax
- The parameter 0C is pressed, corresponding to 12 in decimal, which is the size of S1
- call malloc function
- off-stack balance
- Assign the return value eax to S1
Look at the content of the return value eax:
You can see that eax corresponds to the members in the structure
eax=the first address of the structure member, the structure members inside are stored continuously
2. Assignment, assign 610 corresponding to hexadecimal 262 to [eax], corresponding to the previous 003807B8
16: s1->a=610;
0040D785 mov eax,dword ptr [ebp-4]
0040D788 mov dword ptr [eax],262h
After execution:
3. Assignment, assign 666 corresponding to hexadecimal 29A to [ecx+4], corresponding to the previous 003807BC
17: s1->b=666;
0040D78E mov ecx,dword ptr [ebp-4]
0040D791 mov dword ptr [ecx+4],29Ah
After execution:
4. Assignment, assign 52 corresponding to hexadecimal 34 to [edx+4], corresponding to the previous 003807C0
18: s1->c=52;
0040D798 mov edx,dword ptr [ebp-4]
0040D79B mov dword ptr [edx+8],34h
After execution:
small summary
-
Struct pointers are not really that different from normal pointers
-
When operating on structure members, it needs to be initialized first (allocate memory address for each structure member)
-
The structure pointer does not directly store the structure members, but stores the address pointing to the structure members, which stores all the structure members
array pointer
I learned the pointer array before, and now I have an array pointer, and the transition is made with the structure pointer in the middle to avoid confusion
What is an array pointer
The so-called array pointer is a pointer to an array (essentially a pointer)
Since it is a pointer, it naturally satisfies all the characteristics of the previous pointer: pointer assignment, pointer data width, pointer addition and subtraction, pointer type subtraction, pointer comparison
Declaration of array pointer
int (*px)[2];
As stated above, the array pointer variable is px, and its type is: int(*)[2]; the array pointed to by the array pointer is int[2]
The difference between an array pointer and a pointer to an array
the code
#include "stdafx.h"
void function(){
int arr[6]={
1,2,3,4,5,6};
//声明一个数组指针,该指针指向数组为:int[2]
int (*px)[2];
//给数组指针赋值,使该数组指针指向arr数组的首地址
px=(int (*)[2]) &arr[0];
//用一个临时变量parr2 存储数组指针
int (*parr2)[2]=px;
//*px为数组的首地址,也就是arr,这里就相当于int* arr2=arr;此时的arr2就是指向数组的指针
int* arr2=*px;
//初始化变量,准备循环
int i;
//循环遍历数组
for(i=0;i<6;i++){
printf("%x\t%d\n",arr2+i,arr2[i]);
}
printf("\n");
int a=(int) (parr2+1);
int b=(int) (arr2+1);
printf("%x\t%x\n",a,b);
}
int main(int argc, char* argv[])
{
function();
return 0;
}
operation result
First you can see the normal traversal of the array
Then output the results of parr2+1 and arr2+1 respectively, note that the results here are different
disassembled code
8: int arr[6]={
1,2,3,4,5,6};
00401038 mov dword ptr [ebp-18h],1
0040103F mov dword ptr [ebp-14h],2
00401046 mov dword ptr [ebp-10h],3
0040104D mov dword ptr [ebp-0Ch],4
00401054 mov dword ptr [ebp-8],5
0040105B mov dword ptr [ebp-4],6
9:
10: int (*px)[2];
11:
12: px=(int (*)[2]) &arr[0];
00401062 lea eax,[ebp-18h]
00401065 mov dword ptr [ebp-1Ch],eax
13:
14: int (*parr2)[2]=px;
00401068 mov ecx,dword ptr [ebp-1Ch]
0040106B mov dword ptr [ebp-20h],ecx
15: int* arr2=*px;
0040106E mov edx,dword ptr [ebp-1Ch]
00401071 mov dword ptr [ebp-24h],edx
16:
17: int i;
18:
19: for(i=0;i<6;i++){
00401074 mov dword ptr [ebp-28h],0
0040107B jmp function+66h (00401086)
0040107D mov eax,dword ptr [ebp-28h]
00401080 add eax,1
00401083 mov dword ptr [ebp-28h],eax
00401086 cmp dword ptr [ebp-28h],6
0040108A jge function+8Fh (004010af)
20: printf("%x\t%d\n",arr2+i,arr2[i]);
0040108C mov ecx,dword ptr [ebp-28h]
0040108F mov edx,dword ptr [ebp-24h]
00401092 mov eax,dword ptr [edx+ecx*4]
00401095 push eax
00401096 mov ecx,dword ptr [ebp-28h]
00401099 mov edx,dword ptr [ebp-24h]
0040109C lea eax,[edx+ecx*4]
0040109F push eax
004010A0 push offset string "%x\t%d\n" (00422024)
004010A5 call printf (00401160)
004010AA add esp,0Ch
21: }
004010AD jmp function+5Dh (0040107d)
22: printf("\n");
004010AF push offset string "\n" (00422020)
004010B4 call printf (00401160)
004010B9 add esp,4
23:
24: int a=(int) (parr2+1);
004010BC mov ecx,dword ptr [ebp-20h]
004010BF add ecx,8
004010C2 mov dword ptr [ebp-2Ch],ecx
25: int b=(int) (arr2+1);
004010C5 mov edx,dword ptr [ebp-24h]
004010C8 add edx,4
004010CB mov dword ptr [ebp-30h],edx
26: printf("%x\t%x\n",a,b);
004010CE mov eax,dword ptr [ebp-30h]
004010D1 push eax
004010D2 mov ecx,dword ptr [ebp-2Ch]
004010D5 push ecx
004010D6 push offset string "%x\t%x\n" (00422fa4)
004010DB call printf (00401160)
004010E0 add esp,0Ch
Disassembly analysis
1. Array initialization
8: int arr[6]={
1,2,3,4,5,6};
00401038 mov dword ptr [ebp-18h],1
0040103F mov dword ptr [ebp-14h],2
00401046 mov dword ptr [ebp-10h],3
0040104D mov dword ptr [ebp-0Ch],4
00401054 mov dword ptr [ebp-8],5
0040105B mov dword ptr [ebp-4],6
After the array is initialized, the corresponding address and content are:
2. Assignment of array pointer
12: px=(int (*)[2]) &arr[0];
00401062 lea eax,[ebp-18h]
00401065 mov dword ptr [ebp-1Ch],eax
Directly pass the first address of the arr array, which is 0012FF14, to eax
Then assign eax to the value pointer px
After value pointer assignment:
You can see that the content stored in the value pointer is 0012FF14, which is the address of arr
3. Assign the value pointer px to another array pointer parr2
14: int (*parr2)[2]=px;
00401068 mov ecx,dword ptr [ebp-1Ch]
0040106B mov dword ptr [ebp-20h],ecx
After assignment:
You can see that the content stored in parr2 = the content stored in px = 0012FF14 = the first address of arr
4. Assign the first address of the array to arr2, that is, arr2=arr
14: int* arr2=*px;
0040D82E mov edx,dword ptr [ebp-1Ch]
0040D831 mov dword ptr [ebp-24h],edx
It should be noted here that it is assigned as before [ebp-1Ch]
That is to say, the assignment is *px, but the assignment is the same as px
It can also be concluded that px=px, so why are px and px the same**?
First of all, it must be clear whether it is px or *px, they are all pointers, one is an array pointer, and the other is an ordinary pointer
The addresses they point to are the same, both point to the first address 0012FF14 of arr
The essence of the difference between px and *px is that its data types are two different pointer structures
When pointers are added and subtracted, the basic unit of addition and subtraction is the data width of the pointer minus one *
- The data type of px is: int ( )[2], after removing one, it becomes int [2], and the data width is the data width of int × the number of members of the array=4*2=8
- The data type of px is: int , remove one * and become int, data width=4
After assignment:
5. Loop through the array
It is an ordinary circular array of pointers, which has been introduced in detail in the previous article, so I won’t go into details here
6. The second cycle
24: int a=(int) (parr2+1);
004010BC mov ecx,dword ptr [ebp-20h]
004010BF add ecx,8
004010C2 mov dword ptr [ebp-2Ch],ecx
25: int b=(int) (arr2+1);
004010C5 mov edx,dword ptr [ebp-24h]
004010C8 add edx,4
004010CB mov dword ptr [ebp-30h],edx
It can be known from the front that *px=px, parr2=arr2, so [ebp-20h]=[ebp-24h] here:
The difference here is that one adds 8 and the other adds 4, which is consistent with the unit of pointer addition and subtraction analyzed earlier, so different results are produced
small summary
- Add * before an array pointer to get a pointer to the array, such as int arr2=px in the above example;
- The content stored in the value pointer and the pointer to the array is the first address of the array, such as px=*px=arr=0012FF14 in the above example
- The main difference between an array pointer and a pointer to an array is the unit of operation. The former is the data type width × the number of array members, and the latter is the data type width
Application of array pointer
You can use the different units when adding and subtracting array pointers to traverse the fixed interval members of the array
The following example starts from the second member of the array and extracts the array members whose interval is 3
the code
#include "stdafx.h"
void function(){
int arr[15]={
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
int (*px)[3];
//从数组的第二个成员开始
px=(int (*)[3]) &arr[1];
int i=0;
for(i=0;i<15/3;i++){
printf("%x\t%d\n",px+i,**(px+i));
//注意这里取了两次*,第一次获得的是指向数组成员的指针,第二个获得的才是数组成员
}
}
int main(int argc, char* argv[])
{
function();
return 0;
}
operation result