"C and Pointers" Reading Notes (Chapter 13 Advanced Pointer Topics)

0 Introduction

As we all know, pointers are the soul of the C language, so this book ( "C and Pointers" ) will devote more ink to topics related to pointers . In this chapter we will see more applications of pointers and better explain them. The unique charm of C language.

Overview of the contents of this issue:
Insert image description here

1 Further exploration of pointers to pointers

If you learn pointers, it is not difficult to understand pointers to pointers. That is to say, there is a pointer in the address pointed by the current pointer, and the address pointed by the pointer holds the value we need to access.

You can verify it with a simple example:

#include <stdio.h>
int main()
{
    
    
	int i = 10;
	int *pi = &i;
	int **ppi = &pi;
	printf("i = %d\n",i);
	printf("*pi = %d\n", *pi);
	printf("**ppi = %d\n", **ppi);
}

Run, print output:
Insert image description here

It can be seen that the results are consistent with our expectations.

2 Advanced Statement

The book lists some advanced pointer declaration issues. Unless you want to understand them all, you only need to read the rest of the book, because the specific declaration methods have been listed in the rest of the book. This part just has a deeper explanation.

3 function pointer

Function pointers, as the name suggests, are pointers to functions. In essence, they are not much different from ordinary pointers. They just have some differences in form and are more interesting in usage.

3.1 Callback function

In layman's terms, a callback function passes a function pointer as a parameter to other functions, which will "call back" the user's function. A function that is passed as a parameter is calledCallback

There is this description in the book:

You can use this technique any time you write a function that must be able to perform different types of work at different times or perform work that can only be defined by the caller of the function. Many windowing systems use callback functions to connect multiple actions, such as dragging the mouse and clicking a button, to specify a specific function in the user's program.

It sounds a bit convoluted, but specifically, when we have set up an interface (function), but a certain part we need cannot be predicted in advance, at this time we need to call back our later functions to perform specific tasks, and That is to say, the specific implementation needs to be considered based on the specific situation.

For example, in the C language stdliblibrary, a function that implements the quick sort algorithm is encapsulated qsort. When calling, we need to write the sorting function ourselves.

Quick sortIt is a very classic and common sorting algorithm. If you are interested in the specific implementation principles of sorting algorithms, please go to:
Top Ten Classic Sorting Algorithms (implemented in C language)
for a very detailed explanation.

Let’s first implement a simple array sorting,

	int a[] = {
    
    1,3,5,11,2};
	qsort(a, 5, sizeof(int), compare);

	for (int i = 0; i < 5; i++)
	{
    
    
		printf("a[%d] is %d\n", i, a[i]);
	}

The comparison function is implemented like this,

int compare(const void  *a, const void *b)
{
    
    
	int *p1 = (int *)a, *p2 = (int *)b;
	if (*p1 > *p2)
	{
    
    
		return 1;
	}
	else if (*p1 == *p2)
	{
    
    
		return 0;
	}
	else if (*p1 < *p2)
	{
    
    
		return -1;
	}
}

Now that the sorting function has been encapsulated, why not also write the comparison function for us?

This is because the sorting function cannot predict in advance the data type we need to compare. Is it an integer, a floating point type, or a structure member? So we need to complete the comparison function ourselves to achieve sorting. The examples given in the book are just like this. Of course, the application of callback functions goes far beyond that.

3.2 Transfer table

The transfer table (or conversion table) is an array of function pointers . In this way, calling functions of the same type becomes very simple, and the related functions can be found directly through the array subscript.

Suppose we need to design a small calculator (that can perform addition, subtraction, multiplication and division calculations). If we use the traditional method, we will write a program like this:

enum OPER
{
    
    
	ADD = 1,
	SUB,
	MUL,
	DIV
};

double cal_add(double a, double b)
{
    
    
	return a + b;
}
double cal_sub(double a, double b)
{
    
    
	return a - b;
}
double cal_mul(double a, double b)
{
    
    
	return a * b;
}
double cal_div(double a, double b)
{
    
    
	return a / b;
}
//使用传统方法
//使用传统方法
double cal_all_1(int oper, double op1, double op2)
{
    
    
	double result = 0;
	switch (oper)
	{
    
    
	case ADD: result = cal_add(op1, op2); break;
	case SUB: result = cal_sub(op1, op2); break;
	case MUL: result = cal_mul(op1, op2); break;
	case DIV: result = cal_div(op1, op2); break;
	default:
		break;
	}
	return result;
}

Now we implement the same functionality using a transfer table:

First define the following transfer table

double(*oper_func[])(double, double) = {
    
     cal_add, cal_sub, cal_mul, cal_div };

Now the execution function of the algorithm becomes like this:

