C-Sprache – erweiterte Zeiger (2)

Fügen Sie hier eine Bildbeschreibung ein
Als ich mit dem letzten Zeiger fortfuhr, fiel mir ein, dass der Inhalt des Zeigers noch nicht aktualisiert wurde. Heute werde ich den vorherigen Inhalt nachholen. Das letzte Mal haben wir über Funktionszeiger gesprochen und sie zur Implementierung einiger Funktionen verwendet. Heute werden wir darüber sprechen Funktionszeiger. Arrays und andere Inhalte, ohne weitere Umschweife, beginnen wir mit dem heutigen Studium.


Beim Extrahieren von Funktionszeigern aus Funktionszeiger-Arrays extrahieren wir zunächst Zeichenzeiger und Ganzzahlzeiger. Ebenso sind wir möglicherweise noch nicht mit den Funktionszeiger-Arrays vertraut, aber wenn es sich um ein Zeichenzeiger-Array handelt, gibt es auch Ganzzahlzeiger . Arrays von Zeigern klingen für uns vielleicht nicht besonders fremd.
Zuvor möchte ich Ihnen zunächst etwas über Funktionszeiger erzählen. Was sind Funktionszeiger? Funktionszeiger sind eigentlich Zeiger, die zum Speichern der Adresse einer Funktion verwendet werden. Schreiben wir also zuerst eine einfache Funktion und speichern Sie dann ihre Adresse. .

int Add(int x, int y)
{
    
    
	return x + y;
}
int main()
{
    
    
	printf("%p\n", &Add);
	printf("%p\n", Add);

	return 0;
}

Wir können feststellen, dass die beiden gedruckten Adressen dieselbe Adresse sind, was bedeutet, dass die Adresse der Funktion auf beide Arten entnommen werden kann.

Fügen Sie hier eine Bildbeschreibung ein
Hier sehen wir, dass unsere Adressen identisch sind. Wie schreiben wir also ihre Adressen, wenn wir sie speichern möchten?

Lass uns einen Blick darauf werfen

#include<stdio.h>
int Add(int x, int y)
{
    
    
	return x + y;
}
int main()
{
    
    
	printf("%p\n", &Add);
	printf("%p\n", Add);
	int (*pf)(int, int) = &Add;
	return 0;
}

Auf diese Weise können wir die Adresse seiner Funktion schreiben. Dies ist dem Array-Zeiger sehr ähnlich, und die Adresse des herausgenommenen Arrays ist ebenfalls dieselbe.
Da es zu lange dauert, möchte ich Ihnen helfen, sich an unseren Array-Zeiger zu erinnern. Was wir jetzt beispielsweise herausnehmen möchten, ist die Adresse des Arrays. Wie ändern wir die Darstellung? Werfen wir einen Blick darauf.

int main()
{
    
    
	int arr[] = {
    
     1,2,3,4,5,6 };
	int(*pa)[6] = &arr;
	return 0;
}

Was wir hier sehen können, ist der Array-Zeiger, der ein Zeiger auf die Array-Adresse ist. Wir können sehen, dass sein Format tatsächlich dem eines Funktionszeigers ähnelt.
Was nützt also unser Funktionszeiger? Die Antwort ist, dass wir diese Funktion aufrufen können. Schauen wir uns zum Beispiel den Code für unsere Add-Funktion oben an.

int Add(int x, int y)
{
    
    
	return x + y;
}
int main()
{
    
    
	printf("%p\n", &Add);
	printf("%p\n", Add);
	int (*pf)(int, int) = &Add;
	return 0;
}

wir können so schreiben

int Add(int x, int y)
{
    
    
	return x + y;
}
int main()
{
    
    
	printf("%p\n", &Add);
	printf("%p\n", Add);
	int (*pf)(int, int) = &Add;
	int ret = (*pf)(3, 5);
	printf("%d\n", ret);
	return 0;
}

