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 323. 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
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
Lesen Sie zwei interessante Codeteile:
1. Zeichen Fingerspitze
Unter den Zeigertypen wissen wir, dass es einen Zeigertyp namens „character pointer char*“ ; gibt
int main()
{
char ch = 'w';
char *pc = &ch;
*pc = 'w';
return 0;
}
int main()
{
const char* pstr = "abcdef";//这里是把一个字符串放到pstr指针变量里了吗?
printf("%s\n", pstr);
return 0;
}
#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;
}
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分别是什么?
int ( * p )[ ]; 10Erlä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
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;
}
#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-ZeigertypDie 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
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 .
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;
}
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.
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.
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;
}
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.
void test()
{
printf("hehe\n");
}
//下面pfun1和pfun2哪个有能力存放test函数的地址?
void (*pfun1)();
void *pfun2();
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.