C-Sprache – erweiterte Zeiger

Wir haben das Thema Zeiger bereits im Kapitel „Zeiger“ im ersten Schritt angesprochen. Wir kennen das Konzept der Zeiger:
1. Ein Zeiger ist eine Variable, die zum Speichern von Adressen verwendet wird. Die Adresse identifiziert eindeutig einen Speicherplatz.
2. Die Größe des Fingers ist festgelegt 4/8 Sonderwert ( Iheidai). /64Iheidai 32
3. Zeiger haben Typen und der Typ des Zeigers bestimmt die +- Ganzzahl des Zeigers Schrittgröße, Erlaubnis während der Zeiger-Dereferenzierungsoperation.
4. Zeigeroperationen.
5. Speichereinheiten sind nummeriert, Zahl == Adresse == Zeiger

Als nächstes lernen wir fortgeschrittenere Inhalte über Zeiger.

Inhaltsverzeichnis

 1. Zeichenzeiger

2. Zeiger-Array  

 3. Array-Zeiger

3.1 Definition des Array-Zeigers

3.2 &Array-Name vs. Array-Name

 3.3 Verwendung von Array-Zeigern

 4. Array-Parameter, Zeigerparameter

 4.1 Eindimensionale Array-Parameterübertragung

4.3 Übergabe von Zeigerparametern der ersten Ebene

 4.4 Übergabe von Zeigerparametern der zweiten Ebene

5. Funktionszeiger

Lesen Sie zwei interessante Codeteile:


 1. Zeichen Fingerspitze

Unter den Zeigertypen wissen wir, dass es einen Zeigertyp namens „character pointer char*“ ; gibt

Allgemeine Verwendung :
int main()
{
    char ch = 'w';
    char *pc = &ch;
    *pc = 'w';
    return 0;
}
Eine andere Möglichkeit, es zu verwenden, ist wie folgt:
int main()
{
    const char* pstr = "abcdef";//这里是把一个字符串放到pstr指针变量里了吗?
    printf("%s\n", pstr);
    return 0;
}
代码 const char* pstr = "abcdef" ;
ist für uns besonders einfach zu glauben, dass die Zeichenfolge abcdef im Zeichenzeiger pstr platziert ist, aber / Das Wesentliche besteht darin, die Adresse des ersten Zeichens der Zeichenfolge abcdef in einzufügen pstr.  
Der obige Code bedeutet, die Adresse des ersten Zeichens einer konstanten Zeichenfolge h in der Zeigervariablen zu speichern pstr .
Dann gibt es Interviewfragen wie diese:

#include <stdio.h>
int main()
{
	char str1[] = "hello bit.";
	char str2[] = "hello bit.";
	const char* str3 = "hello bit.";
	const char* str4 = "hello bit.";
	if (str1 == str2)
		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;
}
Die endgültige Ausgabe hier ist:

Hier zeigen str3 und str4 auf ein Die gleiche konstante Zeichenfolge . C/C++ speichert die konstante Zeichenfolge in einem separaten Speicherbereich. Wenn mehrere Zeiger auf dasselbe zeigen. Wenn sie eine Zeichenfolge sind, verweisen sie tatsächlich auf denselben Speicher. Aber wenn Sie dieselbe konstante Zeichenfolge verwenden, um verschiedene Arrays zu initialisieren, werden unterschiedliche Speicherblöcke zugewiesen. Str1 und str2 sind also unterschiedlich, str3 und str4 sind unterschiedlich.
Wie im Bild gezeigt:

2. Fingerkombination  

Ein Array von Zeigern ist ein Array, in dem jedes Element ein Zeiger ist. Jeder Zeiger kann auf verschiedene Arten von Daten oder Objekten verweisen.

Wie das folgende Formular:

int* arr1[10]; //整形指针的数组
char *arr2[4]; //一级字符指针的数组
char **arr3[5];//二级字符指针的数组

 Sie können ein Array von Zeigern verwenden, um ein zweidimensionales Array zu simulieren:

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };
	        //int*  int*  int*
	//指针数组
	int* arr[] = { arr1, arr2, arr3 };
	int i = 0;

	return 0;
}

Int* arr[] speichert drei Elemente arr1, arr2 und arr3, und der Typ jedes Elements ist int*.

Natürlich kann auf diese Schreibweise wie auf ein zweidimensionales Array zugegriffen werden:

 Sie können auch mehrere Zeichenfolgen auf diese Weise verwalten:

int main()
{
	//指针数组
	char* arr[5] = {"hello", "hehe", "haha", "heihei", "C"};

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

	return 0;
}

Laufergebnisse und Illustrationen:

 3. Anzahl der Finger

3.1 Definition des Array-Zeigers

