当前位置:网站首页>30 000 mots de production, sur la langue C, vous devez connaître ces points de connaissance (haut niveau)

30 000 mots de production, sur la langue C, vous devez connaître ces points de connaissance (haut niveau)

2021-10-14 07:31:21 - Non.


Table des matières

Un.,C'est écrit devant

2.,Stockage des données

1,Description du type de données

2,Classification de base des types

3,Le stockage des formes en mémoire

4,Stockage en mémoire flottante

Trois,L'avancement du pointeur

1,Pointeur de caractères

2,Tableau de pointeurs

3,Utilisation de pointeurs de tableau

 4,Pointeur de fonction

5,Tableau des pointeurs de fonction

6,Fonction de rappel

7,Pointeur et tableau questions écrites

Quatre, Fonctions de caractères et de chaînes

1,strlen

2,strcpy

3,strcat

4,strcmp

5,strstr

6,memcpy

7,memmove

8,Implémenter analogiquement les fonctions de mémoire et de chaîne décrites ci - dessus

 Cinq,Type personnalisé:Structure,Enumeration,Union européenne

1,Structure

2,Enumeration

3,Union européenne(La communauté)

Six,Gestion dynamique de la mémoire

1,Pourquoi l'allocation dynamique de mémoire existe

2,Introduction aux fonctions de mémoire dynamique

Sept,COpérations de fichiers linguistiques


Un.,C'est écrit devant

Pour être honnête,J'a i écrit un article de base sur la liste de recherche, C'est vraiment effrayant. , J'ai l'impression de ne pas être digne de cette liste. , Le partage n'est pas si bon. ,Je l'ai.C Reconnaissance des amis debout , Un peu heureux. ,Cela me poussera encore plus à améliorer mon niveau, Améliorer la qualité de votre blog , Oui, tout le monde est d'accord. .Avant d'étudier ce billet, vous pouvez apprendre mon blog précédent,Contribuer à une meilleure compréhension et à un meilleur apprentissage de ce chapitre.Cliquez sur le titre pour passer au blog correspondant.

️Résumé en dix mille mots,C Tu marches encore sur ces trous de mots? (Chapitre de base)️

L'article précédent portait sur les fondements , C'est une édition de haut niveau. , J'ai besoin de plus d'entraînement et de compréhension. , Cet article est une étude précédente C Résumé linguistique , La production est principalement pour mon examen , Puisque c'est la connaissance, , Bien sûr, le partage est important. ,C'est un vieux dicton.,Si vous pensez que ce blog est bien écrit,S'il te plaît.Commentaires,Collection demandée,Je t'en prie.,Votre triple lien est ma plus grande force de production, C'est environ 30 000 mots. ,Il n'y a pas de temps pour finir de regarder, Une partie du contenu que je présente sous forme de liens ,Ne dis pas de bêtises,Apprenons à!!!


2.,Stockage des données

1,Description du type de données

char        //Type de données de caractère
short       //Forme courte
int         //Remodelage
long        //Forme longue
long long   //Remodelage plus long
float       //Nombre de points flottants de précision unique
double      //Nombre de points flottants de double précision

Le sens du type:

Utilisez ce type pour ouvrir la taille de l'espace mémoire(La taille détermine la plage d'utilisation).

Comment voir la perspective de l'espace mémoire.

2,Classification de base des types

Famille orthopédique

char
   unsigned char
   signed char
short
   unsigned short[int]
   signed short[int]
int
   unsigned int
   signed int
long
   unsigned long[int]
   signed long[int]

Famille de nombres flottants

float
double

Type de construction

  Type de tableau
  Type de structure struct
  Type d'énumération enum
  Type d'union union
int main()
{
	unsigned char a = 200;
	unsigned char b = 100;
	unsigned char c = 0;
	c = a + b;
	printf("%d %d", a + b, c);
	return 0;
}

Le résultat de l'exécution du programme est: ( )

A.300 300

B.44 44

C.300 44

D.44 300

Description:printfLors de l'entrée d'un paramètre, un entier passe quatre octets par défaut,Alors...a+bLe résultat est reçu avec un entier de quatre octets,Ne dépassez pas les bornes..EtcC'est déjàc = a + bLe plus haut niveau de1,Donc ça ne peut être que300-256Je l'ai.44C'est.

※Parce queprintfEst une fonction d'un paramètre variable,Le type de paramètre suivant est donc inconnu,Donc peu importe le type que vous passez,printfIl ne sera stocké que dans deux longueurs différentes selon le type.Parmi eux8Les octets sont seulementlong long、floatEtdouble(Attention!floatÇa se passera commedoubleRe - pass),Les autres types sont4Octets.Donc, bien quea + bLe type dechar,Reçu en fait avec un entier de quatre octets.En plus,Lors de la lecture,%lld、%llxIsomorphisme et%f、%lfLecture isoflottante8Octets,Autres lectures4Octets.

3,Le stockage des formes en mémoire

Code source、Code inverse、Complément

Code source

Il suffit de traduire le binaire directement en binaire sous forme de nombre positif et négatif.

Code inverse

Modifie le BIT de symbole du code source,Les autres bits sont inversés dans l'ordre.

Complément

Code inverse+1J'ai un complément.

Pour en savoir plus sur le calcul de l'anti - complément original et le système décimal, consultez mon blog précédent, Explication binaire

À propos deC Contenu lié au binaire linguistique + Exercices d'examen écrit ,Collection recommandée

Code source、Code inverse、 Le complément est faux. ( )

A.Le code original d'un nombre est que ce nombre est converti directement en binaire

B.Le Code inverse est le symbole binaire du code original avec le BIT invariant,Les autres bits sont inversés

C. Le complément est l'addition binaire du Code inverse 1

D.Code source、Code inverse、 Le BIT le plus élevé du complément est 0Indique un nombre négatif,La position la plus élevée est1Indique un nombre positif

 ABCExact.,D La description des bits symboliques est inversée

Stockage des données en mémoire

#include<stdio.h>
int main()
{
	int a = 1;
	int b = -2;
	return 0;
}

 Les données sont stockées en mémoire à la fin de la taille

Original of positive、Contre、Le complément est le même.

Pour le remodelage:La mémoire de stockage des données contient en fait un complément.

Introduction de la taille

Grande extrémité(Stockage)Mode,Le BIT inférieur des données est stocké dans une adresse mémoire élevée,Et le haut niveau des données,Enregistrer en mémoire à faible adresse;

Petit bout(Stockage)Mode,Le BIT inférieur des données est stocké dans une adresse mémoire basse,Et le haut niveau des données,,Enregistrer en mémoire à haute adresse.

Pourquoi les grandes et les petites extrémités

Pourquoi y a - t - il une différence de taille??C'est parce que dans un système informatique,Nous sommes en octets,Chaque Unit é d'adresse correspond à un Octets,Un octet est8bit.Mais dansCDans la langue8bitDecharAu - delà,Et16bitDeshortType,32bitDelongType(Ça dépend. Compilateur de corps),En plus,Pour les chiffres supérieurs à8Processeur de bits,Par exemple16Bits ou32Processeur de bits,Parce que la largeur du registre est supérieure à un mot Section,Il doit y avoir un problème si plusieurs octets sont programmés.Il en résulte des modes de stockage à grande et à petite échelle. Par exemple, 16bit De short Type x ,L'adresse en mémoire est 0x0010 , x La valeur de 0x1122 ,Alors 0x11 Est un octet élevé, 0x22 Faible octet.Pour le mode grand terminal,Juste... 0x11 Placer à basse adresse,C'est - à - dire: 0x0010 Moyenne, 0x22 Placer à haute adresse,C'est - à - dire: 0x0011 Moyenne.Petit Mode terminal,Exactement le contraire..Que nous utilisons X86 La structure est un modèle à petite extrémité,Et KEIL C51 Mode grand terminal.Beaucoup.ARM,DSPTous petits. Mode terminal.CertainsARMLe processeur peut également être sélectionné par le matériel en mode grand ou petit.

unsigned int a = 0x1234; 
unsigned char b = *(unsigned char*)&a;

In32Variable sur le processeur de mode grand bitbégal à( )

Grande séquence terminale,L'arrangement hexadécimal de quatre octets de l'adresse basse à l'adresse haute est00 00 12 34,Le contenu du premier octet est00,Choix judicieuxA

La description de l'ordre des octets de fin de taille est correcte( )

A.L'ordre des octets de taille se réfère à l'ordre des bits binaires dans lesquels les données sont stockées sur l'ordinateur

B.L'ordre des octets de taille se réfère à l'ordre des octets dans lesquels les données sont stockées sur l'ordinateur

C.Un grand ordre d'octets est de stocker le contenu d'octets élevés des données à une adresse élevée, Contenu de faible octet stocké à faible adresse

D.L'ordre des petits octets est de stocker le contenu en octets élevés des données à une adresse inférieure, Contenu de faible octet stocké à haute adresse

Ordre des petits octets: Bas à bas

Ordre des grands octets: Haut à bas

Le résultat du code suivant est( )

int main()
{
	char a[1000] = { 0 };
	int i = 0;
	for (i = 0; i < 1000; i++)
	{
		a[i] = -1 - i;
	}
	printf("%d", strlen(a));
	return 0;
}

