[advanced C language] playing with pointer -- High-level playing method of pointer!

Keywords: C C++

preface

We have already touched the topic of pointer in the chapter of pointer at the primary stage. We know the concept of pointer:

1. A pointer is a variable used to store an address, which uniquely identifies a piece of memory space.
2. The size of the pointer is fixed 4 / 8 bytes (32-bit platform / 64 bit platform).
3. The pointer is typed. The pointer type determines the step size of ± integer of the pointer and the permission of pointer dereference operation.
4. Pointer operation

In this chapter, we continue to explore the advanced topic of pointers

1, Character pointer

Among the pointer types, we know that one pointer type is character pointer char *.

Think about the following code. Where do pc and p point?

int main()
{
	char ch = 'www';
	char *pc = &ch;//pc refers to a character variable
	const char* p = "hello boy";//"hello boy" is a constant string
	//The above expression is used to assign the address of the first character h of the constant string "hello bit" to P (point to the first character address)
	return 0;
}

[note]

Code char* pstr = "hello bit"; It is especially easy for students to think that the string hello boy is put into the character pointer
p, but the essence is to put the address of the first character of the string hello boy into p.

Think about the following code. What is the output?

int main()
{
	char str1[] = "hello boy.";
	char str2[] = "hello boy.";
	//Two character arrays to open up space independently.
	//The array name is the address of the first element of the array
	char *str3 = "hello boy.";
	char *str4 = "hello boy.";
	//Both point to constant strings (constant strings cannot be modified)
	//Both point to the same address

	if (str1 == str2)//Compare the addresses of two arrays. They must not be equal
		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;
}

So the results are shown in the figure below

2, Pointer array and array pointer

Is a pointer array a pointer or an array?
The answer is: array.

Is the array pointer a pointer or an array?
The answer is: pointer.

for instance:

int *p1[5];  //Pointer array
int (*p2)[5];  //Array pointer

The two forms are very similar, so how can we distinguish them?

1. Pointer array

[pointer array]

First, it is an array. The elements of the array are pointers. The number of bytes occupied by the array is determined by the array itself. It is short for "array of pointers".

Pointer array is an array whose array elements are pointers (for example, int *p[5], which defines five pointers p[0],p[1],p[2],p[3],p[4]), and its essence is an array.

int *p[5];

Here comes a priority issue.

We know that array subscripts have higher priority than value operators. Therefore, p is first defined as an array with five elements. Its type is int *, so it is a pointer to an integer variable.

[Conclusion] pointer array is an array, and each array element stores a pointer variable.

How to initialize the pointer array?

int main()
{
	//char *arr[5];//arr is an array of character pointers
	//int * arr2[4];//arr2 is an array of integer pointers

	int a = 10;
	int b = 20;
	int c = 30;
	int d = 40;
	                //int* int* int* int*
	int * arr2[4] = { &a, &b, &c, &d };//arr2 is an array of integer pointers
	printf("%d\n", *arr2[0]);//Take out the contents of the first address
	int i = 0;
	for (i = 0; i < 4; i++)
	{
		printf("%d\n", *(arr2[i]));
	}
	return 0;
}

In the array pointer, & A, & B, & C, & D point to 10, 20, 30 and 40 respectively
Have you found that if defined in this way, it will be a little cumbersome.
Therefore, we can adopt the following methods:

int main()
{
	const char* arr[5] = { "abcedf", "bcedfg", "hehe" ,"hhh","zhangsan"};
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%s\n", arr[i]);
	}
	return 0;
}

2. Array pointer

2.1. What are array pointers?

[array pointer]

First, it is a pointer to an array. In a 32-bit system, it always takes up 4 bytes,
As for the number of bytes of the array it points to, I don't know. It is short for "pointer to array".

An array pointer is a pointer to an array address, which is essentially a pointer.

int (*p)[5];

In the above code, parentheses and array subscripts are in the same priority queue, so they are executed from left to right.

Therefore, p is first defined as a pointer variable, and then [5] represents an array with 5 elements, and p points to this array.

Since the type of the pointer variable is actually the type of the element it points to, this int defines the type of the array element as an integer.


Use the following example to deepen your understanding

int main()
{
	int a = 10;
	int*pi=&a;//The address of the integer is stored in the integer pointer
	char ch = 'w';
	char* pc=&ch;//The address of the character is stored in the character pointer


	int arr[10] = { 0 };
	int*p = arr;//arr - is the address of the first element of the array

	//int* parr[10]; // This is an array
	int (*parr)[10]=&arr;//What is taken out is the address of the array, which should be stored in the array pointer
	return 0;
}

So how do we initialize?

When we learn the pointer, we point the pointer to the array name, because the array name is the address of the first element of the array. When we know the address of the first element, we can know the following elements. As follows:

