This is the 11th day of my participation in the Gwen Challenge in November. Check out the details: The last Gwen Challenge in 2021

Pointer to the advanced

We have been in touch with Pointers at the beginning and have learned about Pointers, including:

  • Pointer definition: Pointer variable used to hold an address. The address uniquely corresponds to one piece of memory space.
  • Pointer size: 4 bytes for fixed 32-bit platforms and 8 bytes for 64-bit platforms.
  • Pointer type: The type determines the step size of the pointer ± integer and the size to access when the pointer is dereferenced.
  • Pointer operation: pointer dereference, pointer ± integer, pointer – pointer, pointer relation operation.

On this basis, this chapter makes a deeper study of C language stage pointer.

A character pointer

Pointer to a character stored in the address of the character. Type char *

The role of a character pointer
  1. Points to a single character variable
char ch = 'w';
const char* pch = &ch;
Copy the code

It is easy to understand that pointer dereference accesses character variables.

  1. Points to the first character of the string
char* pc = "hello";
printf("%s\n", pc);
Copy the code

Is this putting the string “hello” in a pointer?

Like an array name, this pointer holds the address of the first character of the constant string “hello”. Find the entire string by dereferencing the pointer to access the first character address.

char* pc = "hello";
printf("%c\n", *(pc + 1));//e
printf("%s\n", pc);//hello
printf("%s\n", pc + 1);//ello
Copy the code

Strings are still contiguous in nature, so Pointers plus or minus integers have access effects as well. This also shows the use of %s. Giving an address to %s treats the following content as a string and prints it up to \0. (so I guess the s of %s stands for string)

Character pointer characteristics

sample

char str1[] = "hello bit";
char str2[] = "hello bit";

char* str3 = "hello bit";
char* str4 = "hello bit";

if (str1 == str2)
    printf("str1 = str2\n");/ / 1
else
    printf("str1 ! = str2\n");/ / 2

if (str3 == str4)
    printf("str3 = str4\n");/ / 3
else
    printf("str3 ! = str4\n");/ / 4
Copy the code

Str1 (3)==str2(4); (Address is what really determines whether the two are the same.)

The answer is 2 and 3. Since 1 and 2 initialize arrays with strings, 3 and 4 are Pointers to constant strings.

  • Str1 and STR2 are ordinary arrays that have two Spaces in memory but hold the same data.
  • Str3 and STR4 refer to constant strings and are stored in the constant area of memory, which cannot be modified and is unique i.e. the constant area only holds one. So str3 and STR4 both point to the same string.

The storage characteristics of constant area: the data stored in constant area cannot be modified, because it cannot be modified, so it is enough to save a copy. Later, if necessary, use the same data. (The data is still the same data, but maintained with different Pointers)

conclusion

  1. Constant strings cannot be modified and are stored in the constant area of memory.
  2. It’s unique in that the constant area only holds one.
Pointer to an array
Pointer array definition
int arr[10];// An integer array
char ch[5];// Array of characters
float f[20];// Float array
Copy the code

As you can see, the element type is the “type” of the array.

char* pch[5];
int* parr[10];
float* pf[20];
Copy the code

An array of Pointers is an array of Pointers.

int arr[10];
int* arr[10];
Copy the code

The array name arr, the address of the first element, is a pointer to an integer array.

The name of the array of Pointers is parr, which is also the address of the first element, but the first element is an int* variable, so parr is a second-level pointer.

Use of pointer arrays
int arr1[] = { 1.2.3.4.5 };
int arr2[] = { 2.3.4.5.6 };
int arr3[] = { 3.4.5.6.7 };

int* parr[] = { arr1,arr2,arr3 };

for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 5; j++) {
        / / 1.
        printf("%d ", parr[i][j]);
        / / 2.
        printf("%d ", *(*(parr + i) + j));
    }
    printf("\n");
}
/ / the answer
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
ps:
parr[i] <==> *(parr+i) 
*(parr[i]+j) <==> *(*(parr+i)+j) <==> (*parr+i)[j] <==> parr[i][j]
Copy the code

Access each element of an integer array through an array of Pointers. Parr [I][j] and *(*(parr+ I)+j) are essentially equivalent.