aC'est un tableau de caractères,strlenC'est la première fois qu'il y a des zéros de queue.(La valeur est0)Emplacement.Considérant quea[i]En fait, c'est un type de caractère,Si c'est pour0,Oui.-1-iSi tous les huit étaient0,C'est - à - dire que le problème a été réduit à“Chercher quand-1-iPour la première fois, les huit premiers chiffres inférieurs sont tous0Dans le cas de,iValeur de”(Parce que l'indice du tableau de caractères estiPour la première fois, il y a des zéros de queue,La longueur de la chaîne esti). Je ne vois que les huit premiers. ,En ce moment-1équivalent à255,Alors...i==255Quand,-1-i(255-255) Les huit premiers sont tous 0,C'est - à - dire quandiPour255Quand,a[i]Pour la première fois0,Alors...a[i]La longueur de255C'est

4,Stockage en mémoire flottante

Nombre commun de points flottants:

3.14159 1E10 La famille des nombres flottants comprend:: float、double、long double Type. Plage représentée par un nombre flottant:float.hDéfinition moyenne

Par exemple,

int main()
{
	int n = 9;
	float* pFloat = (float*)&n;
	printf("nLa valeur de:%d\n", n);
	printf("*pFloatLa valeur de:%f\n", *pFloat);
	*pFloat = 9.0;
	printf("numLa valeur de:%d\n", n);
	printf("*pFloatLa valeur de:%f\n", *pFloat);
	return 0;
}

Conformément aux normes internationalesIEEE(Institute of Electrical and Electronic Engineering) 754,N'importe quel nombre binaire de points flottantsVPeut être exprimé sous la forme suivante::

(-1)^S * M * 2^E

(-1)^sReprésente un bit de symbole,Quands=0,VEst un nombre positif;Quands=1,VEst négatif.

MIndique un nombre valide,Supérieur ou égal à1,Moins de2.

2^EReprésente un bit exponentiel.

Par exemple,: Décimal5.0,Écrit en binaire oui 101.0 ,équivalent à 1.01×2^2 . Alors,Suivez les instructions ci - dessus.VFormat de,On peut conclure ques=0, M=1.01,E=2.

Décimal-5.0,Écrit en binaire oui -101.0 ,équivalent à -1.01×2^2 .Alors,s=1,M=1.01,E=2.

IEEE 754Pour les chiffres validesMEt indexE,Il existe également des dispositions spéciales.

EPas tout à fait.0Ou pas tous1

À ce moment - là,,Le nombre de points flottants est représenté par les règles suivantes:,C'est - à - dire l'indiceEValeur calculée moins127(Ou1023),Obtenir la valeur réelle,Ensuite, les chiffres validesMAvant Plus le premier 1. Par exemple,: 0.5(1/2)La Forme binaire de0.1,La partie positive doit être1,Déplacer le point décimal à droite1Bits, Oui.1.0*2^(-1),Son code d'ordre est-1+127=126,Exprimé en01111110,Et le nombre de queues1.0Supprimer la partie entière comme suit:0,Compléter0À23Bits 00000000000000000000000,Sa représentation binaire est:

0 01111110 00000000000000000000000

ETout est0

À ce moment - là,,Indice du nombre de points flottantsEégal à1-127(Ou1-1023)Est la valeur réelle, Nombre effectifMPlus de premier1,Mais revenir à 0.xxxxxxLa décimale de.C'est pour montrer±0,Et près de0Un petit nombre.

ETout est1

À ce moment - là,,Si un nombre valideMTout est0,Représentation±Infini(Plus ou moins dépend du BIT de symboles);

Expliquer les questions précédentes :

En bas, Revenons à la question de départ. :Pourquoi 0x00000009 Revenir au nombre de points flottants,C'est tout. 0.000000 ? Tout d'abord,,Oui. 0x00000009 Démonter Points,Obtenir le premier bit de symboles=0,Derrière8Indice des bits E=00000000 ,Enfin23Nombre valide de bitsM=000 0000 0000 0000 0000 1001.

9 -> 0000 0000 0000 0000 0000 0000 0000 1001

Grâce à l'indiceETout est0,Donc, selon la deuxième situation de la section précédente.Donc,,Nombre de points flottantsVC'est écrit comme suit:: V=(-1)^0 × 0.00000000000000000001001×2^(-126)=1.001×2^(-146) Apparemment.,VC'est un peu près de0Nombre positif de, Donc en décimal petit Le nombre est 0.000000.

Voir la deuxième partie de l'exemple . Excusez - moi, les points flottants9.0,Comment représenter?Qu'est - ce que c'est de revenir à la décimale? Tout d'abord,,Nombre de points flottants9.0 égal au binaire De1001.0,C'est - à - dire:1.001×2^3.

9.0 -> 1001.0 ->(-1) ^ 01.0012 ^ 3->s = 0, M = 1.001, E = 3 + 127 = 130

Alors,Le symbole du premier chiffres=0,Nombre effectifMégal à001Plus de20- Oui.0,Remplir23Bits,IndexEégal à3+127=130,C'est - à - dire: 10000010. Alors...,Écrit sous forme binaire,Je crois.s+E+M,C'est - à - dire:

0 10000010 001 0000 0000 0000 0000 0000

C'est32Nombre binaire de bits,Retour à la décimale,Exactement. 1091567616 .


Trois,L'avancement du pointeur

1,Pointeur de caractères

Utilisation générale

int main()
{
	char ch = 'w';
	char* pc = &ch;
	*pc = 'w';
	return 0;
}

Utilisation de haut niveau

int main()
{
	char* pstr = "hello bit.";
	printf("%s\n", pstr);
	return 0;
}

Pratiquez une question.

#include <stdio.h>
int main()
{
	char str1[] = "hello word.";
	char str2[] = "hello word.";
	char* str3 = "hello word.";
	char* str4 = "hello word.";
	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;
}

Ici.str3Etstr4Pointez vers la même chaîne constante.C/C++Les chaînes constantes sont stockées dans une seule zone mémoire, Quand quelques pointeurs.Quand vous pointez vers la même chaîne,Ils pointent vers la même mémoire.Mais utiliser la même chaîne constante pour initialiser La transformation de différents tableaux ouvre différents blocs de mémoire.Alors...str1Etstr2C'est différent.,str3Etstr4C'est différent..

À propos de"Pointeur"La description incorrecte de:( )

A.Lorsqu'il est utiliséfree Après avoir libéré le contenu d'un pointeur , La valeur de la variable pointeur est définie à NULL

B.32La longueur de n'importe quel type de pointeur sous le système bit est4Octets

C.Le type de données du pointeur indique le type de données que le pointeur pointe réellement vers le contenu

D.Un pointeur sauvage est un pointeur vers une adresse mémoire non assignée ou déjà libérée

Afree Ne change pas la direction du pointeur .

B L'option souligne 32Système de bits,Donc pas de problème..

CD L'option est la définition elle - même .

Donc l'exclusion peut être aussi sûre A

À propos de la description de code suivante est correcte :( )

char* p = "hello word";

A.Mettez la chaînehello bitÀ conserver danspDans la variable

B.Mettez la chaînehello bit Le premier caractère de pDans la variable

C.Mettez la chaînehello bit L'adresse du premier caractère de pDans la variable

D.*pÉquivalent àhello bit

Ce passage, cité en guillemets doubles, est une chaîne constante, Essentiellement un type de tableau de caractères constant , Assigner un pointeur ,C'est l'équivalent d'assigner la première adresse d'un tableau à un pointeur,Le premier élémenthAdresse.

Options seulement C Adresse du premier caractère mentionné ,Choix judicieuxC

2,Tableau de pointeurs

Définition

Tableau de pointeurs: Pointeur capable de pointer vers un tableau .

int* p1[10];
int(*p2)[10];
//p1, p2Quelle est la différence??
int (*p)[10];
//Explication:pD'abord.*Union,DescriptionpEst une variable pointeur, Puis pointez vers une taille de 10Un tableau entier.Alors...pC'est un
Pointeur,Pointez vers un tableau, Appelle un pointeur de tableau .
//Attention ici.:[]Priorité supérieure à*No.,Il faut donc ajouter()Pour garantirpD'abord.*Union.

&Nom du tableauVSNom du tableau

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

Nom du tableau visible et& L'adresse imprimée du nom du tableau est la même .

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

D'après le code ci - dessus, nous avons trouvé,En fait...&arrEtarr,Bien que la valeur soit la même,Mais le sens devrait être différent. En fait,: &arr Indique l'adresse du tableau,Au lieu de l'adresse du premier élément du tableau.(Faites l'expérience) Adresse du tableau+1,Sauter la taille du tableau entier,Alors... &arr+1 Par rapport à &arr La différence est40.

Lequel est le pointeur de tableau ci - dessous ( )

A.int** arr[10]

B.int (*arr[10])

C.char *(*arr)[10]

D.char(*)arr[10]

A Est un tableau de pointeurs secondaires ,BEst un tableau de pointeurs,C- Oui.char *Pointeur vers un tableau,D- Oui.char *Tableau de.SeulementCEst un pointeur de tableau.

