Latest update time: December 2021 twelve
Environment: vs2019, x86 compilation; 64 bit win10
Source code (including games) uploaded to
11, Pointer
11.1 what is the pointer
A pointer is actually an address. First, learn how memory addresses are numbered. Take a 32-bit machine as an example:
32 bits – 32 address lines – physical lines – power on – 1 / 0
Thus, the conversion from electrical signal to digital signal is completed, and the binary sequence composed of 1 and 0 is obtained:
00000000 00000000 00000000 00000000
......
11111111 11111111 11111111 11111111
A total of 2 ^ 32 addresses can be represented, that is, so many storage units.
One of the storage units occupies one byte.
int a = 10;//a 4 bytes need to be allocated in memory. printf("a Address of:%p\n", &a);//%p is specifically used to print addresses. int *pa = &a;//a is 4 bytes. Take the address as the address of the first byte. This address is low. // *Note that pa is a pointer variable, and int indicates that the object pointed to by pa is of type int. *pa = 20;// *For dereference, * pa is to find a through the address in pa. printf("Modify by pointer a Value of:%d\n", *pa); ++pa; printf("Self added address:%p\n",pa);//Self incrementing 4 bytes char ch = 'q'; char *pc = &ch; printf("ch Address of:%p\n", pc); printf("ch Next address for:%p\n", ++pc);//Self increment by one byte //The size of the pointer is the same: the pointer type is used to store the address. How much space the pointer needs depends on how much space the address needs to be stored printf("%d\n", sizeof(char*)); printf("%d\n", sizeof(short*)); printf("%d\n", sizeof(int*)); printf("%d\n", sizeof(long*)); printf("%d\n", sizeof(long long*)); printf("%d\n", sizeof(float*)); printf("%d\n", sizeof(double*));
11.2 pointer and pointer type
Meaning of pointer type:
1. Pointer type determines the permission of pointer dereference.
int a = 0x11223344; char *pc = &a; *pc = 0;//Since pc is a char pointer, only one byte can be accessed here. Change it to 0 int *pa = &a; *pa = 0;//Since pa is an int pointer, you can access four bytes here and change it to 0
Observe the changes in memory:
2. The pointer type determines how far the pointer can go in one step, that is, the step size.
int arr[10] = { 0 }; int* p = arr; char* pc = arr; printf("%p\n", p); printf("%p\n", p + 1);//int type, 4 bytes printf("%p\n", pc); printf("%p\n", pc + 1);//char type, 1 byte
int arr[10] = { 0 }; //int* p = arr;// Skip 4 bytes, that is, access in elements char* p = arr;//Byte by byte change for (int i = 0; i < 10; i++) { *(p + i) = 1; }
11.3 field pointer
Wild pointer: the position pointed to by the pointer is unknown (random, incorrect and without explicit permission)
Causes of wild pointer:
1. Pointer not initialized:
int* p;//p is a local variable. If the local variable is not initialized, the default is a random value *p = 20;//Illegal access to memory, because the space pointed to by p is random, and p here is a wild pointer
2. Pointer cross-border access:
int arr[10] = { 0 }; int* p = arr; for (int i = 0; i <= 10; i++) { *p = i; p++;//When i=10, it is out of bounds to access the elements in arr again }
3. Space release pointed by pointer:
int* test() { int a = 10; return &a;//After the function call, the space of a is released. If you operate this space again, it is actually illegal. }
int* p = test(); *p = 20;
How to avoid wild pointers:
1. To initialize the pointer:
int* p = NULL;//When you don't know what address p should initialize at present, it is directly initialized to NULL int a = 10; int* p = &a;//Clearly know the initialization value
2. Be careful to cross the border. C language itself will not check the cross-border behavior;
3. When the space pointed to by the pointer is released, set the pointer to null;
4. Check the validity of the pointer before use:
int* p = NULL; if(p != NULL) *p = 50;
11.4 pointer operation
1. Pointer + - integer:
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int* p = arr; int* pend = arr + 9;//Equivalent to arr[0] while (p <= pend)//Pointer relation operation { printf("%d\n", *p); p++; }
2. Pointer - pointer, provided that two pointers point to the same space:
Pointer + pointer meaningless
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; printf("%d", &arr[9] - &arr[0]);//Subtract the pointer from the pointer to get the number of elements between the pointers
Analog strlen():
int myStrlen(char* str) { char* start = str; while('\0' != str) { str++; } return str - start; }
size_t myStrlen(const char* str) { assert(str != NULL); //assert(str); size_t len = 0; while (*str++ != '\0') { len++; } return len; }
3. Pointer relation operation
The standard specifies that a pointer to an array element is allowed to be compared with a pointer to the last element of the array and the memory location behind it
However, it is not allowed to compare with a pointer to the memory location before the first element.
#define N_VALUES 5 float values[N_VALUES]; float *vp; for (vp = &values[0]; vp < &values[N_VALUES];) { *vp++ = 0; }
11.5 pointers and arrays
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int* p = arr;//Array name //[] is an operator 2 and arr are two operands printf("%d\n", 2[arr]); //arr[2] --> *(arr+2) <==> *(2+arr) --> 2[arr] printf("%d\n", arr[2]); printf("%d\n", p[2]); //p[2] --> *(p+2) <==> *(2+p) --> 2[p] //arr[2] <==> *(arr+2) <==> *(p+2) <==> *(2+p) <==> *(2+arr) //2[arr] <==> *(2+arr) //The [] operator is converted to the understand reference operator * () after being compiled, which is adjusted according to its operands //Pointers can also be used as array names, which is very flexible.
11.6 secondary pointer
int a = 10; int* pa = &a;//pa is the pointer variable, the first level pointer int* *ppa = &pa;//PA is also a variable, &pa takes the starting address of PA in memory, and ppa is a secondary pointer variable int** *pppa = &ppa;
11.7 pointer array
int arr[10];//Integer array - an array that holds the integer char ch[5];//Character array - an array of characters //Pointer array - an array of pointers int* parr[5];//An array that holds integer pointers char* pch[5];//An array of character pointers
11.8 const and pointer
//const modifies a variable. This variable is called a constant variable and cannot be modified, but it is still a variable in essence. const int num = 10; int n = 100; //num = 20;//err int* p = #//This allows you to change the value of num through the p pointer const int* p = #//const, if placed on the left of * and decorated with * p, means that the content pointed to by the pointer cannot be changed by the pointer, but the pointer variable itself can be modified *p = 20;//err, modified by const, cannot change the content pointed to by p p = &n;//*P cannot be modified, but p can still be modified
const int num = 10; int n = 100; num = 20;//err int* p = #//This allows you to change the value of num int* const p = #//const, if placed on the right of *, modifies the pointer variable p, indicating that the pointer variable cannot be changed, but the content pointed to by the pointer can be modified *p = 20;//*P can be modified, but p cannot be modified. p = &n;//err and p are directly modified by const and cannot be changed int const* const p = #//Neither the pointer itself nor the variable pointed to by the pointer can be changed
11.9 classification and application of pointer
11.9. 1 character pointer
char ch = 'q'; char* pc = &ch; char* ps = "hello world";//Essentially, the first character address of the string is stored in ps *ps = 'w';//err, constant cannot be changed char arr[] = "hello world"; printf("%c\n", *ps); printf("%s\n", ps); printf("%s\n", arr); char str1[] = "hello world."; char str2[] = "hello world."; const char* str3 = "hello world."; const char* str4 = "hello world.";//"hello world." Is a constant string. There is only one copy in memory. Two pointers point to the same space without creating a new space. if (str1 == str2) printf("str1 and str2 are same\n"); else printf("str1 and str2 are not same\n"); if (str3 == str4) printf("str3 and str4 are same\n"); else printf("str3 and str4 are not same\n");
11.9. 2 pointer array
Pointer array is an array of pointers
int *arr[3];//An array that holds integer pointers int a = 10; int b = 20; int c = 30; int* arr[3] = { &a,&b,&c }; for (int i = 0; i < 3; i++) printf("%d ", *(arr[i])); int a[5] = { 1,2,3,4,5 }; int b[] = { 2,3,4,5,6 }; int c[] = { 3,4,5,6,7 }; int* arr[3] = { a,b,c }; for (int i = 0; i < 3; i++) { for (int j = 0; j < 5; j++) printf("%d ", *(arr[i] + j)); //printf("%d ",arr[i][j]); printf("\n"); }
11.9. 3 array pointer
Array pointers are pointers to arrays
int arr[10] = { 1,2,3,4,5 }; //arr;// Is the address of the first element arr[0] int(*parr)[10] = &arr;//parr is an array pointer, where the address of the array is stored //If there are no parentheses, parr is combined with [] to become a pointer array. double* d[5]; double* (*pd)[5] = &d;//pd is an array pointer that points to an array with five elements. Each element of the array is double* int arr[10] = { 0 }; printf("%p\n", arr); printf("%p\n", &arr);//The values are the same but have different meanings int* p1 = arr; int(*p2)[10] = &arr;//The address of the array is taken out printf("%p\n", p1); printf("%p\n", p1 + 1);//p1 points to an integer. Add one to increase the length of an integer by 4 printf("%p\n", p2); printf("%p\n", p2 + 1);//p2 points to an array and increases the length of an array by 40
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int(*pa)[10] = &arr;//[] has higher priority than *. If it is not parenthesized, it indicates the pointer array for (int i = 0; i < 10; i++) printf("%d ", *(*pa + i));//Array pointers are cumbersome to use in one-dimensional arrays //*pa gets the address of the first element of arr, which is of type int, so + i will increase the integer length //If pa+i is used directly, the length of i arrays will be increased int arr[5] //arr is an integer array. int *parr1[10] //parr1 is an array of integer pointers. int (*parr2)[10] //parr2 is an array pointer, which points to an array. The array has 10 elements, and each element is of type int. int (*parr3[10])[5]; //parr3 is an array with 10 elements. Each element is an array pointer. Each pointer points to an array with 5 elements. Each element is of type int //After the array name [] is removed, all that remains is the type of each element of the array
void ptint2(int (*p)[5], int row, int col) { for(int i = 0;i < row;i++) { for(int j = 0;j < col;j++) printf("%d ",*(*(p + i) + j)); printf("\n"); } } int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} }; print2(arr, 3, 5);
11.9. 4 array parameter passing and pointer parameter passing
To judge whether the setting of the receiving parameter type meets the requirements, you can see two points:
(1) Look at the parameters passed
(2) Look what kind of this thing is
Meet the above two points
1. One dimensional array parameter transfer
int arr[10] = { 0 }; int* arr2[20] = { 0 }; test(arr);//ok test2(arr2);//ok //Receive arr void test(int arr[]) {}//ok void test(int arr[10]) {}//ok void test(int* arr) {}//ok //Receive arr2 void test(int* arr[20]) {}//ok void test(int** arr) {}//ok
2. Two dimensional array parameter transfer
int arr[3][5] = { 0 }; void test(int arr[3][5]) {}//ok void test(int arr[][5]) {}//ok void test(int arr[][]) {}//err void test(int* arr) {}//err, whose first element address receives a pointer array instead of an integer array void test(int* arr[5]) {}//err void test(int (*arr)[5]) {}//ok void test(int** arr) {}//err
3. Primary pointer transfer parameter
void test(char* p) {} void print(int* p, int sz) { for (int i = 0; i < sz; i++) printf("%d ", *(p + i)); } int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int* p = arr; int sz = sizeof(arr) / sizeof(arr[0]); print(p, sz); char ch = 'w'; char* p1 = &ch; test(&ch); test(p1); return 0; }
4. Secondary pointer transfer parameter
void test2(int** p2) { **p2 = 20; } int main() { int a = 10; int* pa = &a;//pa is the first level pointer int* *ppa = &pa;//ppa is a secondary pointer //Pass secondary pointer test2(ppa);//Pass secondary pointer test2(&pa);//Pass the address of the first level pointer variable int* arr[10] = { 0 }; test2(arr);//Pass first level pointer array printf("%d", a); return 0; }
11.9. 5 function pointer
A function pointer is a pointer to a function, that is, a pointer that stores the address of the function.
&The function name gets the address of the function.
Array name! =& Array name, function name = = & function name
void test3(char* str){} int main() { void (*pt)(char*) = &test3; printf("%p\n", &Add); printf("%p\n", Add); int (*pf)(int, int) = &Add;//pf is a function pointer variable int (*pf)(int, int) = Add;//Add <==> pf printf("%d\n",(****pf)(3, 5));//The function pointer dereference is used to call the function. In fact, * is meaningless. You can write a few one printf("%d\n",Add(3, 5)); // 2 printf("%d\n",pf(3, 5)); //These three lines are equivalent three 1 <==> 2 <==> 3 return 0; }
See 14.3 for exercises
11.9. 6 function pointer array
Function pointer array is an array of function pointers.
int (*pf1)(int, int) = Add; int (*pf2)(int, int) = Sub; int (*pfArr[2])(int, int) = { pf1,Sub };//pfArr is an array of function pointers. pfArr is first combined with square brackets, indicating that it is an array //After removing pfArr[2], the remaining int (*)(int,int) indicates that it is a function pointer, pointing to a function with two ints as parameters and an int as return value.
Design simple calculator
int main() { int (*pArr[4])(int , int) = { Add, Sub, Mul, Div }; int input = 0; do { menu(); scanf("%d",&input); int x = 0; int y = 0; if (0 <= (input - 1) && 3 >= (input - 1)) { scanf("%d %d", &x, &y); printf("%d", pArr[input - 1](x, y)); } else if(input == 0) printf("About to exit\n"); else printf("Please enter a valid option\n"); }while(input); return 0; }
11.9. 7 pointer to function pointer array
int(*p)(int, int);//Function pointer int(*pArr[10])(int, int);//Array of function pointers int(*(*pa)[10])(int, int);//pa is a pointer to an array of function pointers //First, * pa is the pointer. Remove (* pa) to see that it points to an array with 10 elements. Remove (* pa)[10] to see this number //Each element of a function is a pointer to a function. The function has even an int parameter and the return value is int
11.9. 8 callback function
1. A callback function is a function called through a function pointer. If you pass the pointer (address) of a function as a parameter to another number, when the pointer is used to call the function it points to, we say it is a callback function. The callback function is not called directly by the implementer of the function, but by another party when a specific event or condition occurs, which is used to respond to the event or condition.
Implement calculator using callback function:
int Cacl(int (*pfun)(int,int)) { int x = 0; int y = 0; printf("Please enter two operands:\n") scanf("%d %d",&x,&y); return pfun(x, y); } int main() { int input = 0; do { menu(); scanf("%d", &input); switch(input) { case 0: printf("About to exit\n"); break; case 1: printf("%d\n",Cacl(Add)); break; case 2: printf("%d\n",Cacl(Sub)); break; case 3: printf("%d\n",Cacl(Mul)); break; case 4: printf("%d\n",Cacl(Div)); break; default: printf("Please enter a valid option\n"); break; } }while(input); return 0; }
2.qsort() function
void qsort( void *base, size_t num, size_t width, int (*compare )(const void *elem1, const void *elem2 ) );
void* base: the address of the first element of the data to be sorted.
size_t num: the number and of elements in the data to be sorted.
size_t width: the size of each element in the data to be sorted, in bytes.
Int (* compare) (const void * elem1, const void * elem2): a function that can judge the size of any type of element. Elem1 > elem2 returns 1; Equal return 0; Otherwise, return - 1
Simulate qsort() to realize bubble sorting of any type of data. Take the structure type as an example:
struct Stu { char name[20]; int age; }; int cmp_struct(void* ele1,void* ele2) { //When calling bubbleAnyType(), the address of this function is the fourth parameter, which needs to be implemented by yourself //First cast the formal parameter to a pointer of the type of data to be compared, and then operate return strcmp(((struct Stu*)ele1) -> name,((struct Stu*)ele2) -> name);//Sort by name //return (struct Stu*)ele1.age- (struct Stu*)ele2.age;// Sort by age } void swap(char* ele1,char* ele2,int width) { //Exchange two elements in bytes, so set the formal parameter to char * for(int i = 0; i < width; i++) { char tmp = *ele1; *ele1 = *ele2; *ele2 = tmp; ele1++; ele2++; } } void bubbleAnyType(void* base,int size,int width,int (*compare)(const void* e1, const void* e2)) { for(int i = 0; i < size - 1; i++) { for(int j = 0; j < size -1 -i; j++) { //Operates in bytes, because bytes are the smallest storage unit of each type //The data to be operated is found by the first address + the size of the data type if( compare( (char*)base + j * width, (char*)base + (j + 1) * width) > 0 ) {//Exchange element swap( (char*)base + j * width, (char*)base + (j + 1) * width, width) ); } } } } int main() { struct Stu s[3] = { {"zhangsan",30},{"lisi",35},{"wangwu",25} }; int sz = sizeof(s) / sizeof(s[0]); bubbleAnyType(s,sz,sizeof(s[0]),cmp_struct); return 0; }
Before sorting:
After sorting (take sorting by name as an example):
11.9. Analysis of 9 pointer and array interview questions
Sizeof (array name) the array list is placed in parentheses, and the & array name is the size of the entire array and the address to get the entire array, respectively. In addition, all array names are the address of the first element.
int a[] = { 1,2,3,4 }; printf("%d\n", sizeof(a)); // 16 printf("%d\n", sizeof(a + 0)); // four a+0 is the address of the first element printf("%d\n", sizeof(*a)); // four A is the address of 1, * a means 1 printf("%d\n", sizeof(a + 1)); // four a+1 is the address of the second element printf("%d\n", sizeof(a[1])); // 4 printf("%d\n", sizeof(&a)); // 4 printf("%d\n", sizeof(*&a)); // sixteen *& Actually, they offset each other printf("%d\n", sizeof(&a + 1)); // four The addresses of the space behind the array are all addresses * (& A + 1) can access the size of an array printf("%d\n", sizeof(&a[0])); // four Wherever it points, it's the address printf("%d\n", sizeof(&a[0] + 1)); // four Wherever it points, it's the address