1. Character pointer
What is the output of the following code?
Answer: h hello the hello the
Analysis: character pointer variables can store strings.
The first h is because the * ps pointer points to the first character h of hello, so h is output; The last two array names, arr and ps, are the first character address of hello, so they both output hello.
int main() { //In essence, the first character address of the string "hello the" is stored in ps char* ps = "hello the"; char arr[] = "hello the"; printf("%c\n", *ps);//h printf("%s\n", ps); printf("%s\n", arr); return 0; }
What is the output of the following code?
Answer: 1 and 2 are different, 3 and 4 are the same
Analysis: the array name represents the address of the first element of the array. str1 and str2 are two different arrays, which need to open up two different memory spaces respectively. str1 and str2 point to the first addresses of two hello, so they are different;
"hello bit" is a constant string, and the pointer variable cannot be changed by dereference. For memory, since "hello bit" is a constant, you only need to open up a memory space for it, and the address number is determined. Therefore, 3 and 4 point to the same address, that is, the first element address of the constant string "hello bit"
int main() { char str1[] = "hello bit."; char str2[] = "hello bit."; const char* str3 = "hello bit."; const char* str4 = "hello bit."; 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"); return 0; }
2. Pointer array
Definition: pointer array is an array for storing pointers. In essence, it is an array in which pointers are stored
In the following code: three integer pointers int * can be stored in the ARR array, and a, B and C are the addresses of the first elements of the three integer arrays respectively, in which arr [0], arr [1] and arr [2]
int main() { //Pointer array //Array - the array contains pointers (addresses) //int* arr[3];// An array that holds integer pointers int a[] = { 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 }; int i = 0; for (i = 0; i < 3; i++) { int j = 0; for (j = 0; j < 5; j++) { printf("%d ", *(arr[i]+j)); printf("%d ", arr[i][j]); } printf("\n"); } return 0; }
3. Array pointer
Definition: it is a pointer that should be able to point to the array. The array pointer should store the address of the array
Next, it will be different from the previous pointer array:
- int *p1[10];—— Pointer array
The priority of [] is higher than that of *, so () must be added to ensure that p is combined with * first
- int (*p2)[10];
P is first combined with * to indicate that P is a pointer variable, and then points to an array of 10 integers. So p is a pointer to an array, called an array pointer
Think about the form of array pointers
First, the pointer (*) → how many elements are there in the array pointed to by the pointer ([]) → what type of array is pointed to
int main() { int arr[10] = { 1,2,3,4,5 }; //Arr -- is the address of arr[0] int(*parr)[10] = &arr;//The array address is taken out //parr is an array pointer -- where the address of the array is stored double* p[10]; double* (*pd)[10] = &p; return 0; }
What is the connotation
Observe the following codes:
int main() { int arr[10] = {1,2,3,4,5,6,7,8,9,10 }; int(*pa)[10] = &arr;//Array pointer int i = 0; for (i = 0; i < 10; i++) { printf("%d\n", (*pa + i)); printf("%d\n", *(*pa + i)); } return 0; }
After running, let's take a look:
- *Note that pa is a pointer variable. pa should store the address of an array, and pa+1 will skip the address size of an array;
- *pa is the address of the first element, that is, the name of the arr array, * pa+1, that is, the address advances by 4 bytes (matching the int pointer type), reflecting the address of each element in the array
- Dereference operation: * (* pa) get the elements in the arr array
Practical application: print each element in a two-dimensional array
p is the array pointer, pointing to an array, * p saves the address of the first element (arr array name), [5] indicates that there are 5 elements in the array, and int indicates the array element type
The first element of the two-dimensional array is the first row of the two-dimensional array. The arr passed here is actually equivalent to the address of the first row, which is the address of the one-dimensional array
- (p+i) get the address of each row array
- *(p+i) get the address of the first element of each row array
- (* (p+i) + j) get the address of each element in each row array
- *(* (p+i) + j) get the element array contents in each row array
void print(int(*p)[5],int r,int c) { int i = 0; int j = 0; for (i = 0; i < r; i++) { for (j = 0; j < c; j++) { printf("%p ", (p + i) ); printf("%p ", *(p + i) ); printf("%p ", *(p + i)+j); printf("%d ", *((*(p+i) + j))); } printf("\n"); } } int main() { int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} }; print(arr,3,5); return 0; }
Verify the following results:
Judge the meaning of the following code
int arr[5];—— An array with five integer elements
int *parr1[10];—— An array of 10 integer pointers
int (*parr2)[10];—— The pointer can point to an array, 10 elements in an array, and each element type is int
int (*parr3[10])[5];—— Parr3 is an array that stores array pointers. The array can store 10 pointers. Each array pointer can point to an array with 5 elements. Each element is of type int
4. Array parameters and pointer parameters
Be sure to analyze clearly what is passed by the argument. If it is an address, whose address is it, and in what form should the formal parameter be received.
One dimensional array parameter transfer
Judge which parameters can be transferred and which cannot?
#include <stdio.h> void test(int arr[])//ok? {} void test(int arr[10])//ok? {} void test(int *arr)//ok? {} void test2(int *arr[20])//ok? {} void test2(int **arr)//ok? {} int main() { int arr[10] = {0} int *arr2[20] = {0}; test(arr); test2(arr2); }
The form of formal parameters here is correct.
- test()
1,2: receive as array √ correct
3: arr is the array name. At this time, the first element address is passed. It is correct to receive √ with int *
- test2() -- int* arr2[20] is a pointer array that stores pointers of type int *
4: Pass the pointer array, and the corresponding type receives √ correctly
5: arr2 is the address of the first element of the pointer array. The first element is a pointer of type int *, which becomes a secondary pointer √ correct
Two dimensional array parameter transfer
Judge which parameters can be transferred and which cannot?
void test(int arr[3][5])//ok? {} void test(int arr[][])//ok? {} void test(int arr[][5])//ok? void test(int *arr)//ok? {} void test(int* arr[5])//ok? {} void test(int (*arr)[5])//ok? {} void test(int **arr)//ok? {} int main() { int arr[3][5] = {0}; test(arr); }
- arr is a two-dimensional array. A two-dimensional array may not know the number of rows, but it must know the number of columns, that is, how many elements there are in a row
So 1 √ correct, 2 × Error, 3 √ correct
- The address of the first element of arr represents the address of the first line element. It is understood as an array pointer and should point to an array
1: It is understood that arr is an array pointer (it can point to the array in the first row, and the first row is an array with 5 integers). The corresponding formal parameter is malformed, but it is only a first-order pointer × error
2: The parameter received should be a pointer array × error
3: arr is an array pointer. There are 5 int type elements in the array pointed to √ correct
4: What passed is not a secondary pointer × error
Primary pointer transfer parameter
The form of function parameter is that when receiving the first level pointer, the actual parameter passes the address
Secondary pointer transfer parameter
The function parameter form is that when receiving the secondary pointer, the argument can pass the secondary pointer, that is, the address of the primary pointer, or the array name storing the primary pointer
void test(char **p) { } int main() { char c = 'b'; char*pc = &c; char**ppc = &pc; char* arr[10]; test(&pc); test(ppc); test(arr);//Ok? return 0; }
Analysis:
pc is the primary pointer, ppc is the secondary pointer, and test(ppc) passes the secondary pointer ppc as a parameter;
Test (& PC) pass the address of the first level pointer variable;
test(arr) passes the array storing the first level pointer and the name of the arr array. The array name represents the address of the first element. Each element of the arr array is of type char * and the address of char * is equivalent to char * *, which meets the receiving requirements of formal parameters in char(int ** p)
5. Function pointer
Definition: pointer to function and pointer to store function address
Form of function pointer:
int(*pf)(int,int)
First, it should be a pointer (for example, * pf), pointing to a function. What is the type of function?
The function includes the type of function parameter and the return type of the function. Therefore, the function pointer should also indicate the components of the pointed function.
//Function pointer - a pointer that stores the address of a function //&Function name - what you get is the address of the function int Add(int x, int y) { return x + y; } int main() { //&The function name is equivalent to the function name printf("%p\n",&(Add)); printf("%p\n",Add); //Function pointer variable /*int(*pf)(int, int) = &Add;*/ int(*pf)(int, int) = Add;//Means Add===pf printf("%d\n", (*pf)(3, 5)); printf("%d\n", pf(3, 5)); printf("%d\n", Add(3, 5)); return 0; }
Observe the result of the above code:
- Function name = = & function name, indicating that the function name is the address of the function! (also remember array name! = & array name)
- In the past, we used to call the function in the form of Add(3,5) with the same effect as int (*pf) (3,5)
pf is the function pointer variable, which stores the address of the function. From this, we can know that pf==Add, and the function can also be written as pf(3,5)
(* is the understanding of form, but it doesn't work in practice)
6. Function pointer array
As the name suggests - an array for storing function pointers. The address of the function is stored in an array, and the function pointers of the same type are stored at the same time
int (*pf)(int,int)=Add; int (*pf1)(int,int)=Sub; int (*pfArr[2])(int,int);//Function pointer array pfArr
Design a calculator to understand:
//Function pointer array //Suppose you implement a calculator that calculates integer variables and can add, subtract, multiply and divide int Add(int x, int y) { return x + y; } int Sub(int x, int y) { return x - y; } int Mul(int x, int y) { return x * y; } int Div(int x, int y) { return x / y; } void menu() { printf("************* 1.Add ***************\n"); printf("************* 2.Sub ***************\n"); printf("************* 3.Mul ***************\n"); printf("************* 4.Div ***************\n"); printf("************* 0.sign out ***************\n"); } int main() { int input = 0; do { int(*pfArr[5])(int, int) = {NULL,Add,Sub,Mul,Div}; int x = 0; int y = 0; menu();//Calculator interface printf("Please do what you need:>"); scanf("%d", &input); if (input >= 1 && input <= 4) { printf("Please carry out the two values of the calculation you need:>"); scanf("%d%d", &x, &y); printf("%d\n", pfArr[input](x, y)); } else if (input == 0) { printf("Exit program\n"); break; } else { printf("Please reselect\n"); } } while(input); return 0; }
7. Pointer to function pointer array
//integer array int arr[5]; int (*p1)[5]=&arr; //p1 is a pointer to (integer array) //Array of integer pointers int* arr[5]; int* (*p2) [5]=&arr; //p2 is a pointer to (an array of integer pointers) //Function pointer int (*p)(int,int); //Function pointer array int (*p2[4])(int,int); p3=&p2;//The address of the function pointer array is taken out //p3 is a pointer to (array of function pointers) int (*(*p3)[4])(int,int);
8. Callback function
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 function, 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.
Quick understanding: a function itself is not directly used, and its address is called as a formal parameter of another function
Example 1 -- implementation of calculator
//Callback function int Add(int x, int y) { return x + y; } int Sub(int x, int y) { return x - y; } int Mul(int x, int y) { return x * y; } int Div(int x, int y) { return x / y; } void menu() { printf("**************************\n"); printf("**** 1. add 2. sub ****\n"); printf("**** 3. mul 4. div ****\n"); printf("**** 0. exit ****\n"); printf("**************************\n"); } int Calc(int (*pf)(int, int)) { int x = 0; int y = 0; printf("Please enter 2 operands>:"); scanf("%d %d", &x, &y); return pf(x, y); } int main() { int input = 0; //Calculator - calculates the addition, subtraction, multiplication, and division of integer variables //a&b a^b a|b a>>b a<<b a>b do { menu(); int ret = 0; printf("Please select:>"); scanf("%d", &input); switch (input) { case 1: ret = Calc(Add); printf("ret = %d\n", ret); break; case 2: ret = Calc(Sub); printf("ret = %d\n", ret); break; case 3: ret = Calc(Mul);// printf("ret = %d\n", ret); break; case 4: ret = Calc(Div);// printf("ret = %d\n", ret); break; case 0: printf("Exit program\n"); break; default: printf("Selection error, reselect!\n"); break; } } while (input); return 0; }
Example 2 -- learning and Simulation Implementation of qsort function
The qsort function can arrange elements of any type, including integer variables, string variables, structures, and so on
First, let's learn the connotation of qsort function
base The first address of the first element of the array to be sorted is stored in num Is the number of elements in the data array to be sorted size The size of an array element in bytes int (*compar)(const void*,const void*)A function that compares two elements in the data to be sorted
Use:
int cmp_int(const void* e1, const void* e2) { return *(int*)e1 - *(int*)e2; } void test1() { //Sorting of integer data int arr[] = { 9,8,7,6,5,4,3,2,1 }; int sz = sizeof(arr) / sizeof(arr[0]); //sort qsort(arr, sz, sizeof(arr[0]), cmp_int); //Print int i = 0; for (i = 0; i < sz; i++) { printf("%d ", arr[i]); } } struct Stu { char name[20]; int age; }; int sort_by_age(const void* e1, const void* e2) { return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age; } int sort_by_name(const void* e1, const void* e2) { return strcmp(((struct Stu*)e1)->name,((struct Stu*)e2)->name); } void test2() { //Sorting structure data using qsort function struct Stu s[] = { {"zhangsan",30},{"lisi",40},{"wangwu",20}}; int sz = sizeof(s) / sizeof(s[0]); //Sort by age /*qsort(s, sz, sizeof(s[0]), sort_by_age);*/ //Sort by name qsort(s, sz, sizeof(s[0]), sort_by_name); } int main() { //test1(); test2(); return 0; }
Simulation Implementation
//Imitate qsort function to realize a general algorithm for bubble sorting //The comparison method of different types of data shall be determined by the user void Swap(char* buf1, char* buf2,int size) { int i = 0; for (i = 0; i < size; i++) { char tmp = *buf1; *buf1 = *buf2; *buf2 = tmp; buf1++; buf2++; } } void bubble_sort(void* base, int num, int size, int(*cmp)(const void* e1, const void* e2)) { int i = 0; //Lying number for (i = 0; i <num-1; i++) { //Sorting of a trip int j = 0; for (j = 0;j < num - 1 - i; j++) { //Comparison of two elements if (cmp((char*)base+j*size,(char*)base+(j+1)*size) > 0) { //exchange Swap((char*)base + j * size, (char*)base + (j + 1) * size,size); } } } } int cmp_int(const void* e1, const void* e2) { return *(int*)e1 - *(int*)e2; } void test3() { //Sorting of integer data int arr[] = { 9,8,7,6,5,4,3,2,1 }; int sz = sizeof(arr) / sizeof(arr[0]); //sort bubble_sort(arr, sz, sizeof(arr[0]), cmp_int); //Print int i = 0; for (i = 0; i < sz; i++) { printf("%d ", arr[i]); } } int main() { test3(); return 0; }
Points to note:
1. Role of byte size
As the designer of qsort function, byte size is very important because we don't know what type of data the user is comparing;
2. How to get the address when comparing the two data? Why cast a pointer of type char *
Because the user will tell the difference between the previous element and the latter element by several bytes through the formal parameter size. The pointer of char * type is a byte, so skip one element: (char *) address + 1*size, and skip two elements: (char *) address + 2*size;
3. How to implement the internal exchange function? Do not know what type of element, how to exchange the contents of the two elements?
Because we don't know the type of element, we can't convert the pointer to the corresponding type for exchange, but we know the byte size of an element. Therefore, we still pass the pointer of char * type through the exchange of size byte by byte
4. Think: why use void * empty finger needle
Because the void*p null pointer can store any type of pointer, the qsort function does not know what type of array needs to be sorted, so it is received with void * first, and the specific type is informed by the user.