tip: Selon la priorité, seulement C Options prioritaires *Union, Rien d'autre n'est un pointeur , Alors choisissez directement C.

Lequel des codes suivants est incorrect ?( )

#include <stdio.h>
int main()
{
	int* p = NULL;
	int arr[10] = { 0 };
	return 0;
}

A.p = arr;

B.int (*ptr)[10] = &arr;

C.p = &arr[0];

D.p = &arr;

En termes de type de données ,A À gauche et à droite. int *,B À gauche et à droite. int (*)[10],C À gauche et à droite. int *,DÀ gauche. int *,À droite. int (*)[10],Choix judicieuxD.

Le code suivant décrit incorrectement le nom du tableau est( )

int main()
{
  int arr[10] = {0};
  return 0;
}

A.Nom du tableauarrEt&arrC'est pareil

B.sizeof(arr),arrReprésente l'ensemble du tableau

C.&arr,arrReprésente l'ensemble du tableau

D.Sauf quesizeof(arr)Et&arr Nom du tableau dans , Nom du tableau ailleurs arr, Est l'adresse du premier élément du tableau

A Erreur d'option évidente .arrLe type deint [10],Et&arrLe type deint (*)[10], Ce n'est pas du tout un type , Ça ne peut pas être pareil. .Et sizeof(arr)Et&arrMoyenne,arr Sont considérés comme un tout ,En général, c'est la première adresse d'un tableau.

3,Utilisation de pointeurs de tableau

#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	int(*p)[10] = &arr;//ArrayarrL'adresse de est assignée à la variable de pointeur de tableaup
	//Mais nous écrivons rarement le Code comme ça
	return 0;
}

Utilisation d'un pointeur de tableau

#include <stdio.h>
void print_arr1(int arr[3][5], int row, int col)
{
    int i, j;
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col; j++)
        {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}
void print_arr2(int(*arr)[5], int row, int col)
{
    int i, j;
    for (i = 0; i < row; i++)
    {
        for (j = 0; j < col; j++)
        {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}
int main()
{
    int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };
    print_arr1(arr, 3, 5);
    //Nom du tableauarr,Indique l'adresse du premier élément
    //Mais le premier élément d'un tableau bidimensionnel est la première ligne d'un tableau bidimensionnel
    //Donc ce qui est passé iciarr,En fait, c'est l'adresse de la première ligne,C'est l'adresse d'un tableau unidimensionnel
    //Peut recevoir un pointeur de tableau
    print_arr2(arr, 3, 5);
    return 0;
}

 4,Pointeur de fonction

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

pfun1Peut être stocké.pfun1D'abord.*Union,Descriptionpfun1C'est un pointeur.,Le pointeur pointe vers une fonction, Aucune fonction pointée Paramètres,Le type de valeur de retour estvoid.

5,Tableau des pointeurs de fonction

Pour enregistrer l'adresse de la fonction dans un tableau,Ce tableau s'appelle un tableau de pointeurs de fonction,Comment définir un tableau de pointeurs de fonction?

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

parr1 parr1 D'abord. [] Union,Descriptionparr1Est un tableau,Quel est le contenu du tableau? - Oui. int (*)() Type Pointeur de fonction

Lequel est le pointeur de fonction ci - dessous ?( )

A.int* fun(int a, int b);

B.int(*)fun(int a, int b);

C.int (*fun)(int a, int b);

D.(int *)fun(int a, int n);

 ABDAucune différence.,Les parenthèses n'affectent aucune priorité, Toutes les valeurs retournées sont: int *Fonction de,Choix judicieuxC.

Définir un pointeur de fonction, Il y a deux fonctions pointées int Paramètre formel et renvoie un pointeur de fonction , Renvoie un pointeur vers un int Paramètre formel et retour intFonction de? Lequel des éléments suivants est correct ?( )

A.int (*(*F)(int, int))(int)

B.int (*F)(int, int)

C.int (*(*F)(int, int))

D.*(*F)(int, int)(int)

 D Type incomplet à exclure en premier , Puis regardez la valeur de retour ,BLa valeur de retour pour estint,CLa valeur de retour pour estint *,Choix judicieuxA.Pour déterminer le type de valeur de retour, il suffit de supprimer le nom de la fonction/La liste des pointeurs de fonctions et des paramètres est juste à regarder.int (*(*F)(int, int))(int)Supprimer(*F)(int, int) Reste après. int (*)(int),Ça correspond.

Dans la conception du jeu ,Souvent, différentes fonctions sont appelées en fonction de l'état du jeu,Nous pouvons le faire avec un pointeur de fonction, Lequel est le suivant? : Un paramètre est int *,La valeur de retour estintPointeur de fonction pour( )

A.int (*fun)(int)

B.int (*fun)(int *)

C.int* fun(int *)

D.int* (*fun)(int *)

 Tout d'abord,C La racine n'est pas un pointeur de fonction , Exclure d'abord ,Et puisDLa valeur de retour n'est pasint,Exclusion,ALe paramètre pour n'est pasint *,Exclusion,Il resteBC'est.

Déclarer un point contenant 10 Pointeur vers un tableau d'éléments ,Chaque élément est un pointeur de fonction, La valeur de retour de cette fonction est int,Le paramètre estint*,C'est vrai.( )

A.(int *p[10])(int*)

B.int [10]*p(int *)

C.int (*(*p)[10])(int *)

D.int ((int *)[10])*p

 AOptions, La première parenthèse est une définition complète , Il y a un type entre parenthèses ,Quatre..BDOptions,[] Uniquement à droite de l'identificateur , Double exclusion .SeulementC C'est possible. .

6,Fonction de rappel

Une fonction de rappel est une fonction appelée par un pointeur de fonction.Si vous pointez une fonction(Adresse)Passer comme paramètre à un autre Fonctions,Quand ce pointeur est utilisé pour appeler la fonction qu'il pointe,Disons que c'est une fonction de rappel. La fonction de rappel n'est pas définie par L'implémentateur de la fonction appelle directement ,Mais appelé par l'autre partie au moment où un événement ou une condition particulier se produit, Utilisé pour traiter l'événement ou Conditions de réponse .

#include <stdio.h>
//qosrtL'utilisateur de la fonction doit implémenter une fonction de comparaison
int int_cmp(const void* p1, const void* p2)
{
    return (*(int*)p1 - *(int*)p2);
}
int main()
{
    int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
    int i = 0;

    qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);
    for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
    return 0;
}

7,Pointeur et tableau questions écrites

Un tableau unidimensionnel

int main()
{
	int a[] = { 1,2,3,4 };
	
    printf("%d\n", sizeof(a));
	//Nom du tableauaSeulsizeofInterne,Le nom du tableau représente l'ensemble du tableau,La taille du tableau entier est calculée
	
    printf("%d\n", sizeof(a + 0));
	//aIndique l'adresse du premier élément,a+0Ou l'adresse du premier élément,La taille de l'adresse est4/8Octets
	
    printf("%d\n", sizeof(*a));   
 	//aIndique l'adresse du premier élément,*a C'est le premier élément. ==> a[0] ,La taille est4
	//*a == *(a+0) == a[0]
	
    printf("%d\n", sizeof(a + 1));
	//aIndique l'adresse du premier élément,a+1C'est l'adresse du deuxième élément,La taille est4/8
	
    printf("%d\n", sizeof(a[1]));
	//a[1] C'est le deuxième élément. - 4
	
    printf("%d\n", sizeof(&a));  
	//&a - Adresse du tableau - 4/8 - int(*)[4]
	
    printf("%d\n", sizeof(*&a));  
	//*&a - &aC'est l'adresse du tableau,La désactivation de l'adresse du tableau donne le tableau,Donc, à la taille,16
	//équivalent àprintf("%d\n", sizeof(a));//16
	
    printf("%d\n", sizeof(&a + 1));
	//4/8 &aC'est l'adresse du tableau,&a+1 C'est l'adresse du tableau+1,Sauter le tableau entier,Bien que le tableau ait été sauté,
	//Ou l'adresse  4/8
 	
    printf("%d\n", sizeof(&a[0]));
	//4/8
	
    printf("%d\n", sizeof(&a[0] + 1));
	//Adresse du deuxième élément 4/8
	return 0;
}

Tableau de caractères

char arr[] = { 'a','b','c','d','e','f' };
//arrNon.\0De,Etstrlen()La longueur est trouvée\0Ça s'arrête.

printf("%d\n", strlen(arr));
//DearrEmplacement(Adresse du premier élément)Longueur vers l'arrière,Valeurs aléatoires

printf("%d\n", strlen(arr + 0));
//DearrEmplacement(Adresse du premier élément)Longueur vers l'arrière,Valeurs aléatoires

printf("%d\n", strlen(*arr));
//arrEst l'adresse du premier élément,*arrC'est un caractère.‘a’-ascii-97,strlenMettre les caractèresaCorrespondantasciiValeur du Code97Compte en arrière comme adresse,Accès illégal!err


printf("%d\n", strlen(arr[1]));
//strlenMettre les caractèresbCorrespondantasciiValeur du Code98Compte en arrière comme adresse,Accès illégal!err

printf("%d\n", strlen(&arr));//&arrEtarrMême adresse,C'est l'adresse du premier élément.,Mais le sens est différent.
//&arrTransmis àstrlen 