Fügen Sie hier eine Bildbeschreibung ein
Tatsächlich müssen Sie es hier nicht schreiben, was bedeutet, int ret = (*pf)(3, 5);dass es geschrieben werden kann int ret = pf(3, 5);. Tatsächlich sind die Ergebnisse der beiden gleich, oder selbst wenn wir viel hinzufügen, hat dies keinen Einfluss auf unsere Ergebnisse. Nehmen wir eine sehen.

int Add(int x, int y)
{
    
    
	return x + y;
}
int main()
{
    
    
	printf("%p\n", &Add);
	printf("%p\n", Add);
	int (*pf)(int, int) = &Add;
	int ret = (*pf)(3, 5);
	printf("%d\n", ret);
	ret = printf("%d\n", (*********pf)(4, 6));
	return 0;
}

Ich habe so viel geschrieben, hauptsächlich um den Weg für die Zukunft zu ebnen. Lassen Sie uns nun darüber sprechen, was unser Funktionszeiger-
Array ist. Wir haben Zeichenzeiger-Arrays bereits gesehen. Sie werden zum Speichern von Zeichenzeigern verwendet. Wir haben auch über Ganzzahl-Zeiger-Arrays gesprochen. Es wird zum Speichern eines Arrays von Ganzzahlzeigern verwendet. Ebenso wird ein Array von Funktionszeigern zum Speichern von Funktionszeigern verwendet. Lassen Sie uns ein Beispiel geben.


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

int main()
{
    
    
	int (*pf1)(int, int) = &Add;
	int (*pf2)(int, int) = &Sub;
	int (*pf3)(int, int) = &Mul;
	int (*pf4)(int, int) = &Div;
	return 0;
}

Zunächst einmal sehen wir so viele Funktionen. Ihre Funktionen ähneln denen unseres Taschenrechners. Hier schreiben wir nur die Funktionen Addition, Subtraktion, Multiplikation und Division. Durch unseren Code können wir vier identische Funktionszeiger sehen, also können wir das nicht Speichern Sie sie in Form eines Arrays. Weil Arrays nicht mehrere Elemente desselben Typs speichern können.
Dann können wir darüber schreiben

int main()
{
    
    
	int (*pf1)(int, int) = &Add;
	int (*pf2)(int, int) = &Sub;
	int (*pf3)(int, int) = &Mul;
	int (*pf4)(int, int) = &Div;
	int(*pfarr[4])(int, int) = {
    
     &Add,&Sub,&Mul,&Div };
	//pfarr就是存放函数指针的数组
	return 0;
}

