Methoden van structuren in c. Een structuur initialiseren in C (c struct)

Stel je nu eens voor: je kunt zelf op een bepaalde manier de soorten gegevens creëren die je nodig hebt en waarmee je gemakkelijk kunt werken! En het is niet moeilijk!

Structuur is een soort unificatie van verschillende variabelen (zelfs met verschillende soorten gegevens) waaraan u een naam kunt toewijzen. U kunt bijvoorbeeld gegevens over het object Huis combineren: stad (waar het huis zich bevindt), straat, aantal appartementen, internet (al dan niet verbonden), etc. in één structuur. Over het algemeen kun je in één set gegevens verzamelen over alles, of beter gezegd, over alles wat een bepaalde programmeur nodig heeft. Het werd voor iedereen meteen duidelijk :)

Als u net begint kennis te maken met structuren in C++, moet u eerst bekend raken met de syntaxis van structuren in de taal C++. Laten we eens kijken naar een eenvoudig voorbeeld dat u zal helpen kennis te maken met structuren en te laten zien hoe u ermee kunt werken. In dit programma gaan we een structuur maken, een structuurobject maken, de structuurelementen (gegevens over het object) vullen met waarden en deze waarden op het scherm weergeven. Nou, laten we beginnen!

#erbij betrekken naamruimte std gebruiken; struct gebouw //Maak een structuur! ( char *eigenaar; //de naam van de eigenaar wordt hier opgeslagen char *city; //naam van de stad int amountKamers; //aantal kamers zwevende prijs; //prijs ); int main() ( setlocale (LC_ALL, "rus"); gebouw appartement1; //dit is een structuurobject met een gegevenstype, structuurnaam, gebouw appartement1.eigenaar = "Denis"; //vul informatie in over de eigenaar, etc. appartement1 .city = "Simferopol"; appartement1.amountRooms = 5;<< "Владелец квартиры: " << apartment1.owner << endl; cout << "Квартира находится в городе: " << apartment1.city << endl; cout << "Количество комнат: " << apartment1.amountRooms << endl; cout << "Стоимость: " << apartment1.price << " $" << endl; return 0; }

IN lijnen 4 - 10 wij creëren structuur. Om het te declareren gebruiken we het gereserveerde woord struct en geven het een, bij voorkeur logische, naam. In ons geval: bouwen. In dit artikel kunt u vertrouwd raken met de regels voor het benoemen van variabelen. Open vervolgens de accolade ( , we vermelden de 4 elementen van de structuur gescheiden door een puntkomma; , sluit de accolade ) en plaats ten slotte een puntkomma; . Dit zal onze sjabloon (vorm) van de structuur zijn.

IN lijn 16 declareer een structuurobject. Net als bij reguliere variabelen moet u het gegevenstype declareren. De naam van onze gecreëerde structuur zal in deze capaciteitsopbouw fungeren.

Hoe structuurelementen vullen (initialiseren) met gegevens? De syntaxis is als volgt: Objectnaam gevolgd door een puntoperator. en de naam van het structuurelement. Bijvoorbeeld: appartement1.eigenaar . Dus, binnen lijnen 18-21 wijs gegevens toe aan structuurelementen.

En dus hebben we de gegevens ingevoerd. De volgende vraag is: "Hoe krijg ik er toegang toe, hoe kan ik ermee werken en hoe kan ik ze in het programma gebruiken?" Het antwoord is: “Heel eenvoudig: hetzelfde als tijdens de initialisatie, met behulp van een punt. en de naam van het structuurelement." IN lijnen 23 - 26 We tonen de voltooide structuurelementen op het scherm.

En dit is wat we als resultaat zullen zien als we ons programma samenstellen:

Eigenaar appartement: Denis Het appartement is gelegen in de stad: Simferopol Aantal kamers: 5 Kosten: $150.000

Wat nog meer belangrijk is om te weten:

  • Het structuurobject kan vóór de functie main() worden gedeclareerd. Het zou er als volgt uitzien:
struct gebouw ( char *eigenaar char *stad; int aantalKamers; vlottende prijs; )appartement1; //verklaring van een object van het type gebouw
  • U kunt de structuur op deze manier initialiseren:
gebouw appartement1 = ("Denis", "Simferopol", 5, 150000);

maar dit gebeurt uiterst zelden;

  • Een structuur kan in andere structuren worden genest (we zullen dit in het volgende voorbeeld bekijken).

Laten we het vorige voorbeeld uitbreiden om extra mogelijkheden te zien voor het werken met structuren.

Voorbeeld:

#erbij betrekken naamruimte std gebruiken; struct date //maak een andere structuur om deze in de gebouwstructuur te nesten // bouwdatum ( char *maand; // Maand waarin het huis werd gebouwd int jaar; // Jaar ); struct gebouw (char *owner; char *city; int amountRooms; float price; bouwdatum; //plaats één structuur in de definitie van de tweede); void show(building object) //maak een functie die een structuur als parameter neemt ( cout<< "Владелец квартиры: " << object.owner << endl; cout << "Квартира находится в городе: " << object.city << endl; cout << "Количество комнат: " << object.amountRooms << endl; cout << "Стоимость: " << object.price << " $" << endl; cout << "Дата постройки: " << object.built.month << " " << object.built.year << endl; } int main() { setlocale (LC_ALL, "rus"); building apartment1; apartment1.owner = "Денис"; apartment1.city = "Симферополь"; apartment1.amountRooms = 5; apartment1.price = 150000; apartment1.built.month = "январь"; apartment1.built.year = 2013; struct building *pApartment; //это указатель на структуру pApartment = &apartment1; //Обратите внимание, как нужно обращаться к элементу структуры через указатель //используем оператор ->uit<< "Владелец квартиры: " << pApartment->eigenaar<< endl; cout << "Квартира находится в городе: " << pApartment->stad<< endl; cout << "Количество комнат: " << pApartment->aantalKamers<< endl; cout << "Стоимость: " << pApartment->prijs<< " $" << endl; cout << "Дата постройки: " << pApartment->gebouwd.maand<< " " << pApartment->bouwjaar<< "\n\n\n"; building apartment2; //создаем и заполняем второй объект структуры apartment2.owner = "Игорь"; apartment2.city = "Киев"; apartment2.amountRooms = 4; apartment2.price = 300000; apartment2.built.month = "январь"; apartment2.built.year = 2012; building apartment3 = apartment2; //создаем третий объект структуры и присваиваем ему данные объекта apartment2 show(apartment3); cout << endl << endl; return 0; }

Opmerkingen over de programmacode:

Lijn 17— het creëren van een object van het gebouwde typedatum in de constructiedefinitie. Lijnen 42 - 43: maak een verwijzing naar de structuurstructuur gebouw *pApartment; en wijs het vervolgens het adres toe van het pApartment = object dat al is gemaakt en gevuld met gegevens. Bij toegang tot structuurelementen via een aanwijzer gebruiken we de -> operator (streepje en > teken). Dit is te zien bij lijnen 47 - 51.

IN lijn 62 laat zien hoe een structuur kan worden geïnitialiseerd. U kunt namelijk een nieuw structuurobject maken en daaraan een object toewijzen dat al is gemaakt en gevuld met gegevens. We geven het structuurobject door aan de show() functie als parameter - lijn 64. Resultaat:

Eigenaar appartement: Denis
Het appartement is gelegen in de stad: Simferopol
Aantal kamers: 5
Kosten: $ 150.000
Bouwjaar: januari 2013
Eigenaar appartement: Igor
Het appartement is gelegen in de stad: Kiev
Aantal kamers: 4
Kosten: $ 300.000
Bouwjaar: januari 2012
Druk op een willekeurige toets om door te gaan. . .

Na analyse van dit voorbeeld zagen we in de praktijk het volgende:

  • een structuur kan binnen een andere structuur worden genest;
  • zag hoe een verwijzing naar een structuur wordt gemaakt;
  • hoe u via een aanwijzer toegang krijgt tot een structuurelement. Namelijk, met behulp van de operator -> ; In het voorbeeld was het zo: apartment0->eigenaar , maar je kunt het ook zo doen (*apartment0).eigenaar . In het tweede geval zijn haakjes vereist.
  • gegevens uit de ene structuur kunnen worden toegewezen aan een andere structuur;
  • Je kunt een structuur als parameter aan een functie doorgeven (structuurelementen kunnen overigens ook als parameter aan een functie worden doorgegeven).

Daarnaast moet worden opgemerkt dat functies ook structuren kunnen teruggeven als resultaat van hun werk. Bijvoorbeeld:

Building Set() ( bouwobject; // objectvorming //... functiecode retourobject; )

Kortom, we hebben kennis gemaakt met structuren in de taal C++, geoefend met voorbeelden en de basis geleerd. Dit is nog maar het begin!

Laatste update: 10/02/2018

Samen met klassen vertegenwoordigen structuren een andere manier om eigen gegevenstypen te creëren in C#. Bovendien zijn veel primitieve typen, bijvoorbeeld int, double, enz., in wezen structuren.

Laten we bijvoorbeeld een structuur definiëren die een persoon vertegenwoordigt:

Structure User ( publieke stringnaam; public int age; public void DisplayInfo() ( Console.WriteLine($"Name: (name) Age: (age)"); ) )

Net als klassen kunnen structs status opslaan als variabelen en gedrag definiëren als methoden. In dit geval worden dus twee variabelen gedefinieerd: naam en leeftijd om respectievelijk de naam en leeftijd van een persoon op te slaan, en de DisplayInfo-methode om informatie over de persoon weer te geven.

We gebruiken deze structuur in het programma:

Systeem gebruiken; naamruimte HelloApp ( struct User ( public string name; public int age; public void DisplayInfo() ( Console.WriteLine($"Name: (name) Age: (age)"); ) ) class Program ( static void Main(string args ) ( Gebruiker tom; tom.name = "Tom"; tom.age = 34; tom.DisplayInfo(); Console.ReadKey(); ) ) )

In dit geval wordt een tom-object gemaakt. Het stelt de waarden van globale variabelen in en geeft er vervolgens informatie over weer.

Constructeurs van constructies

Net als een klasse kan een structuur constructors definiëren. Maar in tegenstelling tot een klasse hoeven we geen constructor aan te roepen om een ​​structuurobject te maken:

Gebruiker tom;

Als we echter op deze manier een structuurobject maken, moeten we alle velden (globale variabelen) van de structuur initialiseren voordat we hun waarden verkrijgen of voordat we de methoden van de structuur aanroepen. Dat wil zeggen dat we in het volgende geval bijvoorbeeld een foutmelding krijgen, omdat velden en methoden worden geopend voordat er initiële waarden aan worden toegewezen:

Gebruiker tom; int x = tom.age; // Fout tom.DisplayInfo(); // Fout

We kunnen ook een standaardconstructor gebruiken om een ​​structuur te maken. Wanneer deze wordt aangeroepen, krijgen de velden van de structuur een standaardwaarde toegewezen (voor numerieke typen is dit bijvoorbeeld het getal 0):

Gebruiker tom = nieuwe gebruiker(); tom.DisplayInfo(); // Naam: Leeftijd: 0

We kunnen ook onze eigen constructors definiëren. Laten we bijvoorbeeld de gebruikersstructuur wijzigen:

Systeem gebruiken; met behulp van System.Reflection; naamruimte HelloApp ( struct User ( publieke stringnaam; public int age; public User(stringnaam, int age) ( this.name = naam; this.age = leeftijd; ) public void DisplayInfo() ( Console.WriteLine($"Name : (naam) Leeftijd: (leeftijd)"); ) ) klasse Programma ( static void Main(string args) ( Gebruiker tom = new User("Tom", 34); tom.DisplayInfo(); Gebruiker bob = new User( ); bob.DisplayInfo(); Console.ReadKey();

Het is belangrijk om te bedenken dat als we een constructor in een structuur definiëren, deze alle velden van de structuur moet initialiseren, omdat in dit geval de waarden voor de naam- en leeftijdsvariabelen worden ingesteld.

Net als bij een klasse kun je een initializer gebruiken om een ​​structuur te maken:

Gebruiker persoon = nieuwe gebruiker (naam = "Sam", leeftijd = 31);

Maar in tegenstelling tot een klasse kunt u de velden van een structuur niet rechtstreeks initialiseren wanneer u ze declareert, bijvoorbeeld als volgt:

Structure User ( public string name = "Sam"; // ! Fout public int age = 23; // ! Fout public void DisplayInfo() ( Console.WriteLine($"Name: (name) Age: (age)"); ))

Een structuur in C is een gegevenstype dat is ontworpen om waarden van verschillende typen in één object te huisvesten. Handig als u meerdere variabelen van verschillende typen onder één naam wilt combineren. Ze maken het programma compacter en eenvoudiger te beheren. Structuur heeft vergelijkbare kenmerken als arrays en klassen.

Arrays

Voordat we het hebben over structuur in C, moeten we een array beschrijven.

Er zijn eendimensionale, tweedimensionale en driedimensionale arrays. Eendimensionaal is er een die slechts één rij heeft met de ingevulde waarden. Tweedimensionaal - een eendimensionale array, waarbinnen zich andere eendimensionale arrays bevinden.

Een reguliere array in C wordt als volgt geschreven: int a = (1, 2, 3, 4).

We zien dat a de naam is, int het gegevenstype, de waarden staan ​​tussen de accolades ( ) en de lengte, dat wil zeggen het aantal elementen, wordt aangegeven tussen de vierkante haakjes. Het aantal elementen is statisch, gelijk aan 4. Dit betekent dat als de gebruiker in dit voorbeeld een vijfde waarde toevoegt, de compiler een fout zal genereren. Als de hoeveelheid in eerste instantie niet bekend is, kunnen deze later worden toegevoegd, maar de waarde wordt niet tussen vierkante haken geplaatst.

Tweedimensionaal wordt op een vergelijkbare manier gedeclareerd. Een array die bijvoorbeeld 5 array-elementen bevat, die elk 3 elementen bevatten, wordt als volgt gedeclareerd: int a. Naar analogie met een eendimensionale array kun je niets toevoegen, om geen compilatiefout te krijgen.

Er zijn dynamische en statische. Statisch is een bestand dat een vaste hoeveelheid gegevens bevat, dat wil zeggen dat het een constante lengte heeft. Met dynamisch bedoelen we een bestand waarvan de omvang niet beperkt is; deze kan veranderen tijdens de uitvoering van het programma. De dynamische array wordt geïnitialiseerd zonder de exacte hoeveelheid op te geven.

Klassen

De klasse en structuur lijken op elkaar, maar verschillen in sommige nuances. Wat is het? Dit is een abstractie die de methoden beschrijft van een object dat nog niet bestaat. Na creatie heeft een object of, zoals het anders wordt genoemd, een instance van een klasse specifieke eigenschappen. Methoden kunnen intern, extern of door overerving worden gebruikt.

De klasse wordt als volgt gedeclareerd:

klasse /*klassenaam*/

/* private access specificifier betekent dat methoden alleen binnen de klasse kunnen worden beheerd*/

/* maakt eigenschappen beschikbaar voor andere delen van de code */

/* overgeërfde klassen krijgen de mogelijkheid om deze eigenschappen te gebruiken */

Wat is structuur in C-taal

Ontworpen om verschillende soorten gegevens op te slaan. Als u bijvoorbeeld een logdirectory wilt maken, heeft u een lijst nodig met de volgende parameters:

  • publicatiedatum;
  • uitgiftenummer;
  • Naam;
  • prijs.

Arrays kunnen worden gebruikt om dit probleem op te lossen.

We declareren een array met datums int datum, getallen int nummer, namen char titel, kosten int prijs.

Door toegang te krijgen tot de index verkrijgen wij de vereiste informatie. De uitvoer van informatie over werk nummer 3 ziet er als volgt uit: cout<< “дата выпуска: ” date “, номер: ” number “, название: ” title “, стоимость: “ price).

De structuur maakt het gemakkelijker om te schrijven en wordt als volgt beschreven:

We zien een van de belangrijkste voordelen: er zijn verschillende soorten variabelen. De programmeur bespaart niet alleen tijd, hij vereenvoudigt de code en in de toekomst zal het veel gemakkelijker voor hem zijn om te werken.

Aankondiging

Structuren in C spelen een zeer belangrijke rol bij het combineren van verschillende typen gegevens.

Eerst moet u de naam van de structuur en eigenschappen opgeven.

Struct is een trefwoord, het begint de declaratie, naam is de naam, type is het gegevenstype, member is de naam van het element.

Het wordt als volgt verklaard:

naam naam2, waarbij naam de naam is die is opgegeven bij het maken van de structuur, en naam2 de naam van de variabele.

U kunt variabelen declareren in de aanmaakfase.

Het eerste en tweede voorbeeld zijn gelijkwaardig aan elkaar.

Als het nodig is om meerdere variabelen te declareren, worden ze gescheiden door komma's weergegeven.

) naam2, naam3, naam4.

Initialisatie

Na declaratie moet de structuur in C worden geïnitialiseerd.

naam2.lid=”een”;

Initialisatie kan plaatsvinden bij het maken.

char lid = “een”;

Een structuur heeft dezelfde syntaxis als een klasse. Ze hebben bijna hetzelfde gedrag en dezelfde capaciteiten. Alles wat zich in de body van een klasse bevindt, is standaard niet beschikbaar voor gebruik door andere objecten.

De structuur heeft het tegenovergestelde: alle velden en methoden zijn openbaar. U kunt de toegangsmodifier handmatig privé instellen en zo de toegang tot andere functies of klassen openen.

Arrays zijn veel componenten van hetzelfde type. Ze bevinden zich naast elkaar en elk van hen is toegankelijk via een numerieke index. Er zijn eendimensionale, tweedimensionale en driedimensionale arrays.

Eendimensionaal heeft slechts één rij en een n-e aantal elementen. De advertentie ziet er als volgt uit:

Een array van structuren in C wordt als volgt gedeclareerd:

In dit voorbeeld hebben we een MyStruct gemaakt met een geheel getal-element genaamd "a". We declareren de variabele obj1 - het is een array, bestaande uit 10 elementen.

Bij het declareren van meerdere arrays van hetzelfde type wordt MyStruct obj1, obj2 gebruikt; initialisatie vindt plaats tijdens de declaratie. Ziet er zo uit:

Het maken van een array van dynamisch toegewezen structuren ziet er precies hetzelfde uit als het maken van een eenvoudige dynamische array. Om dit te doen, wordt een verwijzing naar een C-structuur gebruikt.

Een pointer is een variabele die geen waarde bevat, maar verwijst naar een variabele die een bepaalde waarde heeft. Dienovereenkomstig bevat de pointer het adres van de variabele waarnaar wordt verwezen. Ptr = &var1 betekent bijvoorbeeld dat aan een variabele met een ampersand-teken alleen het adres van de variabele wordt toegewezen, maar niet de waarde zelf. Nu zijn alle waarden van var1 beschikbaar via de pointervariabele ptr.

De bewerking * verwijst naar de inhoud van de cel waarnaar de variabele na dit teken verwijst. *ptr betekent bijvoorbeeld dat het waarden bevat uit de cel met het adres van ptr.

Gebruik de nieuwe bewerking om geheugen toe te wijzen aan dynamische variabelen.

Wij hebben

We selecteren een geheugengedeelte, voeren een bepaalde waarde in MyStruct * punt = nieuwe MyStruct;

Om dynamische variabelen te verwijderen gebruiken we de verwijderbewerking. Om ruimte vrij te maken, typt u delete p;

Toegang

Alle elementen zijn standaard openbaar, dus andere klassen kunnen ze gebruiken. Om sommige waarden in te stellen of te wijzigen, moet u eerst toegang krijgen tot het element en pas daarna de juiste acties uitvoeren.

Maak myStruct met de variabelenaam b.

struct mijnStruct(

Neem contact op met:

en stel een willekeurige waarde in. Bijvoorbeeld b.fio = “Ivanov”.

Laten we dit voorbeeld eens bekijken.

struct mijnStruct(

("Ivanov", 456756),

("Petrov", 632345)

In dit voorbeeld hebben we een array van structuren met tekenreeksen en getallen. Gebruik het volgende om de achternaam Ivanov weer te geven:

uit<< myStruct tel.fio;

Als we de waarde 456756 willen krijgen, voeren we cout uit<< myStruct tel.num.

Structuur en functies

Kan worden gebruikt als functieargument in een C-structuur.

struct mijnStruct(

We hebben een waardevariabele, een tekstreeks van 100 tekens. Maak een menuvariabele van het type myStruct: myStruct-menu. In het volgende voorbeeld neemt de functie een verwijzing naar een structuur als argument, en initialiseert de hoofdtekst van de naamloze functie deze variabelen.

leeg item(myStruct-menu)

sprintf(menu.text,"Eén item");

Conclusie

Een structuur is een set, net als een array, maar alle elementen kunnen van verschillende typen zijn. Zeer vergelijkbaar met een klasse, maar verschilt doordat de standaardeigenschappen beschikbaar zijn voor gebruik door andere klassen, dat wil zeggen dat ze de openbare specificatie hebben.

Gemaakt met behulp van het sleutelwoord struct, en eigenschappen worden gespecificeerd tussen accolades ( ).

De aankondiging vindt plaats in de creatiefase of daarna.

Ik heb onlangs kennis gemaakt met C/C++-structuren - struct. Heer, “waarom zou u ze leren kennen”, zegt u? Je maakt dus twee fouten tegelijk: ten eerste ben ik God niet, en ten tweede dacht ik ook dat structuren ook in Afrika structuren zijn. Maar het bleek: nee. Ik zal je vertellen over een aantal essentiële details die sommige lezers zullen behoeden voor een uur lang debuggen...

Velden in het geheugen uitlijnen

Let op de structuur:

Structure Foo ( char ch; int waarde; );
Allereerst: wat is de grootte van deze structuur in het geheugen? grootte van(Foo) ?
De grootte van deze structuur in het geheugen hangt af van de compilerinstellingen en van de richtlijnen in uw code...

Over het algemeen worden velden in het geheugen uitgelijnd langs een grens die een veelvoud is van hun eigen grootte. Dat wil zeggen dat velden van 1 byte niet zijn uitgelijnd, velden van 2 bytes zijn uitgelijnd op even posities, velden van 4 bytes zijn uitgelijnd op posities die veelvouden van vier zijn, enz. In de meeste gevallen (of laten we aannemen dat dit vandaag het geval is) is de uitlijningsgrootte van de structuur in het geheugen 4 bytes. Dus groottevan(Foo) == 8 . Waar en hoe worden de extra 3 bytes toegevoegd? Als je het niet weet, raad je het nooit...

  • 1 byte: ch
  • 2 bytes: leeg
  • 3 bytes: leeg
  • 4 bytes: leeg
  • 5 bytes: waarde
  • 6 bytes: waarde
  • 7 bytes: waarde
  • 8 bytes: waarde
Laten we nu kijken naar de geheugenplaatsing van de volgende structuur:

Structure Foo ( char ch; korte id; int waarde; );
Het ziet er zo uit:

  • 1 byte: ch
  • 2 bytes: leeg
  • 3 bytes: id
  • 4 bytes: id
  • 5 bytes: waarde
  • 6 bytes: waarde
  • 7 bytes: waarde
  • 8 bytes: waarde
Dat wil zeggen, wat in een uitlijning van 4 bytes kan worden gepropt, wordt er met een knal in gepropt (zonder de grootte van de structuur in het geheugen te vergroten). Laten we nog een veld toevoegen:

Structure Foo ( char ch; korte id; korte opt; int waarde; );
Laten we eens kijken naar de plaatsing van velden in het geheugen:

  • 1 byte: ch
  • 2 bytes: leeg
  • 3 bytes: id
  • 4 bytes: id
  • 5 bytes: opt
  • 6 bytes: opt
  • 7 bytes: leeg
  • 8 bytes: leeg
  • 9 bytes: waarde
  • 10 bytes: waarde
  • 11 bytes: waarde
  • 12 bytes: waarde
Dit is allemaal oh zo triest, maar er is een manier om dit rechtstreeks vanuit de code aan te pakken:

#pragma pack(push, 1) struct Foo ( // ... ); #pragma-pakket(pop)
We hebben de uitlijningsgrootte ingesteld op 1 byte, de structuur beschreven en de vorige instelling geretourneerd. Ik raad ten zeerste aan om de vorige instelling terug te zetten. Anders zou alles heel slecht kunnen aflopen. Ik heb dit een keer meegemaakt: Qt crashte. Ergens heb ik hun.h-bijnaam onder mijn.h-bijnaam opgenomen...

Bitvelden

In de commentaren werd mij erop gewezen dat bitvelden in structuren volgens de standaard zijn "implementatie gedefinieerd"- daarom is het beter om ze niet te gebruiken, maar voor mij is de verleiding te groot...

Ik voel me niet alleen ongemakkelijk in mijn ziel, maar voel me over het algemeen ook slecht als ik in de code bitvelden zie vullen met behulp van maskers en verschuivingen, bijvoorbeeld als volgt:

Niet-ondertekend veld = 0x00530000; // ... veld &= 0xFFFF00FF; veld |= (id)<< 8; // ... field &= 0xFFFFFF83; field |= (proto) << 2;
Dit alles ruikt naar zoveel verdriet en zulke fouten en het debuggen ervan dat ik onmiddellijk migraine krijg! En dan komen ze van achter de schermen: de Bit Fields. Het meest verrassende is dat ze nog steeds in de C-taal waren, maar ik vraag het aan niemand - iedereen hoort er voor het eerst over. Deze puinhoop moet worden gecorrigeerd. Nu zal ik ze allemaal een link geven, of op zijn minst een link naar dit artikel.

Wat vind je van dit stukje code:

#pragma pack(push,1) struct IpHeader ( uint8_t header_length:4; uint8_t versie:4; uint8_t type_of_service; uint16_t total_length; uint16_t identifier; // Flags uint8_t _reserved:1; uint8_t dont_fragment:1; uint8_t more_fragments:1; uint8_t fragment_off set_part1:5; uint8_t fragment_offset_part2; uint8_t tijd_tot_live; #pragma-pakket(pop)
En dan kunnen we in de code met velden werken, zoals we in C/C++ altijd met velden werken. Er wordt allemaal in ploegendienst gewerkt etc. De compiler neemt het over. Natuurlijk zijn er enkele beperkingen... Wanneer u meerdere bitvelden op een rij opsomt die betrekking hebben op hetzelfde fysieke veld (ik bedoel het type dat links van de bitveldnaam verschijnt), geef dan namen op voor alle bits tot aan de einde van het veld, anders heb je geen toegang tot deze bits, oftewel de code:

#pragma pack(push,1) stuct MyBitStruct ( uint16_t a:4; uint16_t b:4; uint16_t c; ); #pragma-pakket(pop)
Het resultaat is een structuur van 4 bytes! De twee helften van de eerste byte zijn de a- en b-velden. De tweede byte is niet toegankelijk op naam en de laatste 2 bytes zijn toegankelijk op naam c . Dit is een zeer gevaarlijk moment. Nadat u de structuur met bitvelden hebt beschreven, moet u de grootte ervan controleren!

Ook is de volgorde waarin de bits in een byte worden geplaatst afhankelijk van de bytevolgorde. Met de volgorde LITTLE_ENDIAN worden bitvelden verdeeld vanaf de eerste bytes, met BIG_ENDIAN - vice versa...

Bytevolgorde

Ik ben ook bedroefd door de aanroepen van de functies htons() , ntohs() , htonl() , nthol() in C++-code. In C is dit nog steeds mogelijk, maar niet in C++. Ik zal hier nooit mee in het reine komen! Let op, al het volgende is van toepassing op C++!

Nou, ik zal het hier kort houden. In een van mijn vorige artikelen schreef ik al wat er met byte-orders moet gebeuren. Het is mogelijk om structuren te beschrijven die extern als getallen werken, maar intern bepalen ze zelf de opslagvolgorde in bytes. Onze IP-headerstructuur ziet er dus als volgt uit:

#PRAGMA PACK (Push, 1) Struct IPHEADER (Uint8_T Header_LENGTH: 4; UINT8_T VERSION: 4; UINT8_T TYPE_OF_SERVICE; U16BE TOTAL_LENGTH; U16BE IDENTIC T _Reserved: 1; :5; uint8_t fragment_offset_part2; uint8_t time_to_live; u16be checksum; #pragma-pakket(pop)
Besteed aandacht aan de soorten velden van 2 bytes - u16be. Nu hebben de structuurvelden geen conversies van bytevolgorde nodig. Er zijn nog steeds problemen met fragment_offset , maar degenen die ze niet hebben, hebben problemen. Niettemin kun je ook een sjabloon bedenken die deze schande verbergt, het een keer testen en het gerust in je hele code gebruiken.

“De taal C++ is complex genoeg om ons in staat te stellen er eenvoudig in te schrijven.” Vreemd genoeg - ik

ZY In een van de volgende artikelen ben ik van plan om, vanuit mijn gezichtspunt, de ideale structuren uiteen te zetten voor het werken met protocolheaders van de TCP/IP-stack. Praat terug - voordat het te laat is!

Voordat we klassen in C++ gaan bestuderen, zullen we kijken naar een gegevenstype dat lijkt op een klasse: structs. Structuren zijn handig wanneer we verschillende variabelen van verschillende typen onder één naam moeten combineren. Dit maakt het programma compacter en flexibeler om wijzigingen door te voeren. Structuren zijn ook onmisbaar als het nodig is om bepaalde gegevens te groeperen, bijvoorbeeld een record uit een database of een contactpersoon uit een adresboek. In het laatste geval bevat de structuur contactgegevens zoals naam, adres, telefoonnummer, etc.

Syntaxis

Tijdens het schrijven van een programma moet u mogelijk verschillende gegevens groeperen. Mogelijk wilt u bijvoorbeeld de coördinaten van sommige objecten en hun namen opslaan. Je kunt dit doen met:

Int x_coor; int y_coor; tekenreeksnamen;

Maar omdat elk element van de ene array met een ander element is verbonden, zul je, als je er één verandert, ook de rest moeten veranderen. En hoe meer gegevens je moet combineren, hoe complexer zo'n programma zal zijn. Daarom gebruiken we om verschillende gegevens te combineren structuren .

Advertentie-indeling structuur ziet er als volgt uit:

Structure Car (int x_coor; int y_coor; stringnaam; );

Door een structuur te declareren, introduceren we ons eigen gegevenstype in het programma, dat we op dezelfde manier kunnen gebruiken als standaardtypen, d.w.z. De declaratie van een variabele van ons type zal als volgt zijn:

Structuurnaam variabelenaam;

structName is de naam van de structuur, variabeleName is de naam van de variabele.

x_coor, y_coor en naam - velden onze structuur. Wanneer we een structuur declareren, creëren we een samengesteld gegevenstype dat kan worden gebruikt om variabelen te maken die meerdere waarden combineren (bijvoorbeeld coördinaten en een naam). Binnen de structuur geven we elk veld een naam, zodat we vervolgens met de naam naar deze waarde kunnen verwijzen.

Gebruik een punt om toegang te krijgen tot de velden van de structuur:

// declareer de Car-variabele myCar; // en gebruik het myCar.x_coor = 40; mijnCar.y_coor = 40; mijnCar.name = "Porche";

Zoals u kunt zien, kunt u zoveel velden in de structuur opslaan als u wilt, en deze kunnen verschillende typen hebben.

Laten we eens kijken naar een voorbeeld dat de combinatie van arrays en structuren demonstreert.

#erbij betrekken naamruimte std gebruiken; struct PlayerInfo (int skill_level; stringnaam; ); naamruimte std gebruiken; int main() ( // net als bij reguliere typen kun je een reeks structuren declareren PlayerInfo-spelers; for (int i = 0; i< 5; i++) { cout << "Please enter the name for player: " << i << "\n"; // сперва получим доступ к элементу массива, используя // обычный синтаксис для массивов, затем обратимся к полю структуры // с помощью точки cin >> spelers[ i ].naam;<< "Please enter the skill level for " << players[ i ].name << "\n"; cin >uit< 5; ++i) { cout << players[ i ].name << " is at skill level " << players[i].skill_level << "\n"; } }

> spelers[ i ].skill_level;

) voor (int i = 0; ik

Net als bij eenvoudige typen (bijvoorbeeld int), kunt u arrays van structuren maken. En werk met elk element van deze array op dezelfde manier als met een afzonderlijke variabele. Om toegang te krijgen tot het naamveld van het eerste element van een reeks structuren, schrijft u eenvoudigweg:

Spelers[ 0 ].naam

Structuren en functies

Heel vaak moet je functies schrijven die structuren als argumenten gebruiken of een structuur retourneren. Als je bijvoorbeeld een arcadespel met een kleine ruimte moet schrijven, heb je mogelijk een functie nodig om een ​​nieuwe vijand te initialiseren:

Structureer EnemySpaceShip ( int x_coördinaat; int y_coördinaat; int wapen_kracht; ); EnemySpaceShip getNewEnemy();

De functie getNewEnemy zou een structuur met geïnitialiseerde velden moeten retourneren:

EnemySpaceShip getNewEnemy() ( EnemySpaceShip schip; ship.x_coördinaat = 0; ship.y_coördinaat = 0; ship.weapon_power = 20; retourschip; )

Deze functie retourneert feitelijk een kopie van het gemaakte lokale variabele schip. Dit betekent dat elk veld van de structuur naar een nieuwe variabele wordt gekopieerd. In ons geval valt het kopiëren van een klein aantal velden niet op, maar als je met grote hoeveelheden data werkt, moet je onnodige handelingen vermijden. Hierover vertellen we meer in het artikel over pointers.

Om een ​​nieuwe variabele te verkrijgen, gebruiken we dus de volgende code:

EnemySpaceShip-schip = getNewEnemy();

Nu kan deze variabele als een reguliere structuur worden gebruikt.

U kunt structuren als volgt aan een functie doorgeven:

EnemySpaceShip-upgradeWapens (EnemySpaceShip-schip) ( ship.weapon_power += 10; retourschip; )

Wanneer we een structuur doorgeven aan een functie, wordt deze gekopieerd, net zoals wanneer we een structuur retourneren. Daarom gaan alle wijzigingen die binnen de functie zijn aangebracht verloren, dus retourneren we de structuur na de wijziging.

De functie gebruiken:

Schip = upgradeWapens(schip);

Structureer EnemySpaceShip ( int x_coördinaat; int y_coördinaat; int wapen_kracht; ); EnemySpaceShip getNewEnemy() ( EnemySpaceShip schip; ship.x_coördinaat = 0; ship.y_coördinaat = 0; ship.weapon_power = 20; retourschip; ) EnemySpaceShip upgradeWeapons(EnemySpaceShip schip) ( ship.weapon_power += 10; retourschip; ) int main () ( EnemySpaceShip vijand = getNewEnemy(); vijand = upgradeWapens(vijand); )

Wegwijzers

Als u met een structuur werkt, moet u voor toegang tot variabelen de operator “->” gebruiken in plaats van een punt. Alle aanwijzereigenschappen blijven ongewijzigd. Voorbeeld:

#erbij betrekken naamruimte std gebruiken; struct xampl(int x;); int main() ( xampl structuur; xampl *ptr; structure.x = 12; ptr = cout<< ptr->X; cin.get(); )