printf("%d\n", strlen(&arr + 1));//Après avoir sauté le tableau entier,Compte en arrière,Valeurs aléatoires-6
//Espace mémoire continu,Et trouver\0Arrêtez!,Maisstrlen(arr)Etstrlen(&arr)Plus de valeurs aléatoires que la deuxième6Caractèresabcdef

printf("%d\n", strlen(&arr[0] + 1));//Du caractèrebPosition count back,Nombre aléatoire-1
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	//&arrType de:Pointeur de tableau: char(*)[6]
	
    printf("%d\n", sizeof(arr));
	//La liste des tableaux est laissée seule danssizeofInterne,La taille du tableau entier est calculée,Le nombre d'éléments est6- Oui.(Sans\0),Le type estchar Donc la taille est6
	
    printf("%d\n", sizeof(arr + 0));
	//IciarrReprésente l'adresse du premier élément,arr+0Toujours l'adresse du premier élémentchar*,Adresse(Pointeur)La taille est4/8
	
    printf("%d\n", sizeof(*arr));
	//IciarrReprésente l'adresse du premier élément,*arrEst le premier élément du tableau,Est un caractère‘a’  La taille est1
	
    printf("%d\n", sizeof(arr[1]));
	//arr[1]->Les caractères‘b’,La taille est1
	
    printf("%d\n", sizeof(&arr));
	//Extraire l'adresse du tableau entier,Ou l'adresse,La taille de l'adresse est4/8  
	
    printf("%d\n", sizeof(&arr + 1));
	//Extraire le tableauarrAdresse+1,Sauter un tableau,Ou l'adresse,La taille de l'adresse est:4/8
	
    printf("%d\n", sizeof(&arr[0] + 1));//Adresse du deuxième élément du tableau,4/8
	return 0;
}

int main()
{
	char arr[] = "abcdef";
	//Tableau actuelarrStocké dans\0  strlenTrouver la longueur,Rencontre\0C'est - à - dire arrêter de compter
	
    printf("%d\n", strlen(arr));
	//DearrLa position commence à compter en arrière,Rencontre\0C'est fini.,La longueur est6
	
    printf("%d\n", strlen(arr + 0));
	///DearrLa position commence à compter en arrière,Rencontre\0C'est fini.,La longueur est6
	
    printf("%d\n", strlen(*arr));//arrEst l'adresse du premier élément,*arrC'est un caractère.‘a’
	// Correspondant àasciiLa valeur est:97,strlenMettre les caractèresaCorrespondantasciiValeur du Code97Compte en arrière comme adresse,err
	
    printf("%d\n", strlen(arr[1]));///arr[1]:‘b’Correspondant àasciiLa valeur est:98,
	//strlenMettre les caractèresbCorrespondantasciiValeur du Code98Compte en arrière comme adresse,Accès illégal!err
	
    printf("%d\n", strlen(&arr)); 
	//&arrEtarrMême adresse,C'est l'adresse du premier élément.,Mais le sens est différent.
	//&arrTransmis àstrlen  &arrType:Pointeur de tableau char(*p)[6] EtstrlenLe type reçu estchar*,Incompatible,Mais le problème n'est pas grand
	//Comptez en arrière à partir de la position du premier élément du tableau,La valeur est: 6
	
    printf("%d\n", strlen(&arr + 1));
	//Après avoir sauté le tableau entier,Compte en arrière,Valeur inconnue
	
    printf("%d\n", strlen(&arr[0] + 1));
	//DebCompte en arrière inconnu,La longueur est5
	return 0;
}

int main()
{
	char arr[] = "abcdef";
	//En ce momentarrC'est dans le tableau.\0De
	
    printf("%d\n", sizeof(arr));
	//La liste des tableaux est laissée seule danssizeofInterne,La taille du tableau entier est calculée,\0Ça compte aussi.,La taille est7
	
    printf("%d\n", sizeof(arr + 0));
	//Le nom du tableau est l'adresse du premier élément,Adresse(Pointeur)Taille:4/8
	
    printf("%d\n", sizeof(*arr));
	//Le nom du tableau est l'adresse du premier élément,*arrC'est - à - dire l'élément principal,Les caractèresa->charType,La taille est1
	
    printf("%d\n", sizeof(arr[1]));
	//arr[1]:Les caractères'b',La taille est1
	
    printf("%d\n", sizeof(&arr));
	//Extraire l'adresse du tableau,Ou l'adresse,La taille est4/8
	
    printf("%d\n", sizeof(&arr + 1));
	//Extraire l'adresse du tableau+1,Sauter le tableau entier,Ou l'adresse:4/8
	
    printf("%d\n", sizeof(&arr[0] + 1));
	//Extraire l'adresse du premier élément+1,Sauter un élément,C'est l'adresse du deuxième élément,4/8
	return 0;
}

#include<stdio.h>
int main()
{
	//&p[0]==>équivalent à&*(p+0)-->équivalent àsizeof(p),pLes caractères sont stockésaAdresse,+1,Est un caractèrebAdresse,Du caractèrebAccès en arrière,  La longueur est5
	// p[0] :Les caractèresa  
	//&p[0]:Les caractèresaAdresse 
	//&p[0] +1:Les caractèresbAdresse
	const char* p = "abcdef";
	//pLes caractères sont stockésaAdresse,
	//p+1:Les caractèresbAdresse
	
     printf("%d\n", strlen(p));
	//pLes caractères sont stockésaAdresse,C'est - à - dire à partir du caractèreaNombre d'adresses pour,La longueur est6
	
    printf("%d\n", strlen(p + 1));
	//Du caractèrebNombre d'adresses pour,La longueur est5
	
    //printf("%d\n", strlen(*p));
 	//*p ->Les caractères‘a’  En caractèresaDeasciiValeur du Code97Compte en arrière pour l'adresse,Accès illégal,err
	
    //printf("%d\n", strlen(p[0]));
	//p[0] ->Les caractères‘a’  En caractèresaDeasciiValeur du Code97Compte en arrière pour l'adresse,Accès illégal,err
 	
    printf("%d\n", strlen(&p));
	//&pCe qui a été retirépAdresse de la variable,C'est - à - direpAdresse de la variable(16Décimal)Compte en arrière,  Valeurs aléatoires
	
    printf("%d\n", strlen(&p + 1));//&pCe qui a été retirépAdresse de la variable,&p+1,SkippVariables,DepL'emplacement suivant la variable est accessible en arrière  Valeurs aléatoires
	
    printf("%d\n", strlen(&p[0] + 1));
	//&p[0]==>équivalent à&*(p+0)-->équivalent àsizeof(p),pLes caractères sont stockésaAdresse,+1,Est un caractèrebAdresse,Du caractèrebAccès en arrière,  La longueur est5
	return 0;
}
int main()
{
	//Parce que le pointeur pointe vers une chaîne constante,Ne peut pas être modifié
//Pour que ça marche.constModification
//char* p = "abcdef";
	const char* p = "abcdef";
	//pLes caractères sont stockésaAdresse
	
    printf("%d\n", sizeof(p));
	//pC'est un pointeur.,Pointer vers le caractèrea,La taille est4/8
	
    printf("%d\n", sizeof(p + 1));
	//p+1,Pointez vers le caractèreb,Pointeur,La taille est4/8
	
    printf("%d\n", sizeof(*p));
	//pLes caractères sont stockésaAdresse,*p:Est un caractèrea,La taille est1
	
    printf("%d\n", sizeof(p[0]));
	//p[0]->Les caractèresa ,La taille est1
	
    printf("%d\n", sizeof(&p));
	//Enlevez - le.pAdresse de la variable,Toujours l'adresse.,La taille est4/8
	
    printf("%d\n", sizeof(&p + 1));
	//Enlevez - le.pAdresse de la variable+1,SkippVariables,Mais c'est toujours l'adresse.,La taille est4/8
	
    printf("%d\n", sizeof(&p[0] + 1));
	//&p[0]équivalent à&*(p+0),&Et*Compensation,&p[0]:Les caractèresaAdresse,+1:Les caractèresbAdresse,La taille est4/8
	return 0;
}