Sind Array-Zeiger Zeiger? Oder ein Array?
Die Antwort lautet: Zeiger.
Wir kennen bereits:
Ganzzahliger Zeiger: int * pint ; Ein Zeiger, der auf ganzzahlige Daten zeigen kann.
Gleitkommazeiger: float * pf ; Ein Zeiger, der auf Gleitkommadaten zeigen kann.
Der Array-Zeiger sollte sein: ein Zeiger, der auf das Array zeigen kann.

 Welcher der folgenden Codes ist ein Array-Zeiger?

int *p1[10];
int (*p2)[10];
//p1, p2分别是什么?
erklären:
int ( * p )[ ]; 10
Erläuterung: p wird zuerst mit * kombiniert, was darauf hinweist, dass p eine Zeigervariable ist und dann auf ein Array mit 10 Ganzzahlen zeigt. p ist also ein Zeiger, der auf ein Array zeigt, ein sogenannter Array-Zeiger.
Beachten Sie hier: [] hat eine höhere Priorität als *, daher muss () hinzugefügt werden, um sicherzustellen, dass p zuerst mit * kombiniert wird.

3.2 &NummerngruppennameVSNummerngruppenname

Für das folgende Array:
int arr[10];
arr sum &arr Trennung ist es?
Wir wissen, dass arr der Array-Name ist und der Array-Name die Adresse des ersten Elements des Arrays darstellt.
Dann &arr Wie heißt das Array?

 Schauen wir uns einen Code an:

#include <stdio.h>
int main()
{
    int arr[10] = {0};
    printf("%p\n", arr);
    printf("%p\n", &arr);
    return 0;
}
Die Laufergebnisse sind wie folgt:

Der sichtbare Array-Name und die vom Array-Namen & ausgegebene Adresse sind identisch.
Sind die beiden gleich?
Schauen wir uns einen anderen Code an:
#include <stdio.h>
int main()
{
 int arr[10] = { 0 };
 printf("arr = %p\n", arr);
 printf("&arr= %p\n", &arr);
 printf("arr+1 = %p\n", arr+1);
 printf("&arr+1= %p\n", &arr+1);
 return 0;
}

Gemäß dem obigen Code haben wir festgestellt, dass tatsächlich &arr und arr < a i=4>, obwohl der Wert derselbe ist, sollte die Bedeutung unterschiedlich sein.
Eigentlich: &arr repräsentiert die Adresse des Arrays und nicht die Adresse des ersten Elements des Arrays. (Erleben Sie es sorgfältig)
In diesem Beispiel &arr ist der Typ: int(*)[10] < /span> ist ein Array-Zeigertyp
Die Adresse des Arrays +1 , wobei die gesamte Array-Größe übersprungen wird, also &arr+ Der Unterschied zwischen 1 und &arr beträgt 40. a>

 3.3 ​​​​Verwendung von Array-Zeigern

Wie werden Array-Zeiger verwendet?
Da der Array-Zeiger auf ein Array zeigt, sollte die Adresse des Arrays im Array-Zeiger gespeichert werden.
Schauen Sie sich den Code an:
int main()
{

	int arr[10] = { 0 };
	int (*p)[10] = &arr; //p是用来存放数组的地址的,p就是数组指针
	
	char* arr2[5];
	char* (*pc)[5] = &arr2;//pc是用来存放数组的地址的,每个数组的类型为char*
	int (*p)[10] = &arr;

	int arr3[] = { 1,2,3 };
	int (*p3)[3] = &arr3;

	return 0;
}

Im obigen Code warum nicht einfach int (*p)[10] =arr; verwenden?
Das liegt daran, dass die Werte von arr und &arr zwar gleich sind, ihre Bedeutungen jedoch unterschiedlich sind:
*** arr bezieht sich auf It ist die erste Adresse des  ersten Elements dieses Arrays.
*** &arr bezieht sich auf die erste Adresse dieses gesamten Arrays .

Array-Zeiger werden in zweidimensionalen Arrays verwendet:
void print(int (*p)[5], int r, int c)
{
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			printf("%d ", p[i][j]);
		}
		printf("\n");
	}
}

int main()
{
	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
	print(arr, 3, 5);

	return 0;
}
Der Array-Name arr repräsentiert die Adresse des ersten Elements
Aber das erste Element des zweidimensionalen Arrays ist die erste Zeile des zweidimensionalen Arrays
Der hier übergebene arr entspricht also tatsächlich der Adresse der ersten Zeile, die die Adresse des eindimensionalen Arrays ist
kann Array-Zeiger empfangen werden
Nachdem wir etwas über Zeiger-Arrays und Array-Zeiger gelernt haben, schauen wir uns diese gemeinsam an und sehen, was der folgende Code bedeutet:
int arr[5];
int *parr1[10];
int (*parr2)[10];
int (*parr3[10])[5];