Ist das Funktionszeiger-Array nur eine Dekoration? Nein! ! ! Es hat immer noch eine gewisse Wirkung. Was ist also seine Funktion? Werfen wir einen Blick darauf.
Können wir damit einen Taschenrechner implementieren? Lassen Sie uns einen entwerfen.

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  2.Sub ****\n");
	printf("***3.Mul  4.Div ****\n");
	printf("****0.exit      ****\n");
	printf("********************\n");
}
int main()
{
    
    
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;
	do
	{
    
    
		menu();
		printf("请选择>");
		scanf("%d" ,&input);
		switch (input)
		{
    
    
		case 0:
			printf("退出计算器\n");
			break;
		case 1:
			printf("请输入两个操作数 :");
			scanf("%d %d", &x, &y);
			ret = Add(x, y);
			printf("ret = %d\n", ret);
			break;
		case 2:
			printf("请输入两个操作数 :");
			scanf("%d %d", &x, &y);
			ret = Sub(x, y);
			printf("ret = %d\n", ret);
			break;
		case 3:
			printf("请输入两个操作数 :");
			scanf("%d %d", &x, &y);
			ret = Mul(x, y);
			printf("ret = %d\n", ret);
			break;
		case 4:
			printf("请输入两个操作数 :");
			scanf("%d %d", &x, &y);
			ret = Div(x, y);
			printf("ret = %d\n", ret);
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;

}

Obwohl wir einen einfachen Taschenrechner implementieren, sieht unser Code tatsächlich nicht besonders gut aus. Stattdessen ist er etwas redundant und weist viele wiederholte Inhalte auf. Wenn wir außerdem einige andere Operationen hinzufügen, wird die Funktion immer umfangreicher komplexer. Lange, wie sollten wir es dann ändern, damit unser Code gut aussieht und praktisch aussieht? Zu diesem Zeitpunkt können wir das Funktionszeiger-Array verwenden, um Korrekturen vorzunehmen. Jetzt korrigieren wir es.

Wenn wir dies verwenden, müssen wir darauf achten, dass der Typ der Taschenrechnerfunktion derselbe ist, sonst funktionieren die anderen Funktionen nicht.

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  2.Sub ****\n");
	printf("***3.Mul  4.Div ****\n");
	printf("****0.exit      ****\n");
	printf("********************\n");
}
int main()
{
    
    
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;
	do
	{
    
    
		menu();
		printf("请选择>");
		scanf("%d", &input);
		int (*pf[5])(int, int) = {
    
     NULL,Add,Sub,Mul,Div };
		if (input == 0)
		{
    
    
			printf("退出计算器\n");
		}
		else if (input >= 1 && input <= 4)
		{
    
    
			printf("请输入两个操作数 :");
			scanf("%d %d", &x, &y);
			ret = pf[input](x, y);
			printf("%d\n", ret);
		}
	} while (input);
	return 0;

}

Dies kann auch den Effekt unseres Rechners erzielen, und die Vorteile sind ebenfalls sehr groß. Erstens wird die Redundanz unseres Codes gelöst. Zweitens können wir, wenn wir andere Operationen hinzufügen möchten, diese auch direkt hinzufügen. Ändern Sie einfach die Die Größe des Arrays und das Einfügen der Adresse der Funktion können das Problem lösen. Es ist eigentlich sehr einfach. Wir nennen dieses Ding auch eine Übertragungstabelle. Dies ist unsere Funktionsarray-Zeigeranwendung, aber dies ist nur ein Beispiel. Es gibt viele andere Funktionen, daher werden wir hier nicht näher darauf eingehen.

Zeiger auf Array von Funktionszeigern

Als ich diesen Titel sah, wusste ich nicht, ob alle verwirrt waren. Wie auch immer, der Herausgeber war zuerst etwas verwirrt, als ich das sah, aber nach einer gewissen Zeit des Studiums stellte ich fest, dass es das ist. Beginnen wir nun mit Beispielen .

int a = 10;
int b = 20;
int c = 30;
int* arr[] = {
    
     &a,&b,&c };//整型指针数组

Schauen wir uns zunächst die einfachen an und stellen sie dann langsam vor. Zuerst das Integer-Pointer-Array. Wenn es ein solches Problem darstellt, wie sollten wir dann einen Zeiger auf ein Integer-Pointer-Array schreiben?

int* (*parr)[3] = &arr;

Dies ist ein Zeiger auf ein Array von Ganzzahlzeigern. Schauen wir uns aus dem gleichen Grund einen Zeiger auf ein Array von Funktionszeigern an.

int (*pf[5])(int, int) = {
    
     NULL,Add,Sub,Mul,Div };

int(*(*ppf)[5])(int, int) = &pf;

Schreiben wir es mit einem Taschenrechner und es wird so aussehen.
Tatsächlich müssen Sie dies jedoch nicht zu tief verstehen. Sie werden es nach ein wenig Verständnis erkennen. Es ist nicht besonders wichtig.

Ruf zurück

Eine Callback-Funktion ist eine Funktion, die über einen Funktionszeiger aufgerufen wird. Wenn Sie einen Funktionszeiger (Adresse) als Parameter an eine andere
Funktion übergeben und dieser Zeiger zum Aufrufen der Funktion verwendet wird, auf die er zeigt, sprechen wir von einer Callback-Funktion. Die Rückruffunktion wird nicht
direkt von der implementierenden Partei der Funktion aufgerufen, sondern von einer anderen Partei, wenn ein bestimmtes Ereignis oder eine bestimmte Bedingung eintritt, um auf das Ereignis oder die Bedingung zu reagieren
.

Was bedeutet das? Angenommen, wir haben zwei Funktionen, eine namens A und eine namens B. Der Parameter unserer B-Funktion ist die Adresse der A-Funktion. Wir verwenden diese Funktion A in der B-Funktion.
Heute werde ich über ein Beispiel sprechen, es ist immer noch unser Rechner, und das nächste Mal werde ich über qsort sprechen, das auch Schnellsortierung genannt wird, damit jeder unseren Inhalt besser verstehen kann.

Nehmen wir zunächst unseren Taschenrechner heraus und zeigen ihn allen.

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  2.Sub ****\n");
	printf("***3.Mul  4.Div ****\n");
	printf("****0.exit      ****\n");
	printf("********************\n");
}
int main()
{
    
    
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;
	do
	{
    
    
		menu();
		printf("请选择>");
		scanf("%d" ,&input);
		switch (input)
		{
    
    
		case 0:
			printf("退出计算器\n");
			break;
		case 1:
			printf("请输入两个操作数 :");
			scanf("%d %d", &x, &y);
			ret = Add(x, y);
			printf("ret = %d\n", ret);
			break;
		case 2:
			printf("请输入两个操作数 :");
			scanf("%d %d", &x, &y);
			ret = Sub(x, y);
			printf("ret = %d\n", ret);
			break;
		case 3:
			printf("请输入两个操作数 :");
			scanf("%d %d", &x, &y);
			ret = Mul(x, y);
			printf("ret = %d\n", ret);
			break;
		case 4:
			printf("请输入两个操作数 :");
			scanf("%d %d", &x, &y);
			ret = Div(x, y);
			printf("ret = %d\n", ret);
			break;
		default:
			break;
		}
	} while (input);
	return 0;

}