int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));
	//La liste des tableaux est laissée seule danssizeofInterne,La taille du tableau entier est calculée, 
	//L'élément Array est12- Oui.,La taille de chaque élément est4Octets,12*4=48
	
	printf("%d\n", sizeof(a[0][0]));
	//Calcule la taille du premier élément de la première ligne du tableau,intType,La taille est4
	
	printf("%d\n", sizeof(a[0]));
	//a[0]==>*(a+0)==>Le nom du tableau est l'adresse du premier élément,C'est l'adresse de la première ligne,Décochez l'adresse de la première ligne,
	// C'est la première ligne.,Donc la taille de l'élément de la première ligne est calculée 4*4=16
	//a[0] : Première ligne d'un tableau bidimensionnel
	
	printf("%d\n", sizeof(a[0] + 1));
	//a[0]:Nom du tableau pour la première ligne,Adresse représentant le premier élément de la première ligne,a[0]+1::Sauter un élément,
	// C'est l'adresse du deuxième élément de la première ligne,La taille est4/8  
	//Attention!:a[0] + 1 :Pas la deuxième ligne.,a[0]Est le nom du tableau de la première ligne,Adresse du premier élément,
	//C'est l'adresse du premier élément de la première ligne,a[0]+1:Sauter un élément   a+1:aNom du tableau,Adresse du premier élément,Adresse de la première ligne,a+1,Sauter une ligne,Deuxième ligne du tableau 2D

	printf("%d\n", sizeof(*(a[0] + 1)));
	//Disponible à partir de:a[0]+1:Première ligne deuxième élément adresse, *(a[0]+1):C'est le deuxième élément de la première ligne intType La taille est4

	printf("%d\n", sizeof(a + 1));
	//aEst le nom du tableau d'un tableau bidimensionnel->Adresse du premier élément,eAdresse de la première ligne du tableau 2D,+1,Sauter une ligne,C'est l'adresse de la deuxième ligne->Adresse,La taille est4/8

	printf("%d\n", sizeof(*(a + 1)));
	//Par ici.,a+1Est l'adresse de la deuxième ligne,*(a+1)Est la deuxième ligne,La taille est4*4 = 16

	printf("%d\n", sizeof(&a[0] + 1));
	//a[0]Est le nom du tableau de la première ligne,&a[0]C'est l'adresse de la première ligne,
	//(C'est tout.,La relation entre le nom du tableau et le nom du tableau d'adresses,Les deux adresses ont la même valeur,Mais le sens est différent.),&a[0]+1:Sauter la première ligne,Est l'adresse de la deuxième ligne,Adresse:4/8

	printf("%d\n", sizeof(*(&a[0] + 1)));
	//Par ici.:(&a[0]+1):Adresse de la deuxième ligne,La non - référence est la deuxième ligne,La taille est4*4 = 16

	printf("%d\n", sizeof(*a));
	//Le nom du tableau 2D est l'adresse du premier élément,C'est l'adresse de la première ligne,La première ligne est la non - référence, La taille est4* 4  = 16

	printf("%d\n", sizeof(a[3]));
	//a[3]Hypothèse d'existence,C'est le nom du tableau de la quatrième ligne,sizeof(a[3])L'équivalent d'une liste de tableaux placée seule danssizeofInterne,La taille de la quatrième ligne est calculée, 4*4 = 16
	//sizeofL'expression interne ne participe pas à l'opération,C'est - à - dire qu'il n'y a pas vraiment d'accèsa[3]De l'espace,Il n'y a pas d'erreur.,Il ne regarde que le type de la quatrième ligne,Ne pas vraiment accéder au contenu de la quatrième ligne,

	return 0;
}

Le résultat de la procédure suivante est :( )

int main()
{
  int aa[2][5] = {10,9,8,7,6,5,4,3,2,1};
  int *ptr1 = (int *)(&aa + 1);
  int *ptr2 = (int *)(*(aa + 1));
  printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
  return 0;
}

&aaLe type deint (*)[2][5], Une action supplémentaire provoque un saut int [2][5]Longueur, Juste au - delà de la limite. . À la dernière position après moins un. 1Division.*(aa + 1)équivalent àaa[1], C'est la première adresse de la deuxième ligne. ,Bien sûr.5Emplacement.Après moins un, en raison de la continuité de l'espace de tableau multidimensionnel, Va revenir à la fin de la ligne précédente 6Division

Le résultat de la procédure suivante est :( )

int main()
{
  int a[5] = {5, 4, 3, 2, 1};
  int *ptr = (int *)(&a + 1);
  printf( "%d,%d", *(a + 1), *(ptr - 1));
  return 0;
}

 *(a + 1)équivalent àa[1],Le premier est4,aLe type deint [5],&aLe type deint(*)[5],Est un pointeur de tableau.Voilà.int(*)[5] Type plus un , C'est l'équivalent d'un ajout int [5]Longueur. C'est ce pointeur qui saute. a Tous les éléments , Directement au - delà de la limite. , Puis il a été converti en int * Un de plus. ,C'est l'équivalent d'un pas en avant de cette positionint, Je me sens de plus en plus à l'aise. 1À l'adresse de, Donc le deuxième est 1


Quatre, Fonctions de caractères et de chaînes

J'ai des détails sur mon blog précédent dans cette section , Si vous êtes intéressé, vous pouvez aller à l'archéologie.

Le foie briséC Chaîne avancée + Introduction à la fonction mémoire + Simulation de la fonction de bibliothèque + Analyse des questions d'examen écrit ,Collection recommandée!!!

1,strlen

size_t strlen ( const char * str );

La chaîne est déjà '\0' Comme signe de fin,strlenLa fonction renvoie dans la chaîne '\0' Nombre de caractères précédents(Ne contient pas '\0' ).

La chaîne pointée par le paramètre doit être '\0' Fin.

Notez que la valeur de retour de la fonction estsize_t,Non signé( C'est facile. )

2,strcpy

char* strcpy(char * destination, const char * source );

La chaîne source doit être '\0' Fin.

La chaîne source '\0' Copier dans l'espace cible.

L'espace cible doit être suffisamment grand,Pour s'assurer que la chaîne source peut être stockée.

L'espace cible doit être variable.

3,strcat

char * strcat ( char * destination, const char * source );

La chaîne source doit être '\0' Fin.

L'espace cible doit être assez grand,Contenu qui peut contenir la chaîne source inférieure.

L'espace cible doit être modifiable.

4,strcmp

char * strcmp ( const char * str1, const char * str2)

La première chaîne est supérieure à la deuxième,Renvoie plus de0Nombre de

La première chaîne est égale à la deuxième chaîne,Renvoie0

La première chaîne est inférieure à la deuxième,Renvoie moins de0Nombre de

5,strstr

char * strstr ( const char *, const char * );

6,memcpy

void * memcpy ( void * destination, const void * source, size_t num );

FonctionsmemcpyDesourceL'emplacement denumOctets de données àdestinationEmplacement de la mémoire pour.

Cette fonction rencontre '\0' Ça ne s'arrête pas..

SisourceEtdestinationTout chevauchement,Les résultats copiés ne sont pas définis.

7,memmove

void * memmove ( void * destination, const void * source, size_t num );

EtmemcpyLa différence estmemmoveLes blocs de mémoire source et cible traités par la fonction peuvent se chevaucher.

Si les espaces source et destination se chevauchent,Il faut l'utiliser.memmoveTraitement.

8,Implémenter analogiquement les fonctions de mémoire et de chaîne décrites ci - dessus

memmove Mettre en œuvre des copies qui se chevauchent et des copies qui ne se chevauchent pas 
void* my_memmove(void* dest, const void* src, size_t count)//Entier non signé
{
	// De l'avant à l'arrière 
	assert(dest && src);
	void* ret = dest;
	if (dest < src)
	{
		while (count--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	// De l'arrière à l'avant 
	else
	{
		while (count--)
		{
			*((char*)dest + count) = *((char*)src + count);
		}
	}
	return ret;
}

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9 };
	my_memmove(arr + 2, arr, 16);
	//my_memmove(arr, arr + 2, 16);
	return 0;
}
my_memcpy(void* dest, const void* src, size_t count)
{
	void* set = dest;
	assert(dest && src);
	while (count--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return  set;
}

int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7 };
	int arr2[20] = { 0 };
	my_memcpy(arr2, arr1, 40);//Copie des données entières
	int i = 0;
	for (i = 0; i < 20; i++)
	{
		printf("%d", arr2[i]);
	}
	return 0;
}

char* my_strstr(const char*str1, const char* str2)
{
	assert(str1 && str2);
	char* s1;
	char* s2;
	char* cp = str1;
	if (*str2 == '\0')
		return str1;
	while (*cp)
	{
		s1 = cp;
		s2 = str2;
		//while (*s1!='\0'  && *s2 != '\0' && *s1 == *s2)
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return cp;
		}
		cp++;
	}
	//Impossible de trouver
	return NULL;
}


int main()
{
	char arr1[] = "i am good student, hehe student";
	char arr2[] = "student";
	//Trouverarr1Moyennearr2Emplacement de la première occurrence
	char *ret = my_strstr(arr1, arr2);
	if (ret == NULL)
	{
		printf("Impossible de trouver\n");
	}
	else
	{
		printf("%s\n", ret);
	}
	return 0;
}

#include<string.h>
#include<stdio.h>
#include<assert.h>
my_strcat(char* dest, const char* src)
{
	assert(dest && src);


	// a b c \0
	// d e f \0
	//1,Trouver la fin de la chaîne de destination\0
	//2,Ajouter une chaîne jusqu'à\0
	//Le type de retour estchar*,stractRenvoie l'adresse de départ de l'espace cible
	char* ret = dest;
	while (*dest)
	{
		dest++;
	}
	//AvecstrcpyAjouter l'égalité
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
	//Le type de retour estchar*,stractRenvoie l'adresse de départ de l'espace cible
}


int main()
{
	//strcpyCopie de chaîne\0C'est un signe d'arrêt
	//stractConnexion à chaîne
	char arr1[20] = "abc";//Assurez - vous que les données peuvent être mises dans
	char arr2[20] = { 'd','e','f' };//Aucune\0Il y aura des problèmes avec le programme
	char arr3[20] = { 'd','e','f' ,'\0' };//Écrivez correctement
	my_strcat(arr1, arr3);
	printf("%s\n", arr1);
	return 0;
}

