[C Avancé] Pointeur (1)

Bonjour à tous, je suis un poisson profond~

[Préface]:

Le sujet des pointeurs a déjà été abordé dans le chapitre des pointeurs élémentaires. On connaît la notion de pointeurs :

1. Le pointeur est une variable, utilisée pour stocker l'adresse, l'adresse identifie de manière unique un morceau d'espace mémoire (variable de pointeur), l'unité de mémoire est numérotée, numéro == adresse == pointeur

2. La taille de la variable pointeur/adresse/pointeur est fixée à 4/8 octets (plateforme 32 bits/plateforme 64 bits)

3. Le pointeur a un type, et le type du pointeur détermine la taille de pas de l'entier +- du pointeur et l'autorité de l'opération de déréférencement du pointeur

4. Opérations de pointeur 


【Table des matières】

1. Pointeur de personnage

 2. Tableau de pointeurs

  3. Pointeur de tableau

3.1 Définition du pointeur de tableau

3.2& nom du tableau vs nom du tableau 

3.3 Utilisation de pointeurs de tableau

Quatre, paramètres de tableau, paramètres de pointeur

4.1 Passage des paramètres d'un tableau unidimensionnel

4.2 Passage des paramètres d'un tableau bidimensionnel

 4.3 Passage des paramètres du pointeur de niveau 1

4.4 Passage des paramètres du pointeur de deuxième niveau

Cinq, pointeur de fonction


1. Pointeur de personnage

Usage général:

#include<stdio.h>
int main()
{
	char ch = 'w';
	char* pc = &ch;
	*pc = 'w';
	return 0;
}

Une autre façon de l'utiliser est la suivante :

#include<stdio.h>
int main()
{
	char ch = 'w';
	char* p = "abcdef";
		   //[abcdef\0]
		  //char arr[]="abcdef"
    printf("%s\n,p);//打印的是整个字符串
    printf("%c\n,*p);//打印的是a
	printf("%c\n", "abcdef"[3]);//打印的是d
	return 0;
}

La chaîne "abcdef" ici est similaire à un tableau , attribuez cette chaîne au pointeur p, c'est-à-dire attribuez la première adresse de la chaîne au pointeur p

(En supposant une plate-forme 32 bits, la taille du pointeur est de 4 octets, mais cette chaîne a 7 octets (en comptant \0), elle ne peut donc pas tenir)

Mais il y a un problème avec ce code, la variable p est affectée à une chaîne constante, si vous changez la variable p, la chaîne constante ne changera pas

Par exemple : ce code est facile à commettre des erreurs, il est donc généralement écrit const avant char *p

char* p = "abcdef";
 *p = 'e';

Une manière plus sûre d'écrire :

const char* p = "abcdef";

 Jetons un coup d'œil à une autre [question d'entretien classique] :

Quel est le résultat de cette question ?

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

【Répondre】:

str1 et str2 ne sont pas identiques
str3 et str4 sont identiques

【expliquer】:

(1) Créez d'abord deux tableaux et placez-les respectivement dans hello bit . Puisqu'il s'agit de deux tableaux différents, les chaînes ont des positions différentes. En jugeant str1 et str2, qui sont les premières adresses des deux tableaux, les deux h adresses sont certainement pas pareil

(2) Les pointeurs str3 et str4 pointent vers des chaînes constantes, car les chaînes constantes ne peuvent pas être modifiées, il n'est donc pas nécessaire de créer un autre espace pour stocker deux chaînes constantes identiques , si deux pointeurs pointent vers cette chaîne constante en même temps. temps, il pointe en fait vers la même adresse, donc str3 et str4 sont également identiques


[Extension] : ajoutez-en un autre

si(&str3==&str4)

         printf("OUI\n");

autre

         printf("NON\n");

[Réponse] : NON

[Illustration] : Différentes variables de pointeur ont des adresses différentes

p (variable pointeur) : Indique l'adresse mémoire pointée par la variable pointeur

&p : Prendre l'adresse du pointeur p, indiquant l'adresse mémoire allouée par le compilateur pour la variable p (les adresses allouées par les différentes variables sont différentes), pas l'adresse pointée par le pointeur p


 2. Tableau de pointeurs

Les tableaux de pointeurs sont des tableaux

tableau de caractères - un tableau de caractères

Tableau d'entiers - un tableau d'entiers

Tableau de pointeurs : un tableau qui stocke des pointeurs et les éléments stockés dans le tableau sont tous des types de pointeurs

par exemple : int *arr[5] ; //Array stockant des pointeurs entiers

        char * ch[6]; //Tableau stockant les pointeurs de caractères

[Alors comment utiliser le tableau de pointeurs ?

Généralement non utilisé comme ceci : int *arr[3]={&a, &b, &c}

Utilisez-le plutôt comme ceci : vous pouvez simuler un tableau à deux dimensions avec un tableau de pointeurs.

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 };
    for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 5; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

[Illustration] : placez le tableau de pointeurs en trois tableaux, le type de ces trois tableaux est de type int * pointeur, et le tableau bidimensionnel peut être simulé en imprimant le tableau de pointeurs

【Résultat du programme】: 


  Autre châtaigne : créez un tableau de pointeurs de type caractère (int *) et imprimez les éléments du tableau

#include<stdio.h>
int main()
{
	char* arr[5] = { "hello bit","hehe","penggeC","bitejiuyeke","C++" };
	for (int i = 0; i < 5; i++)
	{
		printf("%s\n", arr[i]);
	}
	return 0;
}

[Illustration] : Passez l'adresse du premier élément de la chaîne au pointeur, puis placez ces pointeurs dans le tableau

【Résultat du programme】:


  3. Pointeur de tableau

3.1 Définition du pointeur de tableau

Les pointeurs de tableau sont des pointeurs , saisis dans des pointeurs de caractères (pointeurs vers des caractères), des pointeurs entiers (pointeurs vers des entiers) et des pointeurs à virgule flottante (pointeurs vers des types à virgule flottante), donc les pointeurs de tableau sont des pointeurs vers des tableaux

int a=10 ; int *p=&a; (pointeur entier)

char ch='a'; char *pc=&ch; (pointeur de caractère)

int arr[10];  int (*p)[10]=&arr ; (pointeur de tableau)

Comprenons int(*p)[10] :

Le * in int (*p) [10] signifie que p est un pointeur, *p pointe vers [10] signifie un pointeur vers un tableau et int signifie le type d'élément du tableau

【Avis】:

Vous ne pouvez pas définir directement un pointeur p, puis attribuer &arr à p. &arr est l'adresse de l'ensemble du tableau, et le type de &arr est int (*) [10], tandis que le type de pointeur p est int *, ce qui est n'est pas égal, donc &arr doit être placé dans le pointeur du tableau 

3.2& nom du tableau vs nom du tableau 

Tout d'abord, la compréhension du nom du tableau :

Le nom du tableau est l'adresse du premier élément à deux exceptions près :

1. sizeof (nom du tableau) , où le nom du tableau représente l'ensemble du tableau et le calcul est la taille de l'ensemble du tableau, en octets

2. &Nom du tableau , où le nom du tableau représente l'intégralité du tableau et l'adresse du tableau est supprimée

int main()
{
	int arr[10];

	printf("%p\n", arr);//int *
	printf("%p\n", arr+1);

	printf("%p\n", &arr[0]);//int *
	printf("%p\n", &arr[0]+1);

	printf("%p\n", &arr);//int *[10]这就是数组指针的类型
	printf("%p\n", &arr+1);
	//指针类型决定了指针+1到底+几个字节
	return 0

[Remarque] : le 10 ici ne peut pas être omis et le pointeur de tableau doit spécifier le nombre d'éléments sur lesquels le pointeur pointe.

 【pratique】:

Pointeur de tableau de char* arr2[5] : char* (*p)[5] (le char* précédent est un type de tableau)

int arr3[]={1,2,3} pointeur de tableau : int (*p)[3] (le pointeur de tableau doit clairement pointer vers la taille du tableau, ce 3 doit être écrit)

3.3 Utilisation de pointeurs de tableau

Voyons d'abord comment imprimer des éléments de tableau avec des pointeurs de tableau : c'est en fait superflu. Vous pouvez imprimer des éléments de tableau directement dans arr, mais vous devez définir un pointeur de tableau, puis utiliser le pointeur de tableau pour imprimer les éléments de tableau.

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9 };
	int(*p)[10] = &arr;

	for (int i = 0; i < 10; i++)
	{
		printf("%d ", (*p)[i]);
	}

	return 0;
}

 [Alors que se passe-t-il si le contenu imprimé est remplacé par p[i] ?

p[i] est équivalent à *(p+i) , et le pointeur +1 saute directement une adresse de tableau, et il est impossible d'imprimer les éléments du tableau

Passez directement le nom du tableau au pointeur p pour que les éléments du tableau soient accessibles : int *p=arr 

Le résultat de l'exécution du code :


  [ Alors, à quoi servent les pointeurs de tableau ?

Les pointeurs de tableau sont utilisés dans les tableaux bidimensionnels, regardons un exemple : imprimer un tableau bidimensionnel


La méthode normale : le paramètre formel utilise la forme d'un tableau à deux dimensions

#include<stdio.h>
void print(int arr[3][5], int row, int col)
{
	for (int i = 0; i < 3;i++)
	{
		for (int j = 0; j < 5; j++)
		{
			printf("%d ", arr[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;
}

 La méthode du pointeur de tableau : le paramètre formel utilise la forme du pointeur de tableau

(1) Premièrement, le nom du tableau est l'adresse du premier élément. Dans un tableau à deux dimensions, l'adresse du premier élément est l'adresse de la première ligne d'éléments du tableau.

(2) Le paramètre formel int (*p)[5] signifie : ce pointeur de tableau pointe vers l'adresse des 5 éléments de la première ligne du tableau

(3) p[i][j] représente : p[i] est équivalent à *(p+i), l'adresse de chaque ligne, après déréférencement est le nom du tableau de chaque ligne, le nom du tableau de chaque ligne [j ], Vous pouvez obtenir les éléments du tableau de chaque ligne

#include<stdio.h>
void print(int (*p)[5], int row, int col)
{
	for (int i = 0; i < 3;i++)
	{
		for (int 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;
}

Après avoir appris le tableau de pointeurs et le pointeur de tableau, passons en revue et voyons la signification du code suivant : 

int arr[5];
int *parr1[10];
int (*parr2)[10];
int (*parr3[10])[5];

<1>arr est un tableau pouvant stocker 5 données entières

<2>parr1 est un tableau de 10 éléments, et le type de chaque élément est int *

<3>parr2 est un pointeur qui pointe vers un tableau, et le tableau pointé a 10 éléments, et le type de chaque élément est int

<4>parr3 est un tableau qui stocke les pointeurs de tableau (ce tableau parr3 [10] a 10 éléments), stocke les pointeurs de tableau (int (*) [5], et le tableau pointé a 5 éléments, chaque élément est de type int (ce c'est plus difficile, ce n'est pas grave si tu ne comprends pas)

Pour comprendre 4 dessins : parr3 est un tableau de 10 éléments, chaque élément est une adresse (pointeur de tableau), et le type de chaque élément est int (*) [5], et le pointeur de tableau stocké dans le tableau correspondant, ce pointeur à un tableau de 5 éléments


Quatre, paramètres de tableau, paramètres de pointeur

Lors de l'écriture de code, il est inévitable de passer [array] ou [pointer] à la fonction, alors comment concevoir les paramètres de la fonction ?

4.1 Passage des paramètres d'un tableau unidimensionnel

Paramètres du tableau, les paramètres formels peuvent être écrits sous forme de tableaux ou de pointeurs , l'essence du passage des paramètres est de transmettre l'adresse du premier élément du tableau

Les 6 façons suivantes de passer des paramètres sont toutes possibles

#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,数组的形式传参,可以省略数组的元素个数
{}
void test2(int** arr)//ok,指针的形式传参
{}
int main()
{
	int arr[10] = { 0 };
	int* arr2[20] = { 0 };//指针数组
	test(arr);
	test2(arr2);
}

Pour dernière compréhension : le type de chaque élément de arr2 est int *, et arr2 doit prendre la première adresse de l'élément int * et l'adresse d'un pointeur, puis le mettre dans le pointeur secondaire


4.2 Passage des paramètres d'un tableau bidimensionnel

void test(int arr[3][5])//ok
{}
void test(int arr[][])//no,二维数组只能省略行,不可省略列
{}
void test(int arr[][5])//ok
{}
void test(int* arr)//no,二维数组首元素地址是第一行的地址,所以指针传参不能省略列
{}
void test(int* arr[5])//no,这是一个指针数组,而不是本来的二维数组
{}
void test(int(*arr)[5])//ok,数组指针,指针指向数组,数组中有5个元素
{}
void test(int** arr)//no,二级指针是用来接收一级指针的地址,而我们只需要第一行数组的地址,一级指针即可
{}
int main()
{
	int arr[3][5] = { 0 };
	test(arr);
}

Passage des paramètres du tableau à deux dimensions :

<1> Passer des paramètres sous forme de tableau : seules les lignes peuvent être omises, les colonnes ne peuvent pas être omises

<2> Passer des paramètres sous forme de pointeur : la forme du paramètre doit être un tableau pointeur int (*arr) [colonne], pas un tableau de pointeurs

 4.3 Passage des paramètres du pointeur de niveau 1

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

Le paramètre de pointeur de premier niveau passant le paramètre formel peut être écrit comme un pointeur de premier niveau


【pense】:

Lorsque la partie paramètre d’une fonction est un pointeur de premier niveau, quels paramètres la fonction peut-elle recevoir ?

(1) Transmettez le nom du tableau du tableau unidimensionnel

(2) Transférer l'adresse de la variable

(3) passer le pointeur

4.4 Passage des paramètres du pointeur de deuxième niveau

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

Le paramètre formel du paramètre de pointeur de deuxième niveau peut être écrit comme l'adresse du pointeur de deuxième niveau ou du pointeur de premier niveau.

【pense】:

Lorsque le paramètre de la fonction est un pointeur secondaire, quels paramètres peut-il recevoir ?

(1) L'adresse du pointeur de premier niveau

(2) Pointeur secondaire

(3) passer un tableau de pointeurs (l'adresse du premier élément)

Cinq, pointeur de fonction

analogie:

Pointeur de tableau - un pointeur vers un tableau - stocke l'adresse du tableau - et le nom du tableau est l'adresse du tableau

Pointeur de fonction - pointeur vers la fonction - stocke l'adresse de la fonction - alors comment obtenir l'adresse de la fonction

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	//&函数名就是函数的地址
	//函数名也是函数的地址

	printf("%p\n", &Add);
	printf("%p\n", Add);

	int (*pf1)(int, int) = Add;//pf1就是函数指针变量
	int (*pf2)(int, int) = &Add;

	return 0;
}

&Le nom de la fonction est l'adresse de la fonction, et le nom de la fonction est également l'adresse de la fonction

int (*pf1)(int, int) = Ajouter Les crochets ici ne peuvent pas être omis, sinon la partie précédente est la même que la déclaration de fonction 

Ajouter et ajouter à l'aide de pointeurs de fonction :

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int (*pf2)(int, int) = &Add;
  //int (*pf2)(int, int) = Add;这样写也可以
	int ret = (*pf2)(2, 3);
  //int ret = pf2(2, 3);不用*也可以,但是用了*一定得加括号
  //int ret = *pf2(2, 3);这个就相当于*5
	printf("%d\n", ret);

	return 0;
}

  Lisez deux morceaux de code intéressants :

(* ( vide ( * )( ) ) 0 )( ) ;

(1) void (*) () est un type de pointeur de fonction

(2) (type) constante - conversion de type forcée - par exemple : int a=(int )3.14 

(3) Le coloré consiste à convertir 0 en un type de pointeur de fonction, ce 0 devient une adresse (adresse), puis appelle la fonction à l'adresse de 0, cette fonction n'a pas de paramètres et la valeur de retour est nulle


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

 Ce code est une déclaration de fonction , qui déclare la fonction signal, et la fonction signal a 2 paramètres

L'un est de type int

L'un est un type de pointeur de fonction, qui est void(*)(int)

           La fonction pointée par le pointeur de fonction, le paramètre est int et le type de retour est void

Le type de retour de la fonction signal est également un type de pointeur de fonction, qui est void(*)(int)

           La fonction pointée par le pointeur de fonction, le paramètre est int et le type de retour est void

[Simplifiez ce code] :

typedef void (* pfun_t )( int );//c'est-à-dire, changez void(*)(int) en nom pfun_t

pfun_t signal(int , pfun_t );


C'est la fin du contenu pour cette fois. Bienvenue dans la zone de commentaires ou dans la communication par message privé. Je pense que l'écriture de l'auteur est correcte, ou j'ai gagné un peu. S'il vous plaît, bougez vos petites mains et donnez-moi un- cliquez sur le triple lien. Merci beaucoup ! 

Je suppose que tu aimes

Origine blog.csdn.net/qq_73017178/article/details/132181132
conseillé
Classement