int main()
{
	int arr[] = { 1, 2, 3, 4, 5 };
	int *p = arr;
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d\n", *(p + i));
	}
	return 0;
}

Therefore, the above pointer p is a pointer to an integer variable, which is not a pointer to an array. The array pointer is the pointer to the array.

Therefore, during initialization, the address of the array should be passed to the array pointer instead of the address of the first element of the array. Although their values are the same, they have different meanings.

int main()
{
	int arr[] = { 1, 2, 3, 4, 5 };
	int (*p)[] = &arr;
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d\n", *(*p + i));
	}
	return 0;
}

2.2. & difference between array name and array name

Let's take arr and & arr as examples:

a. The value of & A is the same.
But the meaning is different,
A is the first address of the first element of the array, that is, the first address of a[0].
&A is the first address of the array and represents the address of the array.

For example:

int main()
{
	int arr[5] = { 0 };
	printf("%p\n", arr);
	printf("%p\n", &arr);
	return 0;
}

As you can see, their values are the same.
But what if they + 1?
As follows:

#include <stdio.h>
int main()
{
 int arr[5] = { 0 };
 printf("arr = %p\n", arr);
 printf("&arr= %p\n", &arr);
 //+1 look
 printf("arr+1 = %p\n", arr+1);
 printf("&arr+1= %p\n", &arr+1);
 return 0; }

You can see that the result after + 1 is different.
So why?

A is the first address of the first element of the array, that is, the first address of a[0].
&A is the first address of the array.
a+1 is the first address of the next element of the array, that is, the first address of a[1].
&A + 1 is the first address of the next array.

2.3. Use of array pointer

The array pointer points to the array and stores the address of the array

How to use it, for example:

#include <stdio.h>
int main()
{
    int arr[10] = {0};
    int (*p)[10] = &arr;//Assign the address of array arr to array pointer variable p
    //Here, * is first combined with p and then with []. Since the array defined above is of type int, the type of address is also of type int.
    return 0; 
}

Look at the following code and think about how we can use array pointers to print the results we want?

void print(int (*parr)[10], int sz)//Pass up the address and accept it with an array pointer
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
	//The following three methods can be printed
		//printf("%d ", parr[0][i]);// Treat a one-dimensional array as a two-dimensional array, [0] represents the first row and [i] represents traversal elements
		//printf("%d ", (*(parr + 0))[i]);//*(parr + 0) dereference header address
		printf("%d ", (*parr)[i]);//(* parr) is equivalent to the array name of the array pointed to by parr
	}
}
int main()
{
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	int sz = sizeof(arr) / sizeof(arr[0]);
	print(&arr, sz);//&Arr passes the address of the first element of the array to the function

	return 0;
}

3, Array and pointer parameters

We all know that parameters are divided into formal parameters and arguments.

A formal parameter is a parameter when a function is declared or defined
The argument is the actual value passed from the calling function when the function is called.

1. One dimensional array parameters

How to pass parameters to a one-dimensional array?
Let's take a look at an example:

Please think about whether the following can be passed successfully?

#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);
 }

2. Two dimensional array parameters

The parameters of a two-dimensional array are similar to those of a one-dimensional array.

for instance:
Can the same thinking be successful?

void test(int arr[3][5])//ok?
{}
void test(int arr[][])//ok?
{}
void test(int arr[][5])//ok?
{}
//Summary: for the design of two-dimensional array parameters and function parameters, only the first [] number can be omitted.
//Because for a two-dimensional array, you can't know how many rows there are, but you must know how many elements there are in a row.
//This is convenient for calculation.
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);
}

3. Primary pointer transfer parameter

First, use the first level pointer to pass parameters, and then use the first level pointer to receive parameters

#include <stdio.h>
void print(int *p, int sz) //The first level pointer receives int* p
{
	 int i = 0;
	 for(i=0; i<sz; i++)
 {
	 printf("%d\n", *(p+i));
 }
}
int main()
{
	 int arr[10] = {1,2,3,4,5,6,7,8,9};
	 int *p = arr;
	 int sz = sizeof(arr)/sizeof(arr[0]);
 //First level pointer p, passed to function
	 print(p, sz);
	 return 0;
 }

If we use the first level pointer to receive the passed parameters, what form can our parameters be?

void test(int *p)//What can I receive?
{}
int main()
{
	int a = 10;
	int* p1 = &a;
	int arr[10] = {0};
//How to pass to function?
	return 0;
}

In fact, we can do it in the following ways:

void test(int *p)
{}
int main()
{
	int a = 10;
	int* p1 = &a;
	int arr[10] = {0};

	test(&a);//Send the address up
	test(arr);//You can pass an array name in the past
	test(p1);//You can pass a pointer
	test(NULL);//It's OK to pass null pointer. Consider it clearly, because passing null pointer is to pass 0, and null pointer cannot be dereferenced, and space access is not supported

	return 0;
}

