Apprentissage du langage C : 16. Pointeurs du langage C

Les pointeurs sont l'essence du langage C. De nombreuses personnes trouvent les pointeurs difficiles à apprendre parce qu'elles ont peur des pointeurs et se font peur. Quelle que soit la difficulté d’un langage d’application, tant que vous comprenez la nature des pointeurs, il est extrêmement facile à apprendre.

1. Qu'est-ce qu'un pointeur ?

1.1. Un pointeur est une sorte de variable , une variable spéciale , c'est aussi simple que cela.

Cette particularité est que la valeur enregistrée dans le pointeur est l'adresse en mémoire . Nous avons déjà découvert les variables de type int, les variables de type char et les variables de type float. Elles stockent les données du type correspondant. Les variables de type int stockent les données de type int, les variables de type char stockent les données de type char et les variables de type float stockent les données. données de type float, tandis que les variables telles que les pointeurs stockent les adresses mémoire.

1.2. La mémoire est introduite ici. Alors, qu'est-ce que la mémoire et qu'est-ce qu'une adresse mémoire ?

La mémoire est un composant de stockage dans un ordinateur, souvent appelé clé USB. La plus petite unité de stockage est un octet.

Chaque unité de stockage dans la mémoire a un numéro, et ce numéro est l'adresse mémoire ;

Par exemple, dans un système 32 bits, la plage d'adresses possible est 0x00000000--0xFFFFFFFF. Les 0x00000000 et 0xFFFFFFFF sont le numéro d'une unité de stockage, qui est l'adresse mémoire. Ce nombre est un entier.

De même, la plage d'adresses d'un système d'exploitation 64 bits est 0x0000000000000000--0xFFFFFFFFFFFFFFFF.

Nous devons également savoir que lorsque le programme est en cours d'exécution, tout ce qu'il contient est en mémoire, nous pouvons donc accéder à tous les éléments du programme via des adresses mémoire.

nous savons:

Une variable char occupe 1 octet

Une variable de type int occupe 4 octets

......

Nous pouvons accéder aux variables via les noms de variables et les adresses mémoire.

1.3. Comment obtenir l'adresse des éléments du programme

Les éléments du programme peuvent être des variables, des tableaux, des fonctions

Utilisez l'opérateur & pour obtenir l'adresse d'un élément de programme. Ce que vous obtenez est l'adresse de début de l'élément.

L'adresse mémoire est essentiellement un entier non signé. Sur un système 32 bits, l'adresse mémoire occupe 4 octets ; sur un système 64 bits, l'adresse mémoire occupe 8 octets.

Exemple de programme 1 : obtenir l'adresse d'une variable

#include <stdio.h>

int main()
{
	int var = 18;

	printf("var的值是%d\n",var);
	printf("var的地址是%p\n", &var); //打印指针类型用%p,取地址用&操作符

    return 0;
}

Résultat de sortie : mon ordinateur utilise un système d'exploitation 64 bits et l'adresse de sortie est de 64 bits.

var的值是18
var的地址是0000008146D3FCC4

 Les variables sont accessibles via les adresses mémoire. Comme mentionné précédemment, ce que nous obtenons lorsque nous obtenons l'adresse d'une variable est l'adresse de début de la variable dans la mémoire. Pour obtenir la valeur d'une variable, nous devons également connaître la longueur de la variable dans la mémoire, c'est-à-dire combien de secondes elle occupe. Une unité de mémoire, ou combien d'octets elle occupe. Par exemple, une variable int occupe 4 octets, 4 octets consécutifs.

Par conséquent, le langage C détermine la longueur de la variable via le type de la variable et utilise l'adresse de départ de la variable pour déterminer l'emplacement de la variable.

1.4. Comment définir des pointeurs

Syntaxe de définition du pointeur :

//指针定义语法:type * pointer

 Exemple de programme 2 : définition du pointeur

#include <stdio.h>

int main()
{
	char*	pChar;		//定义一个char类型指针
	int*	pInt;		//定义一个int类型指针
	float*	pFloat;		//定义一个float类型指针
	double* pDouble;	//定义一个double类型指针

	printf("pChar的地址是%p\n", &pChar); //打印指针类型用%p,取地址用&操作符
	printf("pInt的地址是%p\n", &pInt); //打印指针类型用%p,取地址用&操作符
	printf("pFloat的地址是%p\n", &pFloat); //打印指针类型用%p,取地址用&操作符
	printf("pDouble的地址是%p\n", &pDouble); //打印指针类型用%p,取地址用&操作符

	printf("pChar占用的空间是%d个字节\n", sizeof(char*)); //char*指针类型占的内存大小
	printf("pInt占用的空间是%d个字节\n", sizeof(int*));
	printf("pFloat占用的空间是%d个字节\n", sizeof(float*));
	printf("pDouble占用的空间是%d个字节\n", sizeof(double*));

	return 0;
}

 Résultat de sortie :

pChar的地址是000000F60E6FF5D8
pInt的地址是000000F60E6FF5F8
pFloat的地址是000000F60E6FF618
pDouble的地址是000000F60E6FF638
pChar占用的空间是8个字节
pInt占用的空间是8个字节
pFloat占用的空间是8个字节
pDouble占用的空间是8个字节

1.5. Accès à la mémoire du pointeur

Les données mémoire sont accessibles via l'opérateur d'accès au pointeur *. La taille de la mémoire occupée par le type de pointeur est fixe dans le système. L'adresse du système 32 bits est de 4 octets et l'adresse du système 64 bits est de 8 octets. L'exemple de programme précédent 2 Les résultats de sortie peuvent illustrer le problème.

Exemple de programme 3 :

#include <stdio.h>

int main()
{
	int var = 0; //定义一个var变量,并初始化为0
	int* pVar = NULL; //定义一个int* 类型的pVar变量,并初始化为0地址

	printf("var = %d\n", var); //打印的值就是0
	printf("var的地址是 %p\n", &var); //打印的值就是0
	printf("pVar = %p\n", pVar); //打印的地址就是0x0000000000000000

	pVar = &var;//把整型变量var的地址赋值给pVar
	*pVar = 18; //经pVar变量所存储的地址所指向的变量赋值18

	printf("var = %d\n", var);
	printf("pVar = %p\n", pVar);

	return 0;
}

Résultat de sortie :

var = 0
var的地址是 000000963A2FFA14
pVar = 0000000000000000
var = 18
pVar = 000000963A2FFA14

2. La relation entre les pointeurs et les adresses

Spécification des pointeurs du langage C :

1. Les pointeurs de type Type* ne peuvent enregistrer que l'adresse des variables de type Type :

        Par exemple, un pointeur de type int* ne peut enregistrer que l'adresse d'une variable de type int ;

        Un pointeur de type float* ne peut enregistrer que l'adresse d'une variable de type float ;

2. Des pointeurs de types différents ne peuvent pas être attribués les uns aux autres :

        comme. Les pointeurs de type int* ne peuvent pas être attribués les uns aux autres avec des pointeurs de type float* ;

3. Vous ne pouvez pas utiliser de valeurs ordinaires comme adresses pour attribuer des valeurs aux pointeurs.

        L'adresse enregistrée par le pointeur doit être une adresse mémoire pouvant être allouée par le système, et les données ne peuvent pas être écrites de manière aléatoire.

Exemple de programme 4 : exemple de code d'erreur

#include <stdio.h>

int main()
{
	int i = 10;
	float f = 10;

	int* pi = &f; //不同类型指针赋值,会有警告
	float* pf = &f; //正常

	printf("pi = %p, pf = %p\n", pi, pf); //能打印出同样的地址
	printf("*pi = %d, *pf = %f\n", *pi, *pf); //输出不同的值

	return 0;
}

Nous savions auparavant que les valeurs de deux variables ne peuvent pas être échangées directement en appelant une fonction, ce qui peut être facilement réalisé à l'aide de pointeurs.

Si vous souhaitez implémenter une fonction pour échanger la valeur d'une variable, vous devez modifier les variables en dehors de la fonction à l'intérieur de la fonction.

Exemple de programme 5 : Utilisation de pointeurs pour modifier des variables en dehors de la fonction à l'intérieur de la fonction

#include <stdio.h>

void change(int* p)
{
	*p = 18;  //把地址p中的变量赋值为18,实现函数内修改外部变量的值
}

int main()
{
	int var = 0;

	change(&var);
	printf("var = %d\n", var); //打印出18

	return 0;
}

Exemple de programme 6 : échanger les valeurs de deux variables

void swap(int* a, int* b)
{
	int t = 0;

	t = *a;
	*a = *b;
	*b = t;
}

int main()
{
	int x = 10;
	int y = 8;

	printf("交换前:x = %d, y = %d\n", x, y);

	swap(&x,&y);
	printf("交换后:x = %d, y = %d\n", x, y);

	return 0;
}

3. La relation entre les pointeurs et les tableaux

L'essence d'un tableau est un morceau de mémoire continu. Quelle est l'adresse du tableau ? Comment l'obtenir?

L'adresse du tableau est l'adresse de début de l'adresse continue, qui peut être obtenue en utilisant le caractère d'adresse &;

Le nom du tableau peut être considéré comme un pointeur, représentant l'adresse du 0ème élément du tableau ;

L'arithmétique du pointeur peut être effectuée lorsque le pointeur pointe vers un élément du tableau.

Exemple de programme 7 : obtenir l'adresse du tableau et l'adresse des éléments du tableau

#include <stdio.h>

int main()
{
	int arr[] = {1, 2, 3, 4,5};
	
	
	printf("数组名代表arr的地址是%p\n", arr); //数组名代表数组的地址
	printf("数组arr的地址是%p\n", &arr); //打印数组的地址
	printf("数组arr首个元素的地址%p\n", &arr[0]); //打印数组中首个元素的地址

	return 0;
}

Résultat de sortie :

数组名代表arr的地址是000000DFC37CF8C8
数组arr的地址是000000DFC37CF8C8
数组arr首个元素的地址000000DFC37CF8C8

&arr et arr sont numériquement identiques, mais ont des significations différentes.

&arr représente l'adresse du tableau arr, le type est int(*)[5];

arr représente l'adresse de l'élément 0 dans le tableau arr, le type est int*

Exemple de programme 8 : fonctionnement du pointeur

#include <stdio.h>

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

	int* p = arr; //p指向数组arr

	printf("*p = %d\n", *p); //打印1
	printf("arr[0] = %d\n", arr[0]); //打印1

	p = p + 1; //指针偏移

	printf("*p = %d\n", *p); //打印2
	printf("arr[1] = %d\n", arr[1]); //打印2

	*p = 100; 
	printf("*p = %d\n", *p); //打印100
	printf("arr[1] = %d\n", arr[1]); //打印100

	
	return 0;
}

Utilisation équivalente des pointeurs et des tableaux

a[i] == *(a + i)

Exemple de programme 9 :

#include <stdio.h>

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

	int* p = arr; //p指向数组arr

	int i = 0;

	for (i = 0; i < 5; i++)
	{
		printf("%d, %d\n",arr[i],*(p + i)); //arr[i]的值与*(p+i)的值是相等的
		printf("%p, %p\n", &arr[i], (p + i));//arr[i]的地址与(p+i)的地址是相同的
	}

	
	return 0;
}

Résultat de sortie :

1, 1
0000005B6716F788, 0000005B6716F788
2, 2
0000005B6716F78C, 0000005B6716F78C
3, 3
0000005B6716F790, 0000005B6716F790
4, 4
0000005B6716F794, 0000005B6716F794
5, 5
0000005B6716F798, 0000005B6716F798

Type de constante de chaîne

Les constantes de chaîne sont en fait un type de char*.

Exemple de programme 10 :

#include <stdio.h>

int main()
{
	printf("%s\n", "hello world!"); //打印字符串
	printf("%p\n", "hello world!"); //打印地址
	printf("%p\n", "hello world!"); //打印地址

	return 0;
}

Résultat de sortie :

hello world!
00007FF75A359DF0
00007FF75A359DF0

Afficher la même adresse. Si la constante de chaîne est une variable de type char*, alors les deux "hello world !" doivent être deux adresses différentes. Pourquoi les adresses de sortie sont-elles les mêmes ?

Les constantes chaîne doivent être stockées en mémoire et dans la zone de données globales. Lorsque le programme a besoin d'utiliser cette variable, le compilateur remplace directement la constante chaîne par le pointeur correspondant, qui est le point de départ de la constante chaîne en mémoire. Adresse, le compilateur trouve la même adresse en appelant deux fois "hello world!". L'adresse imprimée est donc la même.

Synthèse de pointeurs et de tableaux

int v = *p++;//等价于int v = *p; p++;
//指针访问操作符*与自增操作符++优先级相同,所以按从左到右的顺序执行
//先从p指向的内存中取值,然后再移动p指针

Exemple de programme 11 :

#include <stdio.h>

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

	int* p = arr;
	int v = *p++;

	printf("v = %d, *p = %d\n", v, *p); 

	return 0;
}

Résultat de sortie :

v = 1, *p = 2

 La sortie prouve que la valeur enregistrée par v est la première valeur du tableau et que la valeur enregistrée par le pointeur p est la deuxième valeur du tableau.

4. La relation entre les pointeurs et les fonctions

Comment la fonction est appelée

Une fonction est essentiellement un bloc de code stocké en mémoire. Lorsque la fonction est appelée, elle sera transférée au code correspondant au corps de la fonction pour exécuter le code. La position du corps de la fonction est le nom de la fonction, et le nom de la fonction est un pointeur.

Le type d'une fonction est déterminé par le type de valeur de retour et le type de paramètre de la fonction.

int sum(int n); //函数类型是 int(int)

void swap(int* pa, int*pb);//函数类型是 void(int*, int*)

void func(void);//函数类型是void(void)

5. La relation entre les pointeurs et l'espace du tas

Guess you like

Origin blog.csdn.net/m0_49968063/article/details/133063621