Wir können dies implementieren, indem wir denselben Teil, also die Case-Anweisung, in eine Funktion aufteilen.

Wir können sehen, wo sich unser Code unterscheidet, nämlich dort, wo wir Funktionen aufrufen. Wenn wir eine Funktionsberechnung schreiben können, um die Adressen dieser Funktionen zu speichern, wird das Problem dann gelöst? Es ist tatsächlich so geschrieben.

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  2.Sub ****\n");
	printf("***3.Mul  4.Div ****\n");
	printf("****0.exit      ****\n");
	printf("********************\n");
}
int main()
{
    
    
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;
	do
	{
    
    
		menu();
		printf("请选择>");
		scanf("%d" ,&input);
		switch (input)
		{
    
    
		case 0:
			printf("退出计算器\n");
			break;
		case 1:
			calc(Add);
			break;
		case 2:
			calc(Sub);
			break;
		case 3:
			calc(Mul);
			break;
		case 4:
			calc(Div);
			break;
		default:
			break;
		}
	} while (input);
	return 0;

}

Was wir jetzt tun müssen, ist, unsere Berechnungsfunktion zu vervollständigen, damit wir die Funktion des Taschenrechners realisieren können

Der Rückgabetyp von calc ist die Adresse der void-Funktion. Wir können ihn also wie folgt schreiben int (*pf)(int,int):


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  2.Sub ****\n");
	printf("***3.Mul  4.Div ****\n");
	printf("****0.exit      ****\n");
	printf("********************\n");
}

void calc(int (*pf)(int, int))
{
    
    
	int x = 0;
	int y = 0;
	int ret = 0;
	printf("请输入两个操作数 :");
	scanf("%d %d", &x, &y);
	ret = pf(x, y);
	printf("ret = %d\n", ret);
}
int main()
{
    
    
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;
	do
	{
    
    
		menu();
		printf("请选择>");
		scanf("%d", &input);
		switch (input)
		{
    
    
		case 0:
			printf("退出计算器\n");
			break;
		case 1:
			calc(Add);
			break;
		case 2:
			calc(Sub);
			break;
		case 3:
			calc(Mul);
			break;
		case 4:
			calc(Div);
			break;
		default:
			break;
		}
	} while (input);
	return 0;

}

Auf diese Weise werden auch die bisherigen Funktionen realisiert. Wir werden später über qsort sprechen. Ich bin zu faul, heute darüber zu sprechen. Es ist zu chaotisch.

Bis zum nächsten Mal, tschüss

おすすめ

転載: blog.csdn.net/2301_76895050/article/details/132729442