const char* pch[] = { "abcde"."bcdef"."cdefg" };
for (int i = 0; i < 3; i++) {
    / / 1.
    printf("%s", pch[i]);
    / / 2.
    printf("%s", *(pch + i));
    for (int j = 0; j < 5; j++) {
        / / 3.
        printf("%c", pch[i][j]);
        / / 4.
        printf("%c", *(*(pch + i) + j));
    }
    printf("\n");
}
Copy the code

It’s easier to print strings using %s. To use %c, you get the starting address of each string and access it backwards.

We can also see the relationship between array and pointer, I would like to call it * and [] love hate!

 

Pointer to an array

From the previous example, it is not hard to see that an array pointer is a pointer to an array, not an array.

Definition of an array pointer
char ch = 'w';
char* pch = &ch;// The character address is stored in the character pointer

int a = 10;
int* pint = &a;// Integer addresses are stored in integer Pointers

float f = 0.0;
float* pf = &f;// Floating point addresses are stored in floating point Pointers
Copy the code

What variable’s address is stored in what pointer. The type to which the pointer points determines the type of the pointer. As the name implies, array Pointers point to arrays.

The address of the array is stored in an array pointer. And the type of the array pointer is the type of the array plus a star.

Which of the following definitions is correct?

int arr[10] = { 0 };
/ / 1.
int* pa = arr;
/ / 2.
&arr;// The address of the entire array
int* parr = &arr;
/ / 3.
int* parr[10] = &arr;
/ / 4.
int(*parr)[10] = &arr;
Copy the code
  1. Fetch the address of the first element, not the address of the entire array
  2. An integer pointer should hold the address of an integer variable. The address of an array cannot be stored in an integer pointer.
  3. []Priority ratio of*High,parrWith the first[]Combine to an array name, soparrIt’s an array of Pointers.

The type of the pointer is determined by the type of the array. First, find the type int[10]. Int (*parr)[10]; int(*parr)[10]

C specifies that [] must come last, so int[10](*parr) cannot be written.

int* parr[10];// Array of Pointers
int(*parr)[10];// Array pointer
Copy the code

We emphasized earlier that removing the name is a type. So int[10] is the type of an integer array, int*[10] is the type of a pointer array, and int(*)[10] is the type of an array pointer.

& Array name and array name

I’ve been introduced more than once, so I’ll stick to the point.

The pointer type determines the step size of the pointer ± integer.

// Address of the first element +1
printf("%p\n", arr);//0073FCA4
printf("%p\n", arr + 1);//0073FCA8
// The entire array address +1
printf("%p\n", &arr);//0073FCA4
printf("%p\n", &arr + 1);//0073FCCC
Copy the code
  1. The first element address is an integer pointer +1 and can only be accessed backwards by 4shou bytes
  2. The entire array address +1, that isint(*)[10]The type pointer +1 is accessed backwards
    i n t x 10 Int x 10
    That’s 40 bytes.

Sizeof (arr) also represents the entire array, so why does sizeof represent the entire array? An array is a structure that keeps the sizeof an array, and sizeof is the sizeof the array, so that’s a little bit more rigorous.

Use of array Pointers

Iterate through the array, using arrays or Pointers as parameters to receive. And the notion of receiving in arrays is just a level of understanding, it’s all Pointers in nature.