4. Secondary pointer transfer parameter

If it is a secondary pointer, how to pass parameters?

Similarly, we can have the following methods.

void test(int **ppa)
{}

int main()
{
	int a = 10;
	int* pa = &a;
	int** ppa = &pa;
	
	int* arr[5];

	test(ppa);
	test(&pa);
	test(arr);

	return 0;
}

4, Function pointer

What is a function pointer?

We say that an array pointer is a pointer to an array. Is a pointer to an array.
Similarly

A function pointer is a pointer to a function. It is a pointer to a function

Let's consider the following three codes:

char * (*fun1)(char * p1,char * p2);
char * *fun2(char * p1,char * p2);
char * fun3(char * p1,char * p2);

what do you mean?

char * (*fun1)(char * p1,char * p2);


char *fun2(char * p1,char * p2);
//fun2 is the function name, p1 and p2 are parameters, whose type is char * and the return value of the function is char *.

char ** fun3(char * p1,char * p2);
//Compared with the second expression, the only difference is that the return value type of the function is char * *, which is a secondary pointer.

So what does the first code mean?
Here fun1 is not a function name, but a
Pointer variable, which points to a function. This function has two pointer type parameters, and the return value of the function is also a pointer.

So how do we use function pointers?

#include <stdio.h>
#include <string.h>
char * fun(char * p1, char * p2)
{
	int i = 0;
	i = strcmp(p1, p2);
	if (0 == i)
	{
		return p1;
	}
	else
	{
		return p2;
	}
}
int main()
{
	char * (*pf)(char * p1, char * p2);
	pf = &fun;
	(*pf) ("aa", "bb");
	return 0;
}

When we use a pointer, we need to use the key ("*") to get the value in the memory it points to, and the same is true for function pointers. By using (*pf) to extract the function that exists at this address, then call it.

When assigning a value to a function pointer, you can use & fun or directly use the function name fun. This is because the function name is actually an address after being compiled, so there is no essential difference between the two usages here.

Let's take a look at what the following code means?

(*(void(*) ())0)(

Step 1: void(*) (). You can see that this is a function pointer type. This function has no parameters and no return value.

Step 2: (void (*) () 0. This is to cast 0 into a function pointer type. 0 is an address, that is, a function exists in a region with the first address of 0.

Step 3: ((void() ())0), which is the content of a section of memory starting from the 0 address. Its content is the function stored in a section of area with the first address of 0.

Step 4: ((void() ()) 0 ()), this is a function call.

5, Function pointer array

The address of the function is stored in an array, which is called the function pointer array

char * (*pf[3])(char * p);//A function pointer array, pf is the array name, and the type is char * (*) ()
//pf is combined before [3], which indicates that it is an array. The array stores three pointers to the function
//The pointer is combined with * to illustrate that it is a function pointer array

6, Pointer to array of function pointers

It looks very complicated, but it's not difficult to analyze it carefully.

The function pointer array pointer here is just a pointer. But this pointer points to an array, which contains pointers to functions. That's it. (dolls)

How to define it? The following code describes

void test(const char* str) {
 printf("%s\n", str);
}
int main()
{
 //Function pointer pfun
 void (*pfun)(const char*) = test;
 //Array of function pointers pfunArr
 void (*pfunArr[5])(const char* str);
 pfunArr[0] = test;
 //Pointer to function pointer array pfunArr ppfunArr
 void (*(*ppfunArr)[10])(const char*) = &pfunArr;
 return 0; }

7, Callback function

According to Wikipedia:

Pass an executable code to other code like parameter passing, and this code will be called and executed at some time, which is called callback. If the code is executed immediately, it is called a synchronous callback. If it is executed later, it is called an asynchronous callback

For example:
When function F1 calls function F2, function F1 passes the pointer of another function F3 to function F2 through parameters. During the execution of function F2, function F2 calls function F3. This action is called Callback, and the function F3 first passed in as a pointer and then called back is the Callback function.

for instance:

int Add(int x, int y)
{
	return x + y;
}

int Sub(int x, int y)
{
	return x - y;
}
void Cale(int(*pf)(int, int))//Address passing through pointer
{
	int ret = pf(3, 5);
	printf("%d\n", ret);
}

int main()
{
	//Cale(Add);
	Cale(Sub);//Call function
	return 0;
}

summary

This article has been written off and on for several days. First, I don't have half a bucket of water. A lot of knowledge is limited to theory and can't be practiced. Second, the high-order pointer is really difficult to understand. Even if it is written now, the understanding is still not thorough. Referring to the book "in-depth analysis of C language", if you want to have a deeper understanding, it is suggested to look for this book and gain more.

Posted by jonat8 on Sun, 10 Oct 2021 06:44:18 -0700