C language - in-depth understanding of pointers_study notes

For a preliminary understanding of pointers, you can browse the blog I wrote before C Language - Pointers_Study Notes

Use some classic examples to gain a deeper understanding of C language pointers

1. Pointer arithmetic

For pointer operations, in the previous article C Language - Pointers_Study Notes , pointer addition and subtraction and pointer increment and decrement operations have been introduced in detail.

This article will combine array-related knowledge to conduct an in-depth analysis of pointer operations. (Mainly based on the topic)

1.1 Question 1

#include<stdio.h>

int main()
{
    
    
	char* a[] = {
    
     "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);

	return 0;
}

The output is:

at

As shown below:
The meaning of the question is that there is a one-dimensional array with 3 elements. The type of each element in the array is char* type, and the address of the first letter of the three character constants is stored (a[] is a pointer array, Each element of the array is a pointer type); then the address of the first element of the pointer array a[] is stored in pa, and then the pa++ operation is performed, and then *pa is printed in the form of %s.
Insert image description here

1.2 Question 2

#include <stdio.h>

int main()
{
    
    
	char* c[] = {
    
     "ENTER","NEW","POINT","FIRST" };
	char** cp[] = {
    
     c + 3,c + 2,c + 1,c };
	char*** cpp = cp;

	printf("%s\n", **++cpp);
	printf("%s\n", *-- * ++cpp + 3);
	printf("%s\n", *cpp[-2] + 3);
	printf("%s\n", cpp[-1][-1] + 1);

	return 0;
}

The output result is:
Insert image description here
First, analyze this code.
Through the first three lines of code, you can roughly draw a diagram of the pointing relationship, as follows:

Insert image description here

  1. Let’s analyze printf(“%s\n”, **++cpp); ++cpp makes cpp point to element c+2. What *++cpp gets is the third element in array c, which is the first element P. The address of P, so **++cpp dereferences the address of P and prints it out in the form of %s, so the result is POINT.

  2. Then, the pointing relationship diagram changes, as follows
    Insert image description here
    Insert image description here

  3. Because the previous line of code performed the ++cpp operation again, the pointing relationship diagram changed again, as shown below:
    Insert image description here
    Insert image description here

  4. The pointing relationship diagram has not changed
    Insert image description here
    Insert image description here

2. Constant pointer

A const pointer is a pointer. The content it points to cannot be modified, but the pointer itself can be moved. The usage scenarios of constant pointers include but are not limited to the following situations:

2.1 Protecting data

Sometimes, we want the data pointed to by the pointer to be constant, that is, it cannot be modified. This usually occurs when the integrity or security of data needs to be protected. For example, when passing a pointer to sensitive data in a function, you can use a constant pointer to prevent the data from being modified.

const int *ptr = &secret_data;

2.2 Function parameter transfer

In function parameter passing, constant pointers can be used to prevent the function from modifying the passed data. For example, when implementing a sorting function, we may not want the function to modify the incoming data, so we can use a constant pointer.

void sort(const int* arr, int n) {
    
    
    // ...
}

2.3 String processing

In C language, strings are usually represented as character arrays or character pointers. When working with strings, constant pointers ensure that the contents of the string are not modified, which helps prevent potential errors.

const char* str = "Hello, World!";

2.4 Optimize performance

Constant pointers and ordinary pointers may behave differently on the underlying hardware. In some cases, using constant pointers may improve performance, especially when bit operations and high-precision calculations are involved. However, this optimization usually requires a deep understanding of the underlying hardware and compiler, so it is generally not recommended without a good reason.

2.5 Const members of data structures

In some data structures, constant pointers can be used to indicate that the data structure is constant, such as const STL containers.

2.6 Avoid type conversions

Constant pointers can also be used to avoid unnecessary type conversions. For example, if you have a function that returns a const double*, then you don't need to convert the return value to another type.

3. Variable pointer

Examples of usage scenarios for variable pointers include but are not limited to the following situations:

3.1 Write a function to exchange the values ​​of two variables

By using pointers, the values ​​of two variables can be exchanged within a function.

#include <stdio.h>

void swap(int *a, int *b) {
    
    
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    
    
    int x = 10;
    int y = 20;
    printf("Before swap: x=%d, y=%d\n", x, y);
    swap(&x, &y);
    printf("After swap: x=%d, y=%d\n", x, y);
    return 0;
}

3.2 The function returns the status of the operation, but the result is returned through a pointer

For example, have a function return a special value that is not within the valid range to indicate an error.

#include <stdio.h>

int calculate(int *result) {
    
    
    // ... some calculation ...
    if (error) {
    
    
        *result = -1;  // set result to -1 if there is an error
        return 0;
    } else {
    
    
        *result = 123;  // set result to some value if no error
        return 1;
    }
}

int main() {
    
    
    int result = -1;  // Initialize result to -1
    calculate(&result);
    if (result == -1) {
    
    
        printf("Error occurred!\n");
    } else {
    
    
        printf("Result: %d\n", result);
    }
    return 0;
}

4. Array pointers and pointer arrays

4.1 Concept

  1. An array pointer is a pointer, a pointer to an array.
    For example:
int arr[] = {
    
    1, 2, 3, 4, 5};
int *ptr = arr; // ptr是指向数组的指针,指向数组首元素的地址,ptr+1是跨过4个字节
int *ptra = &a;//ptr是指向整个数组的指针,也是数组首元素的地址,但是ptra+1跨过20个字节
  1. A pointer array is an array, and each element in the array stores an address.
char* a[] = {
    
     "work","at","alibaba" };//这里的数组a就是一个指针数组,数组中的每个元素都是char*类型的指针

Insert image description here
Each element of the pointer array is an address, which can point to an area.

Note: It was mentioned before when using pointer arithmetic.

4.2 Pointer array simulation to implement two-dimensional array

Since each element of the pointer array is an address, and this address can then point to an area, you can take advantage of this and use a pointer array to simulate a two-dimensional array.

code show as below:

#include <stdio.h>
int main() 
{
    
    
	int arr1[] = {
    
     1,2,3,4,5 };
	int arr2[] = {
    
     2,3,4,5,6 };
	int arr3[] = {
    
     3,4,5,6,7 };
	//数组名是数组⾸元素的地址,类型是int*的,就可以存放在parr数组中
	int* parr[3] = {
    
     arr1, arr2, arr3 };
	int i = 0;
	int j = 0;
	for (i = 0; i < 3; i++)
	{
    
    
		for (j = 0; j < 5; j++)
		{
    
    
			printf("%d ", parr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

Access and print the contents of the three arrays arr1, arr2 and arr3 through the pointer array. The running results are as follows: The
Insert image description here
relationship between them is represented as follows:
Insert image description here
parr is a pointer array with three elements, all of which are addresses. The first element The address of the first element of array arr1 is stored; the second element stores the address of the first element of array arr2; the third element stores the address of the first element of array arr3. To access arr[1], you can write parr[0][1], which looks like a two-dimensional array.

4.3 The essence of array parameter passing

In C language, arrays are usually passed through pointers. When you pass an array as a parameter to a function, what is actually passed is the address of the array. This is because in C language, the array name is actually a pointer to the first element of the array.

For example:

#include <stdio.h>

void printArray(int arr[], int size) {
    
        //其实这里函数写成 void printArray(int* , int size)这种形式也是可以的
    for (int i = 0; i < size; i++) {
    
    
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main() {
    
    
    int arr[] = {
    
    1, 2, 3, 4, 5};
    int size = sizeof(arr) / sizeof(arr[0]);
    printArray(arr, size);
    return 0;
}

Supplement: The essence of passing parameters for a one-dimensional array is the address of the first element of the array. The essence of passing parameters for a two-dimensional array is the address of the first row of the array.

5. Function pointers

A function pointer is a pointer, which is a pointer to a function. It stores the address of the function. The function can be called through the function pointer variable.

5.1 Function address:

#include <stdio.h>
void test()
{
    
    
	printf("hehe\n");
}
int main()
{
    
    
	printf("test: %p\n", test);
	printf("&test: %p\n", &test);
	return 0;
}

The running results are as follows:
Insert image description here
It means that the function also has an address. The function name and & (function name) can get the function address.

Function pointer type analysis

int       (*pf3) 			(int x, int y)
 | 			| 				------------ 
 | 			| 					|
 | 			| 					pf3指向函数的参数类型和个数的交代
 | 			函数指针变量名
 pf3指向函数的返回类型
 
int (*) (int x, int y) //pf3函数指针变量的类型

5.2 Callback function

When talking about function pointers, we have to mention the callback function. What is the callback function?

A callback function is a function called through a function pointer.

If you pass a function pointer (address) as a parameter to another function, when this pointer is used to call the function it points to,function calledIt's the callback function. The callback function is not called directly by the implementer of the function, but is called by another party when a specific event or condition occurs to respond to the event or condition.

Let's take an example to understand:
Now we need to write a calculator program to implement the addition, subtraction, multiplication and division operations of two integer numbers.
Please add image description

Use the function pointer to pass the address of the called function in the form of a parameter, and use the function pointer to receive it. The function pointed to by the function pointer is called. What is actually used here is the function of the callback function.

5.3 Transfer table

Implementation of function pointer array; transfer table
The related content of pointer array has been introduced before, so it is easy to understand here. The function pointer array is an array. Each element in the array is a function pointer. Each element in the array stores is the address of a function.

The above calculator program can be further optimized using an array of function pointers:

#include <stdio.h>

int Add(int a, int b)
{
    
    
	return a + b;
}

int Sub(int a, int b)
{
    
    
	return a - b;
}

int Mul(int a, int b)
{
    
    
	return a * b;
}

int Div(int a, int b)
{
    
    
	return a / b;
}

int main()
{
    
    
	int input = 0;
	int ret = 0;
	int a = 0;
	int b = 0;
	//初始化一个函数指针数组,5个元素
	int (*p[5])(int, int) = {
    
    0,Add,Sub,Mul,Div}; //这里加入一个元素0,是为了使数组下标和选择匹配
	do
	{
    
    
		printf("*****************************\n");
		printf("******* 1. Add   2.Sub ******\n");
		printf("******* 3.Mul    4.Div ******\n");
		printf("******* 0.Exit (退出)  ******\n");
		printf("*****************************\n");

		printf("请选择你要使用的运算法则:");
		scanf("%d", &input);

		if ((input <= 4 && input >= 1))
		{
    
    
			printf("输入操作数:");
			scanf("%d %d", &a, &b);
			ret = (*p[input])(a, b);
			printf("ret = %d\n", ret);
		}
		else if (input == 0)
		{
    
    
			printf("退出计算器\n");
		}
		else
		{
    
    
			printf("输入有误\n");
		}
	} while (input);

	return 0;
}

6. Second-level pointers and multi-level pointers

A secondary pointer is a pointer-to-pointer, which is typically used to handle pointer-to-pointer variables. For example, if you have a pointer to an integer and you want to store the address of that pointer through a pointer, then you need to use a secondary pointer.

Multilevel pointers are pointers to pointers that can have multiple levels and are usually used to handle pointer variables that point to pointers. For example, if you have a first-level pointer to an integer and you want to store the address of that pointer in a pointer, then you need to use a second-level pointer. Similarly, if you have a first-level pointer that points to a second-level pointer, and you want to store the address of the first-level pointer through a pointer, then you need to use a third-level pointer. By analogy, there can be multiple levels of pointers.

When solving multi-level pointer problems, it is recommended to draw more memory layout diagrams to understand where the pointer points and what it contains! ! !

Multi-level pointers are generally not commonly used. I will add more later if I come across examples.

Guess you like

Origin blog.csdn.net/yjagks/article/details/132676213