erklären:

 

 4. Array-Parameter, Zeigerparameter

Beim Schreiben von Code ist es unvermeidlich, [Array] oder [Zeiger] an eine Funktion zu übergeben. Wie sollten die Parameter der Funktion gestaltet sein?

 4.1 Eindimensionale Array-Parameterübergabe

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

Die oben genannten Schreibmethoden sind alle in Ordnung.

Numerische Parameter und formale Parameter können in Array-Form geschrieben werden.

Der Kern der Array-Parameterübergabe besteht darin, die Adresse des ersten Elements des Arrays zu übergeben.

Array-Parameter können auch in Form von Zeigern übergeben werden

 4.2 Zweidimensionale Zahlenkombination

void test(int arr[3][5])//ok?
{}
void test(int arr[][])//ok?
{}
void test(int arr[][5])//ok?
{}
//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
//这样才方便运算。
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);
}

4.3 Zeigerparameterübergabe der ersten Ebene

#include <stdio.h>
void print(int* p, int sz)
{
	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]);
	//一级指针p,传给函数
	print(p, sz);
	return 0;
}

Verwenden Sie einen Zeiger der ersten Ebene, um Parameter zu übergeben, und einen Zeiger der ersten Ebene, um formale Parameter zu empfangen.

denken:
Welche Parameter kann die Funktion empfangen, wenn der Parameterteil einer Funktion ein Zeiger der ersten Ebene ist?

 4.4 Zeigerparameterübergabe der zweiten Ebene

#include <stdio.h>
void test(int** ptr)
{
	printf("num = %d\n", **ptr);
}
int main()
{
	int n = 10;
	int* p = &n;
	int** pp = &p;
	test(pp);
	test(&p);
	return 0;
}

Sekundärzeiger werden zum Übergeben von Parametern verwendet, und formale Parameter können mithilfe von Sekundärzeigern empfangen werden.

denken:
Welche Parameter kann eine Funktion empfangen, wenn sie ein sekundärer Zeiger ist?

5. Funktionsanzeige

 Erstens ist es ein Zeiger, ein Zeiger auf eine Funktion, und die Adresse der Funktion wird im Speicherplatz gespeichert ;

 Schauen wir uns zunächst den Code an:

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

Hier wissen wir:&Der Funktionsname ist die Adresse der Funktion, und der Funktionsname ist auch die Adresse der Funktion.  

 Die Ausgabe besteht aus zwei Adressen, die die Adressen der Testfunktion sind.

Wenn wir also die Adresse unserer Funktion speichern möchten, wie speichern wir sie?
Schauen wir uns den folgenden Code an:
void test()
{
    printf("hehe\n");
}
//下面pfun1和pfun2哪个有能力存放test函数的地址?
void (*pfun1)();
void *pfun2();
Wenn Sie die Speicheradresse angeben können, benötigen Sie zunächst pfun1 oder pfun2< /span> ist ein Zeiger. Welcher ist also der Zeiger?
die Antwort ist:
  pfun1 kann gespeichert werden. pfun1 wird zuerst mit * kombiniert, was anzeigt, dass pfun1 ein Zeiger ist. Der Zeiger zeigt auf eine Funktion. Die gezeigte Funktion hat keine Parameter und der Rückgabewerttyp ist ungültig. 

 Lassen Sie uns ein Beispiel aufstellen: einfache Summierung

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

	return 0;
}

 Operationsergebnis:

 Als Funktionszeiger ist pf2 auch eine Adresse, und die Funktion selbst ist auch eine Adresse, sodass * in (* pf2) in int ret = (* pf2)(2, 3) natürlich weggelassen werden kann. int ret = pf2(2, 3) ist auch möglich.

Lesen Sie zwei interessante Codeteile:

//代码1
(*(void (*)())0)();
//代码2
void (*signal(int , void(*)(int)))(int);

Code 1: void(*)() ist ein Funktionszeigertyp, *(void (*)())0 ist eine erzwungene Typkonvertierung 0 und 0 wird als Funktionsadresse betrachtet, dann gibt es void(*)() bei die 0-Adresse Eine solche Funktion, daher lautet die Bedeutung dieses Codes: Rufen Sie die Funktion an Adresse 0 auf. Diese Funktion hat keine Parameter und der Rückgabetyp ist ungültig.

Code 2:

 Code2 ist zu komplex, wie kann man ihn vereinfachen:

typedef void(*pfun_t)(int);
pfun_t signal(int, pfun_t);

Geben Sie es ein.

Supongo que te gusta

Origin blog.csdn.net/2301_76618602/article/details/132207177
Recomendado
Clasificación