int my_strcmp(const char* s1,const char* s2)
{
	assert(s1 && s2);
	// a b c d e \0
	// a d n \0
	//cAvecnPas égal,ComparaisonassicValeur
	// a b c \0
	// a b c \0
	//Équivalence
	while (*s1 == *s2)
	{
		if (*s1 == '\0')
		{
			return 0;
		}
		s1++;
		s2++;
	}
	return *s1 - *s2;//La première chaîne est plus petite que la seconde,Renvoie un nombre négatif


}


int main()
{
	char arr1[] = "asihvw";
	char arr2[] = "asns";
	//Comparez les chaînes une par une
	//Il y a trois possibilités pour les valeurs de retour
	//Trouver l'égalité\0,Arrête,Les résultats sont les suivants:0;
	//Les différentes comparaisons correspondent à la chaîneassicValeur du Code
	int ret = my_strcmp(arr1, arr2);
	if (ret == 0)
	{
		printf("=\n");
	}
	else if (ret < 0)
	{
		printf("<\n");
	}
	else
	{
		printf(">\n");
	}
	printf("%d\n", ret);
	return 0;
}

char* my_strcpy(char* dest, const char* src)
{
	assert(dest && src);
	char* ret = dest;
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[] = "xxxxxxxx";
	char arr2[] = "abc";
	printf("%s\n", my_strcpy(arr1, arr2));
	return 0;
}

int my_strlen(const char* str)
{
	int count = 0;
	while (*str !='\0')
	{
		count++;
		str++;
	}
	return count;
}


int main()
{
	char arr1[] = "sfsgssg";
	int ret = my_strlen(arr1);
	printf("%d",ret);
	return 0;
}


 Cinq,Type personnalisé:Structure,Enumeration,Union européenne

1,Structure

Déclaration de la structure

struct tag
{
 member-list;
}variable-list;

Auto - référence de la structure

struct Node
{
 int data;
 struct Node* next;
};

Définition et initialisation des variables structurelles

int x, y;
struct Point
{
	int x;
	int y;
}p1; //Définir les variables tout en déclarant le typep1
struct Point p2; //Définir les variables structurellesp2
//Initialisation:Définir la variable avec la valeur initiale.
struct Point p3 = { x, y };
struct Stu        //Déclaration de type
{
	char name[15];//Nom
	int age;      //Âge
};
struct Stu s = { "zhangsan", 20 };//Initialisation
struct Node
{
	int data;
	struct Point p;
	struct Node* next;
}n1 = { 10, {4,5}, NULL }; //Initialisation de la nidification structurelle
struct Node n2 = { 20, {5, 6}, NULL };// Structure imbriquée initiale h,

Alignement de la mémoire structurelle

Cette section est détaillée sur mon blog précédent , Je vous suggère d'accueillir les archéologues. ,Ne pas comprendre l'alignement de la structure

️IllustrationCAlignement des structures linguistiques,Cours de baby - sitting,Collection recommandée️

Règles d'alignement des structures

1,Le premier membre de la structure est toujours décalé de la position de départ de la structure à0Adresse

2,Structure du deuxième membre,Un multiple entier toujours placé dans un nombre aligné
   Nombre d'alignements = Le nombre par défaut d'alignement du compilateur et la plus petite valeur de la taille de la variable elle - même

3,. La taille totale de la structure est le nombre maximal d'alignements(Chaque variable membre a un numéro d'alignement)Nombre entier de fois de.

4,Si la structure est imbriquée,Les structures imbriquées sont alignées à un multiple entier de leur propre alignement maximum,La taille globale de la structure est le nombre maximum d'alignements(Nombre d'alignements avec des structures imbriquées)Nombre entier de fois de.
 

Pourquoi l'alignement de la mémoire existe

1. Raisons de la plateforme(Raison de la transplantation): Toutes les plates - formes matérielles n'ont pas accès à toutes les données à n'importe quelle adresse;Certaines plates - formes matérielles ne peuvent Obtenir certains types de données à certaines adresses,Sinon, une exception matérielle est lancée.

2. Raisons du rendement: Structure des données(Surtout la pile.)Doit être aligné autant que possible sur les limites naturelles. La raison en est que, Pour accéder à un Mémoire,Le processeur nécessite deux accès à la mémoire;L'accès à la mémoire aligné ne nécessite qu'un seul accès.


int main()
{
	struct S1
	{
		char c1;
		int i;
		char c2;
	};
	printf("%d\n", sizeof(struct S1));
	return 0;
}

 c1Décalage au début de la structure0Adresse.

iEst le deuxième membre,Un multiple entier toujours placé dans un nombre aligné,Nombre d'alignements = Le nombre par défaut d'alignement du compilateur et la plus petite valeur de la taille de la variable elle - même,iEn soi4,VsPar défaut8,Nous avons choisi de4C'est parti.,Jeter tout au milieu.

c2Est lui - même un octet,Par rapport àVs8Oui.1.

Disponible en vertu de la règle 3:La taille totale de la structure est le nombre maximal d'alignements(Chaque variable membre a un numéro d'alignement)Nombre entier de fois de.

Nombre maximum aligné4,En ce moment, notre mémoire8,La taille totale est9,Continuez à reculer.11,La taille totale est12,- Oui.4Nombre entier de fois de,Respect de la règle 3.

int main()
{
    struct S1
    {
        char c1;  //Taille des octets1 VsPour8 Donc pour1
        int i;    //Taille des octets4 VsPour8 Donc pour4
        char c2;  //Taille des octets1 VsPour8 Donc pour1
    };
    printf("%d\n", sizeof(struct S1));
    return 0;
}

c1Décalage au début de la structure0Adresse.

c2Est le deuxième membre,Un multiple entier toujours placé dans un nombre aligné,Nombre d'alignements = Le nombre par défaut d'alignement du compilateur et la plus petite valeur de la taille de la variable elle - même,c2En soi1,VsPar défaut8,Nous avons choisi de1C'est parti..

iEn soi4Octets,Par rapport àVs8Oui.4.

Disponible en vertu de la règle 3:La taille totale de la structure est le nombre maximal d'alignements(Chaque variable membre a un numéro d'alignement)Nombre entier de fois de.

Nombre maximum aligné4,En ce moment, notre mémoire7,La taille totale est8,- Oui.4 Multiple entier de,Respect de la règle 3.


int main()
{
	struct S3
	{
		double d;
		char c;
		int i;
	};
	printf("%d\n", sizeof(struct S3));
	return 0;
}

dDécalage au début de la structure0Adresse.

cEst le deuxième membre,Un multiple entier toujours placé dans un nombre aligné,Nombre d'alignements = Le nombre par défaut d'alignement du compilateur et la plus petite valeur de la taille de la variable elle - même,c2En soi1,VsPar défaut8,Nous avons choisi de8C'est parti..

iEn soi4Octets,Par rapport àVs8Oui.4.Mais il doit partir de12C'est parti.,Parce que la mémoire est9,Pour se conformer à la règle 2.

Disponible en vertu de la règle 3:La taille totale de la structure est le nombre maximal d'alignements(Chaque variable membre a un numéro d'alignement)Nombre entier de fois de.

Nombre maximum aligné4,En ce moment, notre mémoire15,La taille totale est16,- Oui.8Nombre entier de fois de,Respect de la règle 3.

int main()
{
    struct S3
    {  
        double d;     
        char c;        
        int i;         
    };
    printf("%d\n", sizeof(struct S3));
    struct S4
    {
        char c1;       //
        struct S3 s3;
        double d;
    };
    printf("%d\n", sizeof(struct S4));
    return 0;
}

 c1Décalage au début de la structure0Adresse.

La quatrième règle permet d'obtenir l'alignement de la structure imbriquée à un multiple entier de son alignement maximal,S3Le multiple entier maximum est8,Nous devons donc8C'est parti.,Rejet intermédiaire,StructureS3En soi16,Extension vers l'arrière16À23.

dPour8Octets,De24Début de la conformité aux règles

Disponible en vertu de la règle 3:La taille totale de la structure est le nombre maximal d'alignements(Chaque variable membre a un numéro d'alignement)Nombre entier de fois de.

Nombre maximum aligné16,En ce moment, notre mémoire23,La taille totale est24,Continuez à avancer.31,La taille totale est32,- Oui.16Nombre entier de fois de,Respect de la règle 3.

 In32 Environnement du système bit , Les options de compilation sont: 4Alignement des octets,Alorssizeof(A)Etsizeof(B)- Oui.( )

struct A
{
 int a;
 short b;
 int c;
 char d;
};
struct B
{
 int a;
 short b;
 char c;
 int d;
};

Les deux structures sont orientées intRegarde..StructureAMoyenne,a Aligner un seul 4Octets,b+cPlus que4Octets,Alors...b Aligner un seul 4Octets,c Aligner un seul 4Octets,Il en reste un.d Aligner un seul 4Octets,Total16Octets.StructureBMoyenne,a Aligner un seul octet de quatre octets ,b+c+d C'est tout. 4Octets,Alors...bEtc Aligner un ensemble 4Octets,d Aligner un seul 4Octets,Total12Octets