void Print1(int arr[], int sz) {
	for (int i = 0; i < sz; i++) {
		//printf("%d ", arr[i]); 
		printf("%d ", *(arr + i)); }}void Print2(int* arr, int sz) {
	for (int i = 0; i < sz; i++) {
		printf("%d ", arr[i]);
		//printf("%d ", *(arr + i));}}int main(a) {
	int arr[10] = { 1.2.3.4.5.6.7.8.9.10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	Print1(arr, sz);
	Print2(arr, sz);
	return 0;
}
Copy the code
Negative cases

Array as an argument, receive an array or pointer. Array Pointers are useful when used correctly, but can be awkward when used casually. Here’s how to force an array pointer.

// Error
void Print3(int(*pa)[10].int sz) {
	for (int i = 0; i < sz; i++) {
		//printf("%d ", pa[i]);
		printf("%d ", *(pa + i)); }}Copy the code

Pass the entire array address, receive it with an array pointer, and then what, dereference pa directly?

The result is obviously wrong, as you can also see from the result that the address is printed in decimal, +1 skips 40 bytes.

Here I have a question when learning, why pass the address of the array, after solving a layer of reference is still the address?

Arr dereference the address of the first element. Arr is the address of the first element. Arr is the address of the first element

void Print4(int(*pa)[10].int sz) {
	for (int i = 0; i < sz; i++) {
		printf("%d ", *(*(pa)+j)); }}Copy the code

If we think of a one-dimensional array as a two-dimensional array the first row. Since the two-dimensional array is stored consecutively in memory, we can avoid the above error by printing only the first line of the two-dimensional array.

style=”zoom:80%;” />

*(pa) is the name of the array to which the array pointer points. Array Pointers refer to the entire array, treat it as a two-dimensional array and dereference the first element of a row, thus traversing it.

Positive cases

As you can see from the above example, using an array pointer to access a two-dimensional array works fine.

// Use a two-dimensional array to receive parameters
void Print1(int arr[3] [5].int r, int c) {
	for (int i = 0; i < r; i++) {
		for (int j = 0; j < c; j++) {
			//printf("%d ", arr[i][j]);
			printf("%d ", *(*(arr + i) + j));
		}
		printf("\n"); }}Copy the code

The above example is the normal two – dimensional array parameters, two – dimensional array received case. So let’s use an array pointer to receive.

// Use the array pointer to receive the parameter
void Print2(int(*pa)[5].int r, int c) {
	for (int i = 0; i < r; i++) {
		for (int j = 0; j < c; j++) {
            / / 1.
            printf("%d ", pa[i][j]);
            / / 2.
			printf("%d ", *(*(pa + i) + j));
		}
		printf("\n"); }}int main(a)
{
	int arr[3] [5] = { 1.2.3.4.5.2.3.4.5.6.3.4.5.6.7 };
	Print2(arr, 3.5);// The first element of the two-dimensional array is the first line
    
	return 0;
}
Copy the code
  • Think of a two-dimensional array as a one-dimensional array with three elements (each element is also a one-dimensional array), that is, a one-dimensional array of one-dimensional arrays.
  • Since each element is a one-dimensional array with five elements, the array pointer is defined asint(*p)[5], pointing to the “one-dimensional array” in the first line. (Array name is passed)
  • The first layer of the loop is used for “skipping”, which means skipping five elements at a time. The second loop iterates through each row of the one-dimensional array.

  1. Both a two-dimensional array and an array pointer receive the first line address.
  2. The type of an array pointerint(*)[5], the same type as the address of the first element of a two-dimensional array.

Therefore, the address of the first element of the two-dimensional array and the array pointer are equivalent, that is, the array pointer PA is the name of the array.

The first element of a two-dimensional array is its first line, which is equivalent to a one-dimensional array whose address type is int(*)[5]. And the argument is a two-dimensional array name, degraded to a pointer to the first row, so it is an array pointer of type int(*)[5].

Array Pointers to two-dimensional arrays are a good example of how to use array Pointers.

Example

What are the following examples?

/ / 1.
int arr[5];
/ / 2.
int *pa1[5];
/ / 3.
int (*pa2)[10];
/ / 4.
int (*pa3[10[])5];
Copy the code
  1. The integer array
  2. An array of Pointers to integers

Pa1 combines with [] to form an array, leaving int* to form an array element.

  1. Pointer to an integer array

(*pa2), * is first combined with pa2 as a pointer, and the remaining int[10] points to an integer array with 10 elements.

  1. An array that holds Pointers to arrays

Pa3 is first combined with [10] to form an array, and the remaining int(*)[5] is the element that points to an array. So it’s a pointer to an array of 10 elements.

Thinking backwards, there is an integer array arr[5] and an array pointer to that array of type int(*)[5], and an array pointer array pa3[10] to hold the array pointer.

Type discrimination method
  1. If the names sum first[]Combine it with an array, just get rid of the name of the array is the type of the array, get rid of it[n]And array names are the types of their elements.
  2. If the names sum first*Combined as a pointer, just remove the name of the pointer is the type of the pointer, remove*And pointer names are the types of variables to point to.

 

Array pass and pointer pass

In practice, we may encounter the problem of how to design parameters when arrays and Pointers are used as function parameters.

One-dimensional array parameter passing

One-dimensional array parameter passing, is the following reception possible?

/ / 1.
void test(int arr[]) 
{}
/ / 2.
void test(int arr[10]) 
{}
/ / 3.
void test(int* arr) 
{}
int main(a)
{	
	int arr[10] = { 0 };
	test(arr);
	return 0;
}
Copy the code
  1. Array passing is acceptable but is actually degraded and optimized to Pointers, and the compiler doesn’t actually create an array.

  2. The array size is meaningless, arbitrary or none, because the shape parameter group is imaginary. (ambiguous)

  3. Array pass is essentially the address of the first element, which is of type int, so the type of pointer is int*.

So it can be seen that [] and *() are equivalent. I’d like to call it the love and hate between * and []! (‐ ^ ▽ ^ ‐)

/ / 1.
void test2(int* arr[2])
{}
/ / 2.
void test2(int** arr) 
{}
int main(a)
{	
	int* arr2[10] = { 0 };
	test2(arr2);
	return 0;
}
Copy the code

An array of Pointers, each element of type int*, so a secondary pointer receives the array name.

One-dimensional array parameters, array and pointer receive.

Two dimensional array parameter passing
/ / 1.
void test(int arr[3] [5]) 
{}
/ / 2.
void test(int arr[][])
{}
/ / 3.
void test(int arr[][5])
{}
int main(a) {
	int arr[3] [5] = { 0 };
	test(arr);
}
Copy the code
  • A two-dimensional array parameter is received with a two-dimensional array. Rows may be omitted, but columns may not.
/ / 4.
void test(int* arr)
{}
/ / 5.
void test(int* arr[5])
{}
/ / 6.
void test(int(*arr)[5])
{}
/ / 7.
void test(int** arr)
{}
int main(a) {
	int arr[3] [5] = { 0 };
	test(arr);
}
Copy the code
  1. An integer pointer should receive the address of an integer variable, whereas a two-dimensional array name should receive the address of the array in the first line.
  2. Pointer arrays have nothing to do with two-dimensional arrays.
  3. A two-dimensional array pass is received with an array pointer of the size of the first array.
  4. A two-level pointer is independent of a two-dimensional array.
  • Two-dimensional array array namearrThe address of the first “one-dimensional array”, which is received with an array pointer.

An int(*)[5] pointer to a one-dimensional array of 5 elements. The pointer +1 accesses the next line, jumping one line at a time. One more layer of references accesses each element in a row.

Level-1 pointer parameter transmission

Conversely, if the function parameter is a pointer, how can the argument be designed when passing the parameter?

void test(int* ptr, int sz)
{}
void test(int arr[],int sz)
{}
int main(a)
{
    / / 1.
    int a = 10;
    test(&a);
    / / 2.
	int arr[10] = { 0 };
	test(arr);
	return 0;
}
Copy the code
  • Pointers and arrays can be used as parameters, but one-dimensional arrays are not recommended.
  • If the parameter is a pointer, the argument can also be a pointer (address) or an array.
Secondary pointer parameter transmission

How are parameters designed when second-order Pointers are used as arguments?

void test(int** pp) {
	printf("%d\n", **pp);
}
void test(int* arr[]) {// The usage is not good
	printf("%d\n", *arr[0]);
}
int main(a) {
	int a = 10;
	int* p = &a;
	int** pp = &p;
	test(pp);
	return 0;
}
Copy the code
  • When a secondary pointer is used as a function parameter, the parameter can be a secondary pointer and an array of Pointers.

When a parameter is a second-level pointer, what can be passed as an argument?

void test(int** pp) {
	printf("%d\n", **pp);
}
int main(a) {
	int a = 10;
	int* p = &a;
	int** pp = &p;
	int* arr[10] = { &a };
    / / 1.
	test(&p);
    / / 2.
	test(pp);
    / / 3.
	test(arr);
	return 0;	
}
Copy the code
  • When the parameter is a second-level pointer, the argument can be: second-level pointer (first-level pointer address), the address of the first element of the pointer array.

 

A function pointer

Definition of a function pointer

The address where an integer pointer holds an integer; The address of an array pointer; So, by analogy, the function pointer holds the address of the function.

Obviously, the function pointer points to the function, the address where the function is stored. To understand the function pointer, first understand the address of the function.

” />

The ampersand or function name represents the function address, and is slightly different from the ampersand and array names, which are exactly the same.

The address of the function must be placed in the function pointer. What is the type of the function pointer? (Take the Add function as an example)

// Integer pointer
int* pa = &a;
// Character pointer
char* pc = &ch;
// Array pointer
int(*pa)[10] = &arr;
// function pointer - holds the function address
int(*pf)(int.int) = &Add;
Copy the code
The type of a function pointer
int Add(int x, int y);
/ / 1.
int(*pf)(int.int) = &Add;
/ / 2.
int *pf(int.int) = &Add;
Copy the code

If the parentheses int* pf(int, int) are removed, pf becomes the function name and the return type is int*. So Pointers must have parentheses.

* is the type of variable to which the pointer points.

  • Integer pointer, removed*And pointer names, which are integer variable typesint. Character pointer, is a character typechar. Array pointer, removed to array typeint[10].
  • Function pointer, get rid of it*And pointer name, which is the type of the functionint(int,int).

conclusion

  • Remove pointer namepfIs the pointer typeint(*)(int, int)
  • Remove pointer namepfand*Is the type of the function to which the pointer pointsint(int, int)
The use of function Pointers

Computer hardware programs often call functions by calling addresses, so they need to be called using function Pointers.

int Add(int x, int y)
{
	return x + y;
}
int main(a)
{
    / / 1.
    int(*pf)(int.int) = &Add;// Function pointer to Add function
    / / 2.
    int(*pf)(int.int) = Add;
	
    / / 1.
	int ret = (*pf)(2.3);
	/ / 2.
    int ret = pf(2.3);
	
    printf("%d\n", ret);
	return 0;
}
Copy the code

The &function name and the function name are the address of the function. So either way you can initialize a function pointer.

Since the function name Add can be assigned directly to the function pointer pf, the two are equivalent. Function pointer name pf can also be used without reference, * is not used here, even no or multiple write is not important, just for understanding.

Since a function name is also a function address, dereferencing it is also ok. We could even write that, but only for fun, not necessarily.

Add(2.3);/ / 1
(*Add)(2.3);/ / 2
(*&Add)(2.3);/ / 3
Copy the code
Example

Explain the following code

/ / 1.(* (void(*) ())0) ();/ / 2.
void (*signal(int.void(*) (int))) (int);
Copy the code

  1. Void (*)() is a function pointer type placed in () 0, that is, cast 0 to address, where a function of type void(*)(void) is stored.

  2. Thus (void(*)())0 becomes a pointer to the function at that address and dereference it to access the function.

  3. (* (void (*) ()) 0) is equivalent to (* pf), reference solution instead of through a function pointer function name, the function name behind take (); , equivalent to (*pf)(); That is, a function call with no arguments.

  1. signalThe first and(a)Combine, illustratesignalIs the function name, followed by(int, void(*)(int))Is its parameter list.
  2. Remove the function name and argument list, and the restvoid(*)(int)That’s the return type, so onceFunction declaration.
void (* signal(int.void(*) (int))) (int);

typedef void(* pf_t)(int);//typedef simplifies code
pf_t signal(int.pf_t);
Copy the code

 

Function pointer array

// Integer array - Store integer variables
int arr[10];
// Character array - Store character variables
char ch[5];
// Pointer array - holds pointer variables
int* arr[10];
// Function pointer array - store function pointer
int(*pfar[10]) (int.int);
Copy the code

Pointer arrays hold pointer variables and function pointer arrays hold function Pointers, so the element type is function pointer type.

Definition of an array of function Pointers
int Add(int x, int y) {//int(*)(int,int)
	return x + y;
}
int Sub(int x, int y) {//int(*)(int,int)
	return x - y;
}
int Mul(int x, int y) {//int(*)(int,int)
	return x * y;
}
int Div(int x, int y) {//int(*)(int,int)
	return x / y;
}
int main(a) {
	// Function pointer array -pfarr
	int(*pfArr[4]) (int.int) = { Add,Sub,Mul,Div };
	return 0;
}
Copy the code

Functions of the same type are stored in the same array of function Pointers. Functions with similar functions generally have the same type.

Function pointer array use

The calculator is implemented using an array of function Pointers to simplify the calling process.

Transfer table
// The calculator implements 1.0
void menu(a) {
	printf("**********************************\n");
	printf("***** 1.Add ****** 2.Sub *****\n");
	printf("***** 3.Mul ****** 4.Div *****\n");
	printf("************ 0.exit ************\n");
	printf("**********************************\n");
}
int main(a) {
	int (*pfArr[10]) (int.int) = { 0,Add,Sub,Mul,Div };// Array subscript matches option number
	int input = 0;
	int a = 0;
	int b = 0;
	do {
		menu();
		printf("Please select :>");
		scanf("%d", &input);
		if (0 <= input && input <= 4) {
			if (input == 0) {
				printf("Quit the game \n");
				break;
			}
			else {
				printf("Please enter operand \n");
				scanf("%d %d", &a, &b);
				printf("ret == %d\n", pfArr[input](a, b));
				break; }}else {
			printf("Input error \n");
			break; }}while (input);
	return 0;
}
Copy the code

The function pointer array allows you to “jump” to different functions by function address in different selection cases.

Such an array of function Pointers is called a transfer table. (Jump function)

The callback function

If you don’t want to discard the switch statement, you can also simplify code 3.0 by creating global variables. If you don’t want to create global variables, you can use 2.0

/****** * calculator implementation * 2.0 ******/
void Calc(int (*pf)(int.int)) {
	int a = 0;
	int b = 0;
	printf("Please enter operand :>");
	scanf("%d %d", &a, &b);
	printf("%d\n", pf(a, b));
}
int main(a) {
	int input = 0;
	do {
		menu();
		printf("Please select :>");
		scanf("%d", &input);
		switch (input) {
		case 0:
			printf("Exit successful \n");
			break;
		case 1:
			Calc(Add);
			break;
		case 2:
			Calc(Sub);
			break;
		case 3:
			Calc(Mul);
			break;
		case 4:
			Calc(Div);
			break;
		default:
			printf("Please reselect \n");
			break; }}while (input);
	return 0;
}

/****** * calculator implementation * 3.0 ******/
int (*pfArr[10]) (int.int) = { 0,Add,Sub,Mul,Div };
int input = 0;

void Call(a) {
	int a = 0;
  int b = 0;
	printf("Please enter operand :>");
	scanf("%d %d", &a, &b);
	printf("%d\n", pfArr[input](a, b));
}
int main(a) {
	do {
		menu();
		printf("Please select :>");
		scanf("%d", &input);
		switch (input) {
		case 0:
			printf("Exit successful \n");
			break;
		case 1:
		case 2:
		case 3:
		case 4:
			Call();
			break;
		default:
			printf("Please reselect \n");
			break; }}while (input);
	return 0;
}
Copy the code

As shown in the figure below, a function called through a function pointer is called a callback function, which is called even if a third party calls the parameters of the calling function.

If you want to call different functions depending on the conditions in the calling function, you must use the method of the callback function: the calling function uses a pointer to a different function. The callback function is very convenient in large projects.

 

Pointer to an array of function Pointers

int arr[10];
int(*parr)[10] = &arr;// An integer array pointer
char(*pch)[10] = &ch;// Character array pointer
// A pointer to an integer array pointer
int(*(*pparr))[10] = &parr;
// A pointer to a character array pointer
char(*(*ppch))[10] = &pch;

1 / / function.
int Add(int x, int y) {
	return x + y;
}
// Function pointer 2.
int (*pf)(int.int) = Add;
// Function pointer array 3.
int (*pfArr[10]) (int.int) = { Add };
// Pointer 4 to the array of function Pointers.
int(*(*ppfArr)[10]) (int.int) = &pfArr;
Copy the code

The pointer is the type of the variable to which it points. Removing the pointer name is the type of the pointer.

To define an array pointer, we need to get the type of the array to which the pointer points. 1. Write the pointer name, preceded by *. 2. Write an array of type int()[10]

Define a pointer to an array of function Pointers, writing it as follows:

  1. Function — Gets the type of the function:int(int, int)
  2. Function pointer — Returns the type of function pointer:int(*)(int, int)
  3. Function pointer array — Get the type of function pointer array:int(*[10])(int, int)
  4. Pointer to an array of function Pointers

Looking backwards, the pointer to an array of Pointers is the type of the array of Pointers, and the pointer name is the type of the array.

There is no need to explore it further, Pointers are placed in arrays, arrays are pointed to by Pointers…

Because the space is too long, the following callback function and pointer array interview questions are put in pointer advanced 2.