Lesson 6: Elementary pointer
catalogue
1.4 pointer operation and pointer operation
1.5 pointer and array and variable length array (VLA)
1.1 what is the pointer?
A pointer is an address. In colloquial language, a pointer usually refers to a pointer constant.
Two key points of pointer understanding:
1. Pointer is the number of the smallest unit in memory, that is, the address
2. The pointer in spoken English usually refers to the pointer variable, which is used to store the memory address
It can be understood as:
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)
② How to address?
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); Then the address generated by the 32 address lines will be:
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 the 64 bit machine is given 64 address lines, it can calculate how much space it can address by itself.
Here we understand:
On a 32-bit machine, the address is a binary sequence of 32 zeros or 1s, so the address has to be stored in 4 bytes, so
The size of a pointer variable should be 4 bytes.
If there are 64 address lines on a 64 bit machine, the size of a pointer variable is 8 bytes before it can be stored in one place
Address.
So we can conclude:
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.
1.2 pointer and pointer type
As we all know, variables have different types, such as integer, floating point, etc. Does the pointer have a type?
To be exact: Yes.
char *pc = NULL; int *pi = NULL; short *ps = NULL; long *pl = NULL; float *pf = NULL; double *pd = NULL; //Here you can see that the pointer is defined as type +* Actually: char* Type pointer is used to store char Address of the type variable. short* Type pointer is used to store short Address of the type variable. int* Type pointer is used to store int Address of the type variable.
Dereference of pointer:
give an example:
//one #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; } //two #include<stdio.h> int main() { int a=0x11223344; int*pa=&a; *pa=0; return 0; }
Summary: the type of pointer determines how much permission you have to dereference the pointer (can operate several bytes)
For example, the dereference of char * pointer can only access one byte, while the dereference of int * pointer can access four bytes.
1.3. Wild pointer
Concept: a wild pointer means that the position pointed to by the pointer is unknown (random, incorrect, and without explicit restrictions)
Reasons for the formation of field pointer:
1. Pointer not initialized
2. Pointer cross-border access
3. The space pointed to by the pointer is released
give an example:
//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 out of range #include <stdio.h> int main() { int arr[10] = {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. The space pointed to by the pointer is released void test() { int i = 0; int *p = (int *)malloc(10*sizeof(int)); if(NULL == p) { exit(EXIT_FAILURE); } for(i=0; i<=10; i++) { *(p+i) = i;//Cross border access when i is 10 } free(p); } free(p);
How to avoid wild pointers:
1. Pointer initialization
2. Be careful that the pointer is out of range
3. The pointer points to the space release 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; }
1.4 pointer operation and pointer operation
Pointer + - integer:
#define N_VALUES 5 float values[N_VALUES]; float *vp; //Pointer + - integer; Relational operation of pointer for (vp = &values[0]; vp < &values[N_VALUES];) { *vp++ = 0; }
Pointer - Pointer:
int my_strlen(char *s) { char *p = s; while(*p != '\0' ) p++; return p-s; }
Pointer operation: C provides some basic pointer operations. There are roughly 8 different operations (the key point of the pointer is here, which is very important)
#include<stdio.h> int main() { int urn[5]={100,200,300,400,500}; int* ptr1,*ptr2,*ptr3; prt1=urn;//Assign an address to a pointer ptr2=&urn[2];//Assign an address to a pointer ①printf("ptr1=%p,*ptr2=%d,&ptr1=%p\n",ptr1,*ptr1,&ptr1); //Pointer addition ptr3=ptr1+4; ②printf("ptr1+4=%p,*(ptr1+4)=%d\n",ptr1+4,*(ptr1+4)); //Increment pointer ptr1++; ③printf("ptr1=%p,*ptr1=%d,&ptr1=%p\n",ptr1,*ptr1,&ptr1); //Decrement pointer ptr2--; ④printf("ptr2=%p,*ptr2=%d,&ptr2=%p\n",ptr2,*ptr2,&ptr2); //Return to initial value --ptr1; ++ptr2; ⑤printf("ptr1=%p,ptr2=%p\n",ptr1,ptr2); //Subtract one pointer from the other ⑥printf("ptr1=%p,ptr2=%p,ptr2-ptr1=%td\n",ptr2,ptr1,ptr2-ptr1); //Subtract an integer from a pointer ⑦printf("ptr3=%p,ptr3-2=%p\n",ptr3,ptr3-2); return 0; } //Output results (individuals may be different) ①ptr1=0x7fff5fbff8d0,*ptr1=100,&ptr1=0x7fff5fbff8c8 ②prt1+4=0x7fff5fbff8e0,*(ptr1+4)=500 ③ptr1=0x7fff5fbff8d4,*ptr1=200,&ptr1=0x7fff5fbff8c8 ④ptr2=0x7fff5fbff8d4,*ptr2=200,&ptr2=0x7fff5fbff8c0 ⑤ptr1=0x7fff5fbff8d0,*ptr2=0x7fff5fbff8d8 ⑥ptr2=0x7fff5fbff8d8,*ptr1=0x7fff5fbff8d0,ptr2-ptr1=2 ⑦ptr3=0x7fff5fbff8e0,ptr3-2=0x7fff5fbff8d8 //Please combine the compilation results with the following words to understand the basic pointer operation //It may be difficult for you to understand the code here, but I will explain it carefully in the high-level pointer
① Assignment: the address can be assigned to the pointer. For example, use array name, variable name with address operator (&) and another pointer to assign value. In this example, the first address of the urn array is assigned to ptr1, and the number of this address is exactly 0x7fff5fbff8d0. The variable ptr2 obtains the address of the third element of the array urn (urn[2]).
② Dereference: * operator gives a pointer to the value stored on the address. Therefore, the initial value of * ptr1 is 100. The value is stored at the address 0x7fff5fbff8d0. Remember, Never dereference uninitialized pointers (dereference of an uninitialized pointer may lead to no error, erasure of data or code, or program crash. Remember that when creating a pointer, the system only allocates the memory for storing the pointer itself, not the memory for storing data. Therefore, before using the pointer, it must be initialized with the allocated address.)
③ Value: the same as all variables. Pointer variables also have their own addresses and values. For pointers, the & operator gives the address of the pointer itself. In this ex amp le, ptr1 is stored at the address with the memory number 0x7fff5fbff8c8. The content of the storage unit is 0x7fff5fbff8d0, that is, the address of urn. So & ptr1 is a pointer to ptr1, and ptr1 is a pointer to urn[0].
④ Add pointer and integer: you can use the + operator to add pointer and integer, or integer and pointer. In either case, the integer will be multiplied by the size of the type pointed to by the pointer (in bytes), and then add the result to the initial address. Therefore, ptr1+4 is equivalent to & urn [4]. If the result of the addition exceeds the array range of the initial pointer, the calculation result is undefined. C guarantees that the pointer is valid unless it just exceeds the first position at the end of the array.
⑤ Increment pointer: incrementing a pointer to an array element moves the pointer to the next element of the array. Therefore, ptr1 + + is equivalent to adding 4 to the value of ptr1 (int is 4 bytes in our system), and ptr1 points to urn[1]. Now the value of ptr1 is 0x7fff5fbff8d4 (the address of the next element of the array), and the value of * ptr is 200 (that is, the value of urn[1]). Note that the address of ptr1 itself is still 0x7fff5fbff8c8. After all, the variable will not move because the value changes.
⑥ Pointer minus an integer: you can use the - operator to subtract an integer from a pointer. The pointer must be the first operand, and the integer must be the second operand. This integer is multiplied by the size (in bytes) of the type pointed to by the pointer, and then the product is subtracted from the initial address. Therefore, ptr3-2 is equivalent to & urnp [2], because when ptr3 points to urn[4], if the result of subtraction exceeds the range of the array pointed to by the initial pointer, the calculation result is undefined. C guarantees that the pointer is valid unless it just exceeds the first position at the end of the array.
⑦ Decrement pointer: of course, in addition to incrementing the pointer, you can also decrement the pointer. In this case, decrement ptr2 to point to the second element of the array instead of the first element. Both increment and decrement operators for prefixes or suffixes can be used. Note that before resetting ptr1 and ptr2, they both point to the same element urn[1].
⑧ Pointer difference: the difference between two pointers can be calculated. Usually, the two pointers of the difference point to different elements of the same array, and the distance between the two elements is calculated. The unit of difference is the same as that of array type. For example, in the output of the program, ptr2-ptr1=2, which means that the two elements pointed to by two pointers are separated by 2 ints, not 2 bytes. As long as these two pointers point to the same array (or one pointer points to the first address after the array), C can ensure that the operation is effective. If the pointers of two different arrays are subtracted, a value may be obtained, or an error may occur in the operation.
⑨ Compare: use relational operators to compare the values of two pointers, provided that both pointers point to objects of the same type.
//Read it several times. It's troublesome not to understand it here. The essence of C/C + + is to use pointers and memory
1.5 pointer and array and variable length array (VLA)
We won't talk about the basic concepts. We'll talk about them in C language and arrays. We pay attention to understanding here.
Let's start with an example:
#include <stdio.h> int main() { int arr[10] = {1,2,3,4,5,6,7,8,9,0}; printf("%p\n", arr); printf("%p\n", &arr[0]); return 0; }
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 we can change the above code to:
#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[0]); for(i=0; i<sz; i++) { printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p+i); } return 0; }
Access the array directly through the pointer VLA:
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[0]); int i = 0; for (i = 0; i<sz; i++) { printf("%d ", *(p + i)); } return 0; }
Become array (VLA):
Readers may not understand it in learning functions that deal with binary arrays. Why only take the number of rows of the array as the formal parameter of the function, while the number of columns is built into the function body. For example:
//function #define COLS 4 int sum2d(int ar[][COLS],int rows) { int r; int c; int tot=0; for(r=0;r<rows;r++) for(c=0;c<COLS;c++) tot+=ar[r][c]; return tot; } /*Suppose the following array is declared: int array1[5][4]; int array2[100][4]; int array3[2][4]; You can use the sum2d() function to calculate the sum of the elements of these arrays: tot=sum2d(array1,5);//5X4 Sum of elements of array tot=sum2d(array2,100);//100X4 Sum of elements of array tot=sum2d(array3,2);//2X4 Sum of elements of array */
The sum2d() function can handle these arrays because the number of columns in these arrays is fixed to 4, and the number of rows is passed to the formal parameter rows, which is a variable. However, if you want to calculate a 6x5 array (that is, 6 rows and 5 columns), you can't use this function. You must recreate a function with CLOS of 5. Because C stipulates that the dimension of the array must be constant, and the variable CLOS cannot be used.
In view of this, C99 adds variable length array VLA, which allows variables to represent the dimensions of the array.
For example:
int a=4; int b=6; double asles[a][b];//A variable length array
As mentioned earlier, variable length arrays have some limitations. Variable length arrays must be automatic storage categories, which means that static or extern al storage category specifiers cannot be used, whether declared in a function or as a function parameter.
Note: variable length arrays cannot be resized. The variable here refers to the size that cannot be changed to create the array. Because variable length array is a new feature of C language, there are few compilers that fully support this feature.
1.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
**ppa first finds pa through * ppa, and then dereferences PA: * PA, then a is found
Multi level pointer:
1.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.
What about pointer arrays?
int* arr3[5];// What is it?
arr3 is an array with five elements, each of which is an integer pointer.
1.8 pointer compatibility
Assignments between pointers are stricter than those between array types. For example:
//statement int* pt; int (*pa)[3]; int ar1[2][3]; int ar2[3][2]; int** p2; //assignment pt=&ar1[0][0];//Are pointers to int pt=ar1[0];//Are pointers to int pt=ar1;//Invalid assignment pa=ar1;//Are pointers to an array containing three int type elements pa=ar2;//Invalid assignment p2=&pt;//Are pointers to int * *p2=ar2[0];//Are pointers to int p2=ar2;//Invalid assignment
This content is beyond the entry level. It will be explained when we deeply understand the C language. It will be left here to provide you with some understanding.