Le résultat du code suivant est:( )

#pragma pack(4)/*Options de compilation,Représentation4Alignement des octets Plate - forme:VS2013.Langues:CLangues*/
int main(int argc, char* argv[])
{
  struct tagTest1
  {
    short a;
    char d; 
    long b;   
    long c;   
  };
  struct tagTest2
  {
    long b;   
    short c;
    char d;
    long a;   
  };
  struct tagTest3
  {
    short c;
    long b;
    char d;   
    long a;   
  };
  struct tagTest1 stT1;
  struct tagTest2 stT2;
  struct tagTest3 stT3;

  printf("%d %d %d", sizeof(stT1), sizeof(stT2), sizeof(stT3));
  return 0;
}
#pragma pack()

Les trois structures sont les plus longues 4OctetslongRegarde..Le premiera+d+b Juste plus que 4Octets,Alors...aEtd Aligner un ensemble 4Octets, Les deux autres sont seuls. ,Total12Octets, Deuxième Homologie c,d Aligner Un octet de quatre octets ensemble ,C'est aussi12Octets. Troisièmement, parce que c+b,d+aPlus de4Octets, Alors Alignez - vous l'un sur l'autre. 4Octets,Total16Octets.

InVS2013En bas.,La taille de l'espace que cette structure occupe est( )Octets

typedef struct{
  int a;
  char b;
  short c;
  short d;
}AA_t;

16, Voir la méthode de calcul ci - dessus.

Segment

La Déclaration et la structure des segments de bits sont similaires,Il y a deux différences:

1.Les membres du segment doivent être: int、unsigned int Ousigned int .

2.Le nom du membre du segment bit est suivi d'un point - virgule et d'un numéro.

struct A
{
 int _a:2;
 int _b:5;
 int _c:10;
 int _d:30;
};

Allocation de mémoire pour les segments de bits

1. Les membres d'un segment peuvent être int unsigned int signed int Ou char (Appartenant à la famille des plasticiens)Type

2. Les segments de bits sont situés dans l'espace nécessaire pour4Octets( int )Ou1Octets( char )Pour ouvrir.

3. Les segments comportent de nombreuses incertitudes,Le segment BIT n'est pas multiplateforme,Les programmes axés sur la portabilité devraient éviter d'utiliser des segments de bits.

struct S
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};
int main()
{
	struct S s = { 0 };
	s.a = 10;
	s.b = 12;
	s.c = 3;
	s.d = 4;
	return 0;
}

Problèmes de plate - forme croisée pour les segments de bits

1. int Il n'est pas certain que les segments soient traités comme des nombres signés ou non signés.

2. Le plus grand nombre de bits dans le segment de bits n'est pas certain.(16Bit machine Max.16,32Bit machine Max.32,Écrit comme suit:27,In16Ordinateur local Ça va mal tourner. .

3. Les membres du segment bits sont attribués de gauche à droite en mémoire,Ou les critères d'attribution de droite à gauche n'ont pas été définis.

4. Lorsqu'une structure contient deux segments,Le deuxième segment est plus grand,Impossible de s'adapter aux bits restants du premier segment de bits,- Oui. Abandonner les bits restants ou utiliser ,C'est incertain..

Par rapport à la structure,Les segments peuvent avoir le même effet,Mais ça économise de l'espace.,Mais il y a un problème multiplateforme.

2,Enumeration

Définition du type d'énumération

enum Day//Semaine
{
 Mon,
 Tues,
 Wed,
 Thur,
 Fri,
 Sat,
 Sun
};

Avantages de l'énumération

1. Augmenter la lisibilité et la maintenabilité du Code

2. Et#defineL'énumération de comparaison d'identificateurs définie a une vérification de type,Plus de rigueur.

3. Prévention de la contamination par le nom(Encapsulation)

4. Facile à déboguer

5. Facile à utiliser,Plusieurs constantes peuvent être définies à la fois

3,Union européenne(La communauté)

Définition

//Déclaration de type Union
union Un
{
 char c;
 int i;
};
//Définition des variables fédérées
union Un un;
//Calculer la taille des variables contiguës
printf("%d\n", sizeof(un));

Caractéristiques de l'Union

Les membres de la Fédération partagent le même espace mémoire,La taille d'une telle variable fédérée,Au moins la taille du plus grand membre(Parce que L'Union doit au moins avoir la capacité de conserver le plus grand membre).

Calcul de la taille de l'Union

La taille de l'Union est au moins la taille du plus grand membre. Lorsque la taille maximale du membre n'est pas un multiple entier du nombre maximal d'alignement,Est sur le point d'être aligné sur un multiple entier du nombre maximum d'alignement.

union Un1
{
	char c[5];
	int i;
};
union Un2
{
	short c[7];
	int i;
};
//Quel est le résultat de la sortie suivante?
int main()
{
	printf("%d\n", sizeof(union Un1));
	printf("%d\n", sizeof(union Un2));
	return 0;
}

  Il existe les définitions de macro et de structure suivantes:

#define MAX_SIZE A+B
struct _Record_Struct
{
  unsigned char Env_Alarm_ID : 4;
  unsigned char Para1 : 2;
  unsigned char state;
  unsigned char avail : 1;
}*Env_Alarm_Record;
struct _Record_Struct *pointer = (struct _Record_Struct*)malloc
(sizeof(struct _Record_Struct) * MAX_SIZE);

Description: Structure vers la plus longue charAligner, Total des deux premiers éléments de segment 4+2Bits,Pas assez8Bits, Ensemble. 1Octets, Dernier seul 1Octets,Total3Octets.En plus,#define Effectuer une recherche de remplacement , sizeof(struct _Record_Struct) * MAX_SIZE Cette déclaration est en fait 3*2+3,Les résultats sont les suivants:9

Le résultat du code suivant est( )

int main()
{
  unsigned char puc[4];
  struct tagPIM
  {
    unsigned char ucPim1;
    unsigned char ucData0 : 1;
    unsigned char ucData1 : 2;
    unsigned char ucData2 : 3;
  }*pstPimData;
  pstPimData = (struct tagPIM*)puc;
  memset(puc,0,4);
  pstPimData->ucPim1 = 2; 
  pstPimData->ucData0 = 3;
  pstPimData->ucData1 = 4;
  pstPimData->ucData2 = 5;
  printf("%02x %02x %02x %02x\n",puc[0], puc[1], puc[2], puc[3]);
  return 0;
}

A.02 03 04 05

B.02 29 00 00

C.02 25 00 00

D.02 29 04 00

pucC'est uncharTableau, Un octet à la fois , La structure n'est pas ,Il n'a qu'un seul octet pour le premier élément,Les trois autres éléments partagent un octet,Alors...puc Après remplissage de la structure , Seuls deux octets sont écrits en eux - mêmes , Les deux derniers octets doivent être 0,Jusqu'ici.ADExclusion, Et le premier octet est 2C'est2C'est, Le deuxième octet est gênant ,Tout d'abord,ucData0Voilà.3 J'ai dépassé les bornes. ,1 Le nombre de bits ne peut être que 0Ou1,Alors...11 Seulement après la troncature 1,Même chose.ucData1Voilà.4 C'est trop. ,100 Après la troncature 00,Seulement5De101C'est normal.La séquence de remplissage est similaire à la petite extrémité de l'adresse inférieure en bas, Donc l'ordre est 00 101 00 1.C'est - à - dire0010 1001,C'est - à - dire:0x29,Choix judicieuxB.

Le résultat du code suivant est:( )

#include <stdio.h>
union Un
{
	short s[7];
	int n;
};
int main()
{
  printf("%d\n", sizeof(union Un));
  return 0;
}

Orientation de la structureintAligner,7- Oui.shortC'est tout.14Octets,Après l'alignement16Octets.nEst séparé4Octets,Parce que ouiunion,Alors...nAvecsEspace commun,Prenez seulement l'élément le plus long,Donc occupe16Octets.

InX86En bas., Il existe les procédures suivantes:

#include<stdio.h>
int main()
{
  union
  {
    short k;
    char i[2];
  }*s, a;
  s = &a;
  s->i[0] = 0x39;
  s->i[1] = 0x38;
  printf(“%x\n”,a.k);
  return 0;
}

unionSeulement2Octets,2 Octets hexadécimaux seulement 4Bits, Donc la réponse CDExclusion. L'ordre des bits est similaire à la petite extrémité ,L'adresse basse est en bas,Alors...39C'est une adresse basse,En bas,38En haut,Alors c'est3839,

Le résultat du code suivant est:( )

enum ENUM_A
{
		X1,
		Y1,
		Z1 = 255,
		A1,
		B1,
};
enum ENUM_A enumA = Y1;
enum ENUM_A enumB = B1;
printf("%d %d\n", enumA, enumB);

ENUM default from 0C'est parti.,Alors...X1- Oui.0,Donc...Y1- Oui.1, Après avoir donné un nombre, il est poussé vers l'arrière en fonction du nombre ,AlorsZ1- Oui.255,A1- Oui.256,Alors...B1- Oui.257,


Six,Gestion dynamique de la mémoire