//使用函数指针数组
double cal_all_2(int oper, double op1, double op2)
{
    
    
	double result = 0;
	if (oper <= 4)
		result = oper_func[oper - 1](op1, op2);
	else
		exit();
	return result;
}

Obviously, the second method is much simpler. If you want to perform related operations, you only need to index through the array subscript, and then pass in the actual parameters. Let's look at the writing of the main function:

#include <stdio.h>
#include <stdlib.h>
#include "transfor_table.h"

int main()
{
    
    
	double res1 = 0,res2 = 0;
	
	res1 = cal_all_1(ADD, 10, 10);
	printf("fun_1:10 + 10 = %f\n", res1);

	res2 = cal_all_2(ADD, 10, 10);
	printf("fun_2:10 + 10 = %f\n", res2);

	system("pause");
	return 0;
}

Execute and print the following content:
Insert image description here

It can be found that the two executions produce the same results, but this kind of test is not rigorous and requires more test cases to support it. In order to illustrate the problem, here is just a simple comparison.

Note: Do not write the division function as in the book (that is, div()). This will conflict with the function naming in the C language library, causing a compilation error and prompting for renaming.

4 Command line parameters

In some C programs, mainthe function is special and accepts two parameters, like the following

int main(int argc, char **argv)

These two formal parameters accept the parameters passed from the command line!

4.1 Passing command line parameters

In the above main function, the first parameter is called argc, which represents the number of command line parameters, and the second parameter is called argv, which points to a set of parameter values ​​(estimated to be the abbreviation of and argument counter) argument vector.

Compiling and running this program is a little more troublesome. For specific operation methods, please refer to VS using the Developer Command Prompt command line to compile and execute C++ code.

For example, write the following program:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
    
    
	printf("%d\n", argc);
	while(*++argv != NULL)
		printf("%s\n", *argv);
	return EXIT_SUCCESS;
}

4.2 Processing command line parameters

Compile and run the above program, the output is as follows:
Insert image description here
The first parameter automatically counts the number of string parameters we input, and it is displayed 3. Should we click Enter to count one? Then the content we entered is printed correctly.

5 String constants

A simple string also represents a pointer to its first element. This can be compared with an array, except that an array is an array name. Let’s look at an example first:

void string_basic()
{
    
    
	printf("%c\n",*("xyz" + 1));
	printf("%c\n", "xyz"[2]);
}


Insert image description here
If the printout "xyz"is a pointer to the first element, it +1means moving the address of one element backward, and then indirectly accessing it to get the second element y.

Of course, similar to arrays, strings can also access elements through subscripts, so that characters can be obtained naturally z.


In addition, the book gives amystery function, but the answer has not been revealed, what is the function of this mysterious function. Lets come look.
The function is defined as follows:

//参数是一个0~100的值
void mystery(int n)
{
    
    
	n += 5;
	n /= 10;
	printf("%s\n", "**********" + 10 - n);
}

The first two statements are easy to understand. They are to round an integer and then find the tens value. The last printfstatement requires understanding of string constants. After analysis, the number of * signs printed out is the value in the tens digit just calculated. You can do an experiment:

	for(int i = 0; i < 10; i++)
		mystery(i*10);

Then print the output:
Insert image description here
If it is not an integer multiple of 10, you can also get similar output, and the processing methods are the same.


The last part of the book adds another example to convert a binary value into a string. Let’s take a look:

void binary_to_ascii(unsigned int value)
{
    
    
	unsigned int quotient;
	quotient = value / 10;
	if (quotient != 0)
		binary_to_ascii(quotient);
	putchar(value % 10 + '0');
}

Note that recursion is used here, which is not difficult to understand. It is called like this in the main function:

	binary_to_ascii(1001100);

Printout:
Insert image description here
It can be seen that there is no problem with our algorithm.

The book then gives a method for converting a certain hexadecimal digit into a string:

	putchar("0123456789ABCDEF"[value % 16]);

Similarly, we can follow the above example and write a function that converts hexadecimal numbers into strings:

void hexadecimal_to_ascii(unsigned int value)
{
    
    
	unsigned int quotient;
	quotient = value / 16;
	if (quotient != 0)
		hexadecimal_to_ascii(quotient);
	putchar("0123456789ABCDEF"[value % 16]);
}

Then call it in the main function:

	hexadecimal_to_ascii(0xF5);

Printout:
Insert image description here
As you can see, we got the correct answer!

6 Summary

Callback functions and transfer tables are not just about understanding their working process and main ideas, but more importantly, knowing how to use them in actual development.

If an execution environment implements command line parameters, these parameters are passed to the main function through two formal parameters. These two formal parameters are usually called argcsum argv.

Further reading: Pointer functions and function pointers

Guess you like

Origin blog.csdn.net/weixin_43719763/article/details/132442403