Cette section est également détaillée sur mon blog précédent, Bienvenue à l'archéologie

Jouez.C Gestion dynamique de la mémoire linguistique

1,Pourquoi l'allocation dynamique de mémoire existe

La taille de l'ouverture de l'espace est fixe.

Lorsque le tableau est déclaré,La longueur du tableau doit être spécifiée,La mémoire dont il a besoin est allouée au moment de la compilation.

2,Introduction aux fonctions de mémoire dynamique

CLe langage fournit une fonction d'ouverture dynamique de la mémoire

void* malloc (size_t size)

Si l'ouverture réussit,Renvoie un pointeur vers un bon espace.

Si l'ouverture échoue,Renvoie unNULLPointeur,Donc,mallocLa valeur de retour de doit être vérifiée.

Le type de valeur de retour est void* ,Alors...mallocLa fonction ne connaît pas le type d'espace ouvert,L'utilisateur décide lui - même quand il l'utilise..

Si les paramètres size Pour0,mallocLe comportement est standard et non défini,Dépend du compilateur.

CLa langue offre une autre fonctionfree,Spécialement conçu pour la libération et la récupération de la mémoire dynamique

void free (void* ptr);

Si les paramètres ptr L'espace pointé n'est pas dynamique,C'est...freeLe comportement de la fonction n'est pas défini.

Si les paramètres ptr - Oui.NULLPointeur,La fonction ne fait rien..

CLa langue fournit également une fonction appelée calloc , calloc Les fonctions sont également utilisées pour l'allocation dynamique de mémoire.Les prototypes sont les suivants:

void* calloc (size_t num, size_t size);

La fonction est utilisée pour num Les tailles sont size Des éléments qui créent un espace,Et initialiser chaque octet de l'espace à0.

Et fonctions malloc La seule différence est que calloc Chaque octet de l'espace demandé est initialisé à plein avant de retourner l'adresse0.

reallocL'apparition de fonctions rend la gestion dynamique de la mémoire plus flexible. Parfois, nous trouvons trop peu d'espace pour les applications passées,Parfois, on a l'impression qu'il y a trop de place pour postuler.,C'est pour une mémoire raisonnable.

void* realloc (void* ptr, size_t size);

ptr Est l'adresse mémoire à ajuster

size Nouvelle taille après ajustement

La valeur de retour est la position de départ de la mémoire ajustée.

Cette fonction est basée sur la taille de l'espace mémoire original,

Déplace également les données de la mémoire originale dans un nouvel espace.

Ce qui est mal dit sur les fonctions de mémoire dynamique est:( )

A.mallocLa fonction applique un espace continu à la mémoire, Et renvoie l'adresse de départ

B.malloc Échec de la demande d'espace ,RetourNULLPointeur

C.malloc Peut demander à la mémoire 0Octets d'espace

D.malloc Espace mémoire demandé ,Le fait de ne pas procéder à la libération n'aura pas d'incidence sur la procédure

Ne pas libérer crée des fragments de mémoire , Les petits programmes peuvent ne pas prêter attention ,Mais l'impact sur les programmes de taille moyenne et grande est extrêmement profond.Choix judicieuxD.AB Est la fonction de base de la fonction ,C Les options sont spéciales ,malloc(0)C'est permis, Renvoie également un pointeur ,C'est juste qu'il n'y a pas d'espace, donc il n'est pas disponible.

La zone dans laquelle la mémoire appliquée dynamiquement est en mémoire?( )

A.Stack area

B.Zone de gerbage

C.Zone statique

D.Zone de constante de texte

Les allocations de mémoire d'état sont toutes attribuées sur le tas

Lequel des éléments suivants n'est pas une erreur de mémoire dynamique( )

A.freeLe paramètre estNULL

B. Pour la mémoire non dynamique freeRelease

C. Libération multiple de mémoire dynamique

D. Accès hors limite à la mémoire dynamique

AOptions,C'est vrai.,freeTransfert de fonctionsNULLPointeur, Il ne se passe rien.

B,C,DTout est faux.

Ce qui est mal dit sur les fonctions de corrélation dynamique de la mémoire est:( )

A.mallocFonctions etcalloc Les fonctions fonctionnent de la même façon , Est d'appliquer un espace continu .

B.malloc L'espace demandé par la fonction n'est pas initialisé ,callocL'espace demandé par la fonction est initialisé à0

C.reallocLa fonction peut redimensionner dynamiquement la mémoire d'application,Grand ou petit

D.free La fonction ne peut pas être libérée realloc Espace ajusté

 reallocPendant l'opération, l'ancienne allocation d'espace est libérée et un nouvel espace est retourné,Donc le nouvel espace retourné doit aussi être libéré,Choix judicieuxD.AB- Oui.mallocEtcallocLa différence entre.C- Oui.reallocFonctions de base.


Sept,COpérations de fichiers linguistiques

Un blog que j'ai écrit plus tôt a une explication très détaillée de ce chapitre,Cours de baby - sitting,Il est conseillé aux lecteurs de lire et d'étudier cet article avant de faire les exercices suivants,Doubler le résultat avec moitié de travail!!!

️ Je comprends. C Il suffit de lire ceci. (Résumé en dix mille mots, Exercices joints )️

CLangue la façon d'ouvrir un fichier binaire est?( ) 

A.FILE *f = fwrite( "test.bin", "b" );

B.FILE *f = fopenb( "test.bin", "w" );

C.FILE *f = fopen( "test.bin", "wb" );

D.FILE *f = fwriteb( "test.bin" );

Tout d'abord,, Parce que pour ouvrir un fichier ,AD Faites - le sortir. , Parce qu'il n'y en a pas un “fopenb”Fonctions, Alors choisissez directement C. Dans la description binaire b Pour poster les permissions ,C'est - à - dire“wb”C'est légal..

À propos defopen La fonction est incorrecte :( )

A.fopen La façon dont le fichier est ouvert est "r",Si le fichier n'existe pas, Impossible d'ouvrir le fichier

B.fopen La façon dont le fichier est ouvert est "w",Si le fichier n'existe pas, Créer le fichier ,Ouverture réussie

C.fopen La valeur de retour de la fonction n'a pas besoin d'être jugée

D.fopen Le fichier ouvert nécessite fclosePour fermer

CDans les optionsfopenLa valeur de retour pour vérifier si le fichier a été ouvert avec succès, Ouvrir comme "r" C'est particulièrement important. .ABDConcepts et principes de base pour le fonctionnement des documents.

La déclaration suivante concernant le nom et le chemin du fichier est incorrecte:( )

A.Le nom du fichier contient des caractères interdits

B. Le nom du fichier doit contenir un suffixe

C.Le nom du suffixe du fichier détermine la façon par défaut d'ouvrir un fichier

D.Un chemin de fichier est une collection de noms de symboles dans le chemin qui passe de la lettre de lecteur au fichier

BDans les options, Le nom du fichier peut ne pas contenir de suffixe .AEt si, Ces caractères ne peuvent pas être inclus dans le fichier :\/:*?"<>|,C Indique la fonction du nom du suffixe ,D Est le concept de base du chemin .Choix judicieuxB.

CCe qui est incorrect dans la langue en ce qui concerne les fonctions de lecture et d'écriture de fichiers est:( )

A.fgetcEst applicable à toutes les fonctions d'entrée de caractères de flux d'entrée

B.getcharC'est aussi une fonction d'entrée de caractères pour tous les flux

C.fputsEst une fonction de sortie de ligne de texte pour tous les flux de sortie

D.freadEst une fonction d'entrée binaire pour le flux d'entrée de fichier

 BDans les options,getchar Flux d'entrée standard seulement stdin.Même si c'est vrai.stdinRedirection,getchar C'est juste que stdin.fLes fonctions d'entrée et de sortie de la série agissent sur tous les flux,Alors...ACPas de problème!,D Pas de problème non plus. ,fread C'est du travail binaire. .

Quelle est la fonction de la procédure suivante ?  ( )

int main()
{ 
  long num=0;
  FILE *fp = NULL;
  if((fp=fopen("fname.dat","r"))==NULL)
  {
    printf("Can’t open the file! ");
    exit(0):
  }
  while(fgetc(fp) != EOF)
  { 
    num++;
  }
  printf("num=%d\n",num);
  fclose(fp);
  return 0;
}

Le programme n'a ouvert qu'un seul fichier en lecture seule,Utilisé dans le textefgetc,Et non.' 'Et'\n' Statistiques pertinentes , Compter le nombre de caractères du fichier

Ce n'est pas vrai.:( )

A.scanfEtprintf Est pour les entrées standard 、 Entrée formatée du flux de sortie 、Déclarations de sortie

B.fscanfEtfprintf Est pour toutes les entrées 、 Entrée formatée du flux de sortie 、Déclarations de sortie

C.sscanfEst de lire les données formatées à partir d'une chaîne

D.sprintfEst d'écrire les données formatées dans le flux de sortie

DDans les options,sprintfEst d'écrire des données formatées dans une chaîne, Indépendant du flux de sortie .Les trois autres phrases décrivent exactement la fonction.

版权声明
本文为[- Non.]所创,转载请带上原文链接,感谢
https://chowdera.com/2021/10/20211013211336201j.html

随机推荐