Arrays en strings in C
BeginnerLes 3 van 8 in Cursus Programmeren in C: pointers, geheugenbeheer en debuggen
Wat je leert
- Declareer arrays met een vaste grootte, benader elk element via zijn index, doorloop de arrays zonder voorbij het einde te gaan en deel ze met functies.
- Declareer en initialiseer een array en benader de elementen met een indexMaak arrays met een vast aantal elementen, geef ze beginwaarden en lees of wijzig afzonderlijke elementen via hun index.
- Doorloop arrays zonder de grenzen te overschrijdenBezoek elk element met een tellende lus en gebruik dat patroon om op te tellen, de grootste waarde te vinden, te zoeken, te tellen en om te keren.
- Geef arrays door aan functiesSchrijf functies die arrays als parameters ontvangen, geef de lengte apart mee en weet wanneer de functie de gegevens van de aanroepende functie kan wijzigen.
- Declareer en initialiseer een array en benader de elementen met een index
- Behandel tekens als kleine geheeltallige codes, sla tekst op in
char-arrays die eindigen op een nulteken, verwerk tekst teken voor teken en bekijk hoe UTF-8-tekst in bytes past.- Behandel tekens als numerieke codesGebruik het type
charen tekenconstanten als getallen, converteer cijfers en letters met berekeningen en classificeer tekens met<ctype.h>. - Sla tekst op als strings die eindigen op een nultekenLeg uit hoe een C-string in een
char-array is opgebouwd, waarom die een afsluitend nulteken nodig heeft en hoe stringliterals en arrays verschillen. - Verwerk strings teken voor tekenDoorloop een string tot het afsluitende nulteken om tekst te tellen, converteren, omkeren, filteren en versleutelen, en sluit elke nieuwe string af met
'\0'. - Leg uit hoe UTF-8-tekst in char-arrays wordt opgeslagenBreng tekens, Unicode-codepunten en UTF-8-bytes met elkaar in verband en voorspel wat bytegebaseerde C-functies doen met tekst buiten ASCII.
- Behandel tekens als numerieke codes
- Bepaal de lengte van strings, kopieer, voeg samen, vergelijk en doorzoek ze met
<string.h>, en zorg dat elke doelarray ruimte heeft voor het resultaat en het afsluitende nulteken.- Bepaal de lengte van strings, kopieer ze en voeg ze samenGebruik
strlen,strcpyenstrcatcorrect en bepaal hoeveel ruimte elke doelarray nodig heeft. - Vergelijk en doorzoek stringsVergelijk strings met
strcmpenstrncmp, zoek tekens en deelstrings en splits tekst in tokens. - Kopieer binnen de grenzen en werk rechtstreeks met geheugenbytesGebruik de begrensde functies
strncpy,strncatensnprintfcorrect, detecteer afkapping en kopieer, vul en vergelijk hele arrays met de geheugenfuncties.
- Bepaal de lengte van strings, kopieer ze en voeg ze samen
- Sla tabellen en lijsten met strings op in arrays met twee of meer dimensies, doorloop ze met geneste lussen en geef ze door aan functies.
- Declareer en doorloop tweedimensionale arraysDeclareer en initialiseer tabellen met waarden, leg uit hoe hun rijen in het geheugen zijn geplaatst en verwerk rijen en kolommen met geneste lussen.
- Geef tabellen door aan functies en sla lijsten met strings opSchrijf functies die tweedimensionale arrays ontvangen en bewaar meerdere strings in een 2D-
char-array of in een array van stringpointers.
- Declareer en doorloop tweedimensionale arrays
- Lees via
argcenargvde woorden die na de naam van een programma zijn getypt, controleer hoeveel het er zijn en zet ze veilig om in getallen en opties.- Lees argc en argvDeclareer
mainmet zijn twee parameters, beschrijf wat elk element vanargvbevat en controleer het aantal argumenten voordat je een argument gebruikt. - Converteer en valideer numerieke argumentenZet argumentstrings om in getallen met foutcontrole, wijs ongeldige invoer af en controleer het waardenbereik voordat je waarden gebruikt.
- Lees argc en argv
- Herken hoe C-programma’s buiten hun arrays lezen en schrijven, waarom dat gevaarlijk is en hoe je tekst zo leest en kopieert dat die altijd past.
- Herken toegang buiten de grenzen en de gevolgen daarvanLeg uit waarom C toegang buiten de grenzen niet tegenhoudt, wat er kan gebeuren als dit voorkomt en welke fouten het veroorzaken.
- Lees en kopieer tekst binnen de grenzen van de bufferLees invoer met een maximale lengte, detecteer regels die te lang zijn en kopieer tekst alleen als die in de doelarray past.
- Herken toegang buiten de grenzen en de gevolgen daarvan
Arrays en strings in C: uitleg
1Sla verzamelingen waarden op in arrays en verwerk ze
Met arrays kan één lus op veel samenhangende waarden werken. De array bepaalt hoeveel opslagruimte er is, terwijl indexen afzonderlijke elementen selecteren en een teller bijhoudt hoeveel elementen in gebruik zijn. Leer hoe declaraties beginwaarden vastleggen, hoe lussen resultaten berekenen zonder een grens te overschrijden en hoe functies de elementen van de aanroepende functie delen. Kleine voorbeelden verbinden de code met de exacte posities die ze leest of beschrijft.
1.1 Declareer en initialiseer een array en benader de elementen met een index
Een array geeft één naam aan een vast aantal waarden van hetzelfde type. De elementen staan naast elkaar in het geheugen. Gebruik een array wanneer dezelfde bewerking op veel waarden van toepassing is, zoals bij het bijwerken van een verzameling scores.
Maak de elementen
int scores[5] = {90, 72, 85, 64, 99};
int primes[] = {2, 3, 5, 7};
int counts[6] = {0};
De eerste declaratie maakt vijf gehele getallen. De compiler telt vier waarden in de tweede initialisator, dus primes heeft vier elementen. In de derde is het eerste element expliciet nul en wordt ook elke ontbrekende initialisatiewaarde nul. Zo bevat int a[5] = {1, 2}; de waarden 1, 2, 0, 0, 0. Een benoemde initialisator, beschikbaar sinds C99, kiest een positie: int b[5] = {[2] = 7}; zet 7 in het derde element en nul in de andere.
Een automatische lokale declaratie zoals int data[5]; reserveert ruimte zonder beginwaarden te geven. Schrijf elk element voordat je het leest. Arrays die buiten alle functies zijn gedeclareerd en arrays die met static zijn gedeclareerd, worden op nul geïnitialiseerd als er geen expliciete initialisator is opgegeven.
Benader één waarde via de index
Indexen beginnen bij nul. Voor vijf elementen zijn de geldige posities 0 tot en met 4. scores[1] betekent de tweede score, niet de eerste. Je kunt een element overal gebruiken waar een gewone variabele van hetzelfde type kan worden gebruikt:
scores[1] = 75;
scores[1] += 5;
int last = scores[4];
De tweede score is nu 80. De laatste is nog steeds 99. Een index kan een variabele of een expressie zijn, dus scores[n - 1] benadert het laatste element als n het aantal elementen is en positief is. Bij scores[5] is er geen element om te benaderen.
Tel elementen en bytes
sizeof scores meet de hele array in bytes. Op een systeem met gehele getallen van 4 bytes nemen de vijf elementen 20 bytes in. Door te delen door de grootte van één element maak je de uitkomst onafhankelijk van de grootte van een geheel getal:
size_t n = sizeof scores / sizeof scores[0];
printf("%zu\n", n);
Dit drukt 5 af. size_t is het geheelgetaltype zonder teken dat voor groottes wordt gebruikt; %zu drukt het af. Deze berekening werkt waar scores de eigenlijke array aanduidt. Een functieparameter bevat niet de volledige grootte van de array.
Houd grootte en waarden gescheiden
Met een naam zoals #define NUM_SCORES 5 kunnen de declaratie en de bijbehorende lussen één grootte delen. In C17 maakt een lokale const int n = 5; int a[n]; daarentegen een array met variabele lengte: const maakt van n geen geheeltallige constante expressie. De grootte wordt gekozen wanneer de declaratie wordt uitgevoerd en blijft daarna vast gedurende de levensduur van de array. Een initialisatielijst is niet mogelijk. Ondersteuning voor arrays met variabele lengte is optioneel in C11 en C17; C23 voegt constexpr toe voor constanten tijdens compilatie.
Arrays kunnen niet als geheel worden toegewezen: b = a; is ongeldig. Kopieer hun elementen met een lus of een geschikte geheugenfunctie. Voor twee afzonderlijke arrays vergelijkt a == b adressen, geen elementwaarden. Vergelijk overeenkomstige elementen om te testen of de waarden gelijk zijn. Een bytevergelijking met memcmp test daarentegen hun opgeslagen representaties; gelijke drijvendekommawaarden zoals positieve en negatieve nul kunnen verschillende representaties hebben.
Belangrijkste punten
- Array-indexen lopen van 0 tot één minder dan het aantal elementen.
- Ontbrekende initialisatiewaarden worden nul; niet-geïnitialiseerde lokale elementen moet je vóór gebruik beschrijven.
- Gebruik
sizeof a / sizeof a[0]alleen waaraeen echte array is. - Een array behoudt zijn grootte gedurende zijn levensduur.
- Kopieer en vergelijk arraywaarden element voor element.
1.2 Doorloop arrays zonder de grenzen te overschrijden
Een tellende lus verbindt de posities van een array met een bewerking. Bepaal welke elementen bruikbare gegevens bevatten en bezoek dan precies die posities. Hetzelfde patroon ondersteunt totalen, zoekopdrachten en wijzigingen.
Bezoek de gebruikte elementen
int t[5] = {12, 15, 9, 14, 10};
int sum = 0;
for (int i = 0; i < 5; i++) {
sum += t[i];
}
double average = sum / 5.0;
De lus gebruikt de indexen 0, 1, 2, 3 en 4. Het totaal loopt op via 12, 27, 36, 50 en 60, dus het gemiddelde is 12,0. Als je i <= 5 schrijft, voeg je een ongeldige toegang bij index 5 toe. Die extra iteratie is een één-ernaastfout.
Gebruik voor een gemiddelde een drijvendekommagetal bij de deling. Bij een totaal van 61 geeft 61 / 5 het gehele getal 12; 61 / 5.0 geeft 12,2. Als je het eerste resultaat daarna in een double opslaat, kun je het al weggelaten deel achter de komma niet terugkrijgen.
Zoek een maximum of een overeenkomst
Initialiseer bij een niet-lege array het maximum met de eerste waarde:
int max = t[0];
for (int i = 1; i < 5; i++) {
if (t[i] > max) max = t[i];
}
De eerste vergelijking vervangt 12 door 15. De overige waarden zijn kleiner, dus 15 blijft staan. Beginnen met nul zou misgaan bij een lijst zoals {-8, -3, -11}: nul is groter dan elke opgeslagen waarde, maar staat niet in de lijst.
Bij lineair zoeken controleer je de waarden op volgorde:
int found = -1;
for (int i = 0; i < 5; i++) {
if (t[i] == 14) {
found = i;
break;
}
}
Hier wordt found gelijk aan 3. De waarde -1 geeft aan dat er geen overeenkomst is, omdat die geen geldige index kan zijn. Meld pas dat er niets is gevonden nadat alle kandidaten zijn gecontroleerd. Als je na het eerste ongelijke element -1 teruggeeft, mis je overeenkomsten verderop in de array.
Tel en herschik
Een frequentiearray slaat per categorie één teller op. Voor cijfers biedt int counts[10] = {0}; de tellers 0 tot en met 9. Nadat je d >= 0 && d < 10 hebt gecontroleerd, verhoogt counts[d]++ de teller voor cijfer d. De controle beschermt de array wanneer de cijferwaarde uit invoer komt.
Om een array om te keren, wissel je paren vanaf de uiteinden:
for (int i = 0; i < 5 / 2; i++) {
int temp = t[i];
t[i] = t[5 - 1 - i];
t[5 - 1 - i] = temp;
}
De eerste wissel verwisselt 12 en 10. De tweede verwisselt 15 en 14. De middelste 9 blijft staan, met {10, 14, 9, 15, 12} als resultaat. Stop halverwege: als je alle vijf posities doorloopt, wissel je elk paar twee keer.
Houd het aantal gebruikte elementen apart van de capaciteit bij
Een array met ruimte voor 100 waarden kan op dit moment slechts 37 bruikbare elementen bevatten. De capaciteit is 100; het aantal gebruikte elementen is 37. Verwerk de posities onder count. Om één waarde toe te voegen, controleer je eerst count < CAPACITY, sla je de waarde op in a[count] en verhoog je daarna count. Als je tot de capaciteit doorloopt, kun je posities lezen die nooit bruikbare waarden hebben gekregen, ook al liggen die posities fysiek binnen de array.
Belangrijkste punten
- Gebruik een strikte lusgrens met
<. - Gebruik drijvendekommadeling wanneer een gemiddelde een deel achter de komma kan hebben.
- Initialiseer het maximum van een niet-lege array met een element, ook als alle gegevens negatief zijn.
- Beslis pas dat een zoekopdracht is mislukt nadat alle kandidaten zijn gecontroleerd.
- Valideer een waarde voordat je die als index gebruikt.
- Keer om door alleen de eerste helft van de paren te wisselen.
- Het aantal geeft aan hoeveel elementen in gebruik zijn; de capaciteit is de beschikbare ruimte.
1.3 Geef arrays door aan functies
Een functie kan een array verwerken zonder van elk element een afzonderlijke kopie te ontvangen. Via de aanroep heeft de functie toegang tot de opslag van de aanroepende functie. Geef het aantal elementen mee, zodat de functie weet waar ze moet stoppen.
Geef de gegevens en hun lengte mee
#include <stddef.h>
double average(const int a[], size_t n) {
if (n == 0) return 0.0;
int sum = 0;
for (size_t i = 0; i < n; i++) {
sum += a[i];
}
return (double) sum / n;
}
De aanroepende functie kan int values[] = {7, 8, 10}; declareren en average(values, sizeof values / sizeof values[0]) aanroepen. De drie optellingen leveren 25 op; door sum vóór de deling naar double te converteren, krijg je ongeveer 8,33. Bij geen waarden 0,0 teruggeven is de gekozen werkwijze van deze functie voor lege invoer. De kleine waarden in dit voorbeeld houden de geheeltallige som binnen het waardenbereik.
In een parameterdeclaratie wordt int a[] omgezet naar int *a. Die parameter ontvangt het adres van het eerste element. Zelfs int a[10] controleert of vereist geen tien elementen. De aanroepende functie moet een lengte opgeven die overeenkomt met de beschikbare gegevens.
Waarom sizeof de lengte niet meer kent
Op de plaats van de aanroep meet sizeof values de array. Binnen de functie meet sizeof a de pointerparameter. Waar pointers 8 bytes en gehele getallen 4 bytes innemen, geeft deling van deze groottes 2, ongeacht het aantal elementen van de aanroepende functie. Dat resultaat beschrijft geen kopie van twee elementen en ook niet de oorspronkelijke array. Houd de lengte bij als expliciete parameter.
size_t, gedeclareerd door onder meer <stddef.h>, is het type zonder teken dat sizeof oplevert. Het kan objectgroottes voorstellen en %zu drukt het af. Door dit type voor de lusindex te gebruiken, voorkom je dat een index met teken wordt vergeleken met een lengte zonder teken.
Bepaal of elementen mogen veranderen
De const in const int a[] voorkomt toewijzingen aan elementen via deze parameter. Dit past bij een functie die een resultaat uit de gegevens berekent. Een functie die elementen moet bijwerken, laat die kwalificatie weg:
void zero(int a[], size_t n) {
for (size_t i = 0; i < n; i++) {
a[i] = 0;
}
}
Na zero(values, 3) bevatten de drie elementen van de aanroepende functie allemaal nul. De array heeft nog steeds drie elementen. Een scalaire parameter zoals n is een afzonderlijke kopie; als je die kopie wijzigt, verandert een tellervariabele van de aanroepende functie niet.
Laat de aanroepende functie een uitvoerarray en de lengte ervan beschikbaar stellen om meerdere resultaten te produceren. Een functie kan elk resultaat in out[i] plaatsen. C-functies kunnen geen array op waarde teruggeven en het adres van een lokale array teruggeven werkt niet, omdat die array ophoudt te bestaan wanneer de functie terugkeert.
Tel terug met een index zonder teken
Een index zonder teken kan niet negatief worden. In for (size_t i = n - 1; i >= 0; i--) is de test altijd waar; na nul loopt de waarde modulair terug naar een groot positief getal. Bij n == 0 loopt zelfs de eerste aftrekking modulair terug. Begin in plaats daarvan bij het aantal:
for (size_t i = n; i > 0; i--) {
printf("%d\n", a[i - 1]);
}
Bij drie elementen worden de indexen 2, 1 en 0 benaderd. Bij nul elementen wordt de lusinhoud nooit uitgevoerd. Neem <stdio.h> op voor printf.
Belangrijkste punten
- Geef een arraylengte afzonderlijk door; uit een parameter kun je het aantal elementen niet afleiden.
- Schrijven via een arrayparameter wijzigt de elementen van de aanroepende functie.
- Gebruik
constvoor een parameter die elementen alleen leest. - De aanroepende functie stelt opslag beschikbaar voor meerdere uitvoerwaarden.
- Tel bij gebruik van
size_tterug vanafnen benaderi - 1.
2Stel tekst voor met tekens en strings die eindigen op een nulteken
Tekst begint met tekencodes en eindigt met een opslagregel: een C-string stopt bij zijn eerste nulbyte. Leer hoe tekens, literals en beschrijfbare arrays verschillen en gebruik daarna lussen om tekst te tellen en te transformeren. UTF-8 voegt een wezenlijk onderscheid toe tussen een byte en een volledig codepunt. Door zowel de tekst als de opslag te volgen, zie je waarom een zichtbaar woord meer arrayposities kan innemen dan het aantal letters doet vermoeden.
2.1 Behandel tekens als numerieke codes
Een C-teken wordt opgeslagen als een numerieke code. Daardoor kan een programma een symbool afdrukken, het met een ander symbool vergelijken of met de code rekenen. De tekenset bepaalt welk getal elk symbool voorstelt.
Lees de code en het teken
Een char neemt één byte in: sizeof(char) is per definitie 1. Een tekenconstante zoals 'A' heeft het type int. In de hier gebruikte, op ASCII gebaseerde tekenset is de code 65:
printf("%c %d\n", 'A', 'A');
De uitvoer is “A 65”. %c toont het teken; %d toont het getal. ASCII kent de codes 0 tot en met 127 toe. Cijfers lopen van 48 tot en met 57, hoofdletters van 65 tot en met 90, kleine letters van 97 tot en met 122 en de spatie heeft code 32.
Enkele en dubbele aanhalingstekens maken verschillende dingen. 'A' is één tekencode. "A" is een array met 'A' en een afsluitende nulbyte. Sla één teken op met char c = 'A'; en vergelijk het met c == 'A'.
Schrijf tekens waarvoor een escapesequentie nodig is
| C-schrijfwijze | Teken |
|---|---|
'\n' | Nieuwe regel, ASCII-code 10 |
'\t' | Tab, ASCII-code 9 |
'\\' | Backslash |
'\'' | Enkel aanhalingsteken |
'\0' | Nulteken, code 0 |
Het nulteken verschilt van het zichtbare cijfer '0', dat ASCII-code 48 heeft. Een string gebruikt het nulteken om het einde aan te geven.
Zet codes om in bruikbare waarden
De C-standaard garandeert opeenvolgende cijfercodes. Nadat je hebt gecontroleerd of c een cijfer is, levert c - '0' de waarde ervan op. Zo is '7' - '0' gelijk aan 7, niet aan 55. Door de begincode af te trekken, haal je de positie van het cijfer binnen de tekenset weg.
ASCII-letters zijn ook opeenvolgend, dus door 'A' af te trekken zet je een hoofdletter om in een positie van 0 tot en met 25. Voor een Caesarverschuiving met drie gebruik je:
char shifted = (c - 'A' + 3) % 26 + 'A';
Voor 'X' geeft 65 aftrekken 23; drie optellen geeft 26; de rest na deling door 26 is nul; 65 optellen levert weer 'A' op. Alleen 'X' + 3 geeft code 91, oftewel '['. Rekenen met letters is afhankelijk van de lettervolgorde zoals in ASCII; C garandeert opeenvolgende cijfers, maar vereist geen opeenvolgende letters.
Classificeer en converteer met ctype.h
Neem <ctype.h> op voor isdigit, isalpha, isalnum, isspace, isupper, islower, toupper en tolower. De tests geven bij een overeenkomst een waarde anders dan nul terug en anders nul. toupper('q') geeft 'Q' terug; toupper('3') laat het cijfer ongewijzigd. isspace herkent scheidingstekens zoals spatie, tab en nieuweregelteken.
Een gewone char kan een type met teken zijn. Een byte boven 127 kan dan een negatieve waarde worden, die geen geldig argument is voor deze functies, tenzij het de speciale invoermarkering EOF is. Converteer eerst wanneer je bytes uit een string verwerkt:
if (isalpha((unsigned char) c)) {
c = (char) toupper((unsigned char) c);
}
In de standaardlocale “C” herkennen deze functies de basisletters, geen volledige UTF-8-tekens die uit meerdere bytes bestaan. De expliciete typeconversie maakt de byte tot een geldig argument; ze decodeert geen UTF-8.
Belangrijkste punten
- Tekenconstanten gebruiken enkele aanhalingstekens; stringliterals gebruiken dubbele aanhalingstekens.
\0is een teken met waarde nul, niet het cijfer0.- Trek
'0'af van een cijferteken om de waarde ervan te krijgen. - Berekeningen met letterposities gebruiken hier de ASCII-volgorde.
- Converteer een stringbyte naar
unsigned charvóór een aanroep van een ctype-functie. - Een ctype-test geeft bij een overeenkomst een waarde anders dan nul terug, niet noodzakelijk 1.
2.2 Sla tekst op als strings die eindigen op een nulteken
Een C-string is een reeks tekens die eindigt op '\0'. Het afsluitende nulteken maakt deel uit van de opslag, maar niet van de tekstlengte. C heeft geen afzonderlijk ingebouwd stringtype: de tekens staan in een array.
Bekijk de bytes in de array
char word[] = "cat";
char name[20] = "Ada";
word bevat vier bytes: 'c', 'a', 't', '\0'. De arraygrootte is 4 en strlen(word) is 3. Neem <string.h> op voor strlen. De grotere array name bevat de drie letters, hun afsluitende nulteken en nog zestien nulbytes. De capaciteit is 20 en de huidige lengte is 3.
Een initialisator die de tekens één voor één opgeeft, kan dezelfde string maken:
char word[] = {'c', 'a', 't', '\0'};
Als je het laatste element weglaat, maak je drie tekens zonder afsluitend nulteken. C staat ook char word[3] = "cat"; toe. Daarmee vul je alle drie de posities en laat je de nulbyte weg. Zo’n array is geen C-string. Een functie zoals strlen of printf met %s blijft lezen tot ze een nulbyte tegenkomt en kan die array van drie bytes dus niet veilig als tekst verwerken.
Kies een wijzigbare array of een literal
| Declaratie | Waar de tekst staat | Kunnen de tekens veranderen? |
|---|---|---|
char a[] = "hello"; | Een kopie in array a | Ja |
const char *p = "hello"; | Een stringliteral waarnaar p verwijst | Nee |
a[0] = 'H'; verandert de kopie in “Hello”. Een literal mag niet worden gewijzigd. Zelfs als je die aan een gewone char * toewijst, is schrijven via die pointer ongedefinieerd gedrag. Met const char * maak je die beperking zichtbaar voor de compiler.
De compiler voegt stringliterals die naast elkaar staan samen: "Hello, " "world" geeft dezelfde tekst als "Hello, world". De resulterende string heeft nog steeds één afsluitend nulteken. Dit is handig om een lange literal over broncoderegels te verdelen.
Druk de tekst af en wijzig die
printf("%s\n", word);
printf("%c\n", word[0]);
De eerste aanroep drukt de hele string af. De tweede drukt het eerste teken af. Een stringliteral in printf staat tussen dubbele aanhalingstekens omdat het tekst is die een formaat bevat; %c ontvangt één tekencode.
Een toewijzing aan een element wijzigt één opgeslagen teken. Bij char name[20] = "Ada"; levert name[0] = 'E'; de string “Eda” op. Als je daarna name[1] = '\0'; instelt, ontstaat de string “E”. De bytes voor 'a' en het oude afsluitende nulteken bestaan later in de array nog steeds, maar stringbewerkingen stoppen bij de eerste nul.
Na de declaratie kan een array geen vervangende tekst ontvangen met name = "Bob";. Kopieer de tekens erin met een gecontroleerde aanroep van strcpy of met een lus, inclusief het afsluitende nulteken. De lengte van de vervangende tekst moet kleiner zijn dan de capaciteit.
Stel afwezigheid van tekst voor
De lege string "" neemt nog steeds één byte in voor '\0'. De lengte is nul en je kunt dit testen met name[0] == '\0'. Een lege string is een echte string met een afsluitend nulteken; een nulpointer verwijst daarentegen naar geen enkele stringopslag.
Belangrijkste punten
- Een C-string eindigt bij zijn eerste
'\0'. - De capaciteit omvat het afsluitende nulteken; de stringlengte niet.
- Een tekenarray zonder afsluitend nulteken kun je niet als C-string doorgeven.
- Kopieën van literals in arrays zijn wijzigbaar; literals zelf niet.
- Een eerder afsluitend nulteken schrijven verkort de tekst zonder de grootte van de array te veranderen.
2.3 Verwerk strings teken voor teken
Het afsluitende nulteken van een string geeft een lus haar stoppunt. Bezoek de bytes ervoor om tekst te tellen, converteren of filteren. Bij het maken van een nieuwe string moet het programma zelf een nieuw afsluitend nulteken schrijven.
Doorloop de string één keer tot het einde
for (size_t i = 0; s[i] != '\0'; i++) {
/* Process s[i]. */
}
Bij elke iteratie test de lus of de huidige byte bij de tekst hoort. Ze stopt vóór het afsluitende nulteken. Als je strlen(s) in die test aanroept, kan de hele string bij elke iteratie opnieuw worden doorlopen. Test de huidige byte rechtstreeks of bereken één keer size_t len = strlen(s); als de lengte gelijk blijft.
Gebruik voor omzetting naar hoofdletters een wijzigbare array en <ctype.h>:
for (size_t i = 0; s[i] != '\0'; i++) {
s[i] = (char) toupper((unsigned char) s[i]);
}
“Hello, World 42” wordt “HELLO, WORLD 42”. De conversie behoudt de komma, spaties en cijfers. De conversie naar een type zonder teken maakt elke opgeslagen byte tot een geldig argument voor ctype.
Tel categorieën en woordbeginnen
Het oorspronkelijke “Hello, World 42” heeft 15 tekstbytes: 10 letters, twee cijfers, twee spaties en één komma. Afzonderlijke tellers kunnen isalpha, isdigit en isspace gebruiken. Bepaal voordat je gaat tellen wat een woord betekent. Voor een reeks letters begint een nieuw woord wanneer een letter op een niet-letter volgt of het eerste teken is:
int in_word = 0;
size_t words = 0;
for (size_t i = 0; s[i] != '\0'; i++) {
int letter = isalpha((unsigned char) s[i]) != 0;
if (letter && !in_word) words++;
in_word = letter;
}
Het voorbeeld heeft twee letterreeksen, “Hello” en “World”. De cijfers vormen volgens deze definitie geen woord. Door in_word bij elke iteratie bij te werken, kan een leesteken een reeks beëindigen.
Keer alleen de tekst om
Bepaal voor een string met tekens van één byte eerst één keer len en wissel dan s[i] met s[len - 1 - i] zolang i < len / 2. Bij het omkeren van “stressed” wissel je de eerste en laatste letter, dan het volgende paar, tot “desserts” ontstaat. De nulbyte blijft op index len staan. Als je een wissel bij s[len] begint, verplaats je die nul naar voren. Bytes op deze manier omkeren is geschikt voor ASCII-tekst; tekens van meerdere bytes moeten vóór het herschikken worden gedecodeerd.
Bouw een gefilterd resultaat op
Gebruik verschillende indexen voor lezen en schrijven, omdat sommige invoerbytes worden overgeslagen:
char in[] = "a1b2c3";
char out[sizeof in];
size_t j = 0;
for (size_t i = 0; in[i] != '\0'; i++) {
if (isalpha((unsigned char) in[i])) {
out[j++] = in[i];
}
}
out[j] = '\0';
Het resultaat is “abc”. De doelarray heeft genoeg ruimte omdat filteren deze invoer niet langer kan maken. Zonder out[j] = '\0'; heeft de uitvoer geen vastgelegd stringeinde.
Verschuif voor een Caesarversleuteling hoofdletters ten opzichte van 'A' en kleine letters ten opzichte van 'a' en kopieer andere bytes ongewijzigd. Met sleutel 13 wordt “Hello, World!” omgezet in “Uryyb, Jbeyq!”. Als je die verschuiving herhaalt, krijg je het origineel terug omdat twee verschuivingen samen 26 zijn. Een vergelijking zoals s[i] == 'a' test één teken; gebruik strcmp om volledige tekst te vergelijken.
Belangrijkste punten
- Test de huidige byte of bewaar de lengte om herhaald volledig doorzoeken te voorkomen.
- Houd bij het filteren afzonderlijke lees- en schrijfindexen bij.
- Schrijf een afsluitend nulteken na het opbouwen van een nieuwe string.
- Keer tekstbytes om zonder het afsluitende nulteken te verplaatsen.
- Definieer een woordgrens voordat je een woordteller schrijft.
- Pas ASCII-letterverschuivingen afzonderlijk toe op hoofdletters en kleine letters.
2.4 Leg uit hoe UTF-8-tekst in char-arrays wordt opgeslagen
Tekstlengte kan een aantal bytes of een aantal Unicode-codepunten betekenen. Die aantallen verschillen vaak. Een C-char-array geeft toegang tot afzonderlijke bytes, dus de indexen en stringfuncties volgen niet automatisch volledige niet-ASCII-tekens.
Onderscheid tekens, codepunten en bytes
Een tekencodering beschrijft hoe tekst wordt opgeslagen. ASCII gebruikt de codes 0 tot en met 127 voor basisletters, cijfers, leestekens en besturingstekens. Unicode kent codepunten toe aan tekens uit veel schriftsystemen: “é” heeft codepunt U+00E9 en “€” heeft U+20AC. UTF-8 codeert scalaire Unicode-waarden met één tot vier bytes.
ASCII-codepunten behouden hun codering van één byte. De vooraf samengestelde “é” gebruikt twee bytes, 0xC3 en 0xA9; “€” gebruikt er drie. Veel afzonderlijke emoji-codepunten gebruiken vier bytes. Een weergegeven symbool kan meerdere codepunten bevatten, dus ook een aantal codepunten is niet altijd een aantal zichtbare symbolen.
Meet een UTF-8-string
char s[] = "café";
printf("%zu %zu\n", strlen(s), sizeof s);
Bij UTF-8-uitvoeringstekst drukt dit “5 6” af. De eerste drie letters gebruiken drie bytes en “é” gebruikt er twee, samen vijf tekstbytes. Het afsluitende nulteken voegt de zesde opslagbyte toe. s[3] is de eerste byte van “é”, niet de hele letter.
Als je na vier bytes afkapt, blijft 0xC3 staan maar verdwijnt de vervolgbyte 0xA9. Het resultaat zou geen geldige UTF-8 meer zijn. Een buffergrens in bytes vereist daarom een controle op tekengrenzen als het programma UTF-8-tekst afkapt.
Tel beginbytes in geldige UTF-8
Een vervolgbyte begint met de bits 10. De waarde ligt tussen 0x80 en 0xBF. Een beginbyte of ASCII-byte heeft dat patroon niet:
size_t points = 0;
for (size_t i = 0; s[i] != '\0'; i++) {
unsigned char c = (unsigned char) s[i];
if ((c & 0xC0) != 0x80) points++;
}
Het masker 0xC0 behoudt alleen de twee hoogste bits; 0x80 stelt het patroon 10 op die posities voor. De test telt “café” als vier codepunten door de vier beginbytes te tellen. De test gaat uit van geldige UTF-8, valideert geen ongeldige reeksen en voegt geen codepunten samen tot zichtbare symbolen.
Kies bewerkingen die de codering behouden
Het kopiëren van een volledige UTF-8-string behoudt de bytes. Ook volledige strings samenvoegen, hun bytereeksen op gelijkheid vergelijken en zoeken naar een ASCII-teken of een volledige UTF-8-deelstring werken. UTF-8-vervolgbytes kunnen niet worden verward met ASCII-tekens of beginbytes.
strcmp ordent bytewaarden zonder teken, dus die volgorde verschilt van een taalspecifieke alfabetische volgorde. In UTF-8 hebben gewone Latijnse letters met accenten beginbytes boven ASCII 'z'. Een bytevergelijking plaatst die letters daarom na 'z', ongeacht woordenboekconventies.
In de standaardlocale “C” verwerken toupper en isalpha één byte en decoderen ze “é” niet als letter. Een expliciete typeconversie naar unsigned char maakt de aanroep geldig, maar maakt er geen Unicode-conversie tussen hoofdletters en kleine letters van. Daarvoor zijn functies voor brede tekens of een Unicode-bibliotheek nodig. Een Caesar-lus die alleen ASCII verwerkt, kan letters met accenten behouden door alleen bytes van A–Z of a–z te wijzigen.
De nulbyte is de UTF-8-codering van U+0000; andere gecodeerde codepunten bevatten geen nulbyte. Dat past bij de C-conventie voor afsluitende nultekens. UTF-16 kan nulbytes binnen gewone gecodeerde tekst plaatsen, dus een UTF-16-bytearray kan niet als een gewone char-string worden verwerkt.
Belangrijkste punten
strlentelt bytes, ook in UTF-8-tekst.- Eén Unicode-codepunt kan meerdere bytes innemen.
- Een char-index kan binnen een gecodeerd teken uitkomen.
- Bytes tellen die geen vervolgbyte zijn, telt alleen codepunten bij geldige UTF-8.
- Bytegewijze gelijkheid werkt voor identiek gecodeerde tekst; bytevolgorde is geen woordenboekvolgorde.
- ctype-aanroepen die één byte verwerken, decoderen geen UTF-8.
3Gebruik de standaardfuncties voor strings
De standaardbibliotheek biedt veelgebruikte tekstbewerkingen, maar elke functie verwacht een bepaald soort invoer en geeft een specifieke betekenis aan het argument voor de grootte. Leer strings te meten, kopiëren, uitbreiden, vergelijken en doorzoeken, en kies daarna waar passend voor begrensde opmaak of bytebewerkingen. Door de capaciteit te controleren en retourwaarden te interpreteren, maak je van een korte functieaanroep een voorspelbare bewerking op bekende opslagruimte.
3.1 Bepaal de lengte van strings, kopieer ze en voeg ze samen
De functies in <string.h> werken met tekst die eindigt op een nulteken. Ze kunnen de lengte bepalen, de tekst kopiëren of meer tekst toevoegen, maar kopieerfuncties achterhalen de capaciteit van de doelarray niet. Bepaal de benodigde opslagruimte voordat je schrijft.
Meet de lengte zonder het afsluitende nulteken
strlen(s) geeft een size_t terug met het aantal bytes vóór de eerste nulbyte. Zo is strlen("hello") gelijk aan 5 en strlen("") gelijk aan nul. Druk het resultaat af met %zu.
char buf[64] = "hi";
printf("%zu %zu\n", strlen(buf), sizeof buf);
Dit drukt “2 64” af. Het eerste resultaat meet de huidige tekst; het tweede meet de beschikbare opslagruimte in de array. Een latere kopieerbewerking kan het eerste veranderen zonder het tweede te veranderen. Beide aanroepen zijn hier nuttig omdat buf een echte array is en al een geldige string bevat.
Kopieer een volledige string
strcpy(dest, src) kopieert tekst en de afsluitende nulbyte. De benodigde capaciteit is de lengte van de bron plus één:
char dest[12];
const char *src = "Maple";
if (strlen(src) < sizeof dest) {
strcpy(dest, src);
}
“Maple” gebruikt vijf tekstbytes en één afsluitend nulteken, dus past de tekst. De strikte < is belangrijk: als de lengte van de bron gelijk is aan de capaciteit, blijft er geen positie over voor de nulbyte. Als de controle mislukt, moet het programma de fout afhandelen voordat het de doelarray als nieuwe string gebruikt.
Een arraytoewijzing zoals dest = src; kan de inhoud niet vervangen. De ene char *-variabele aan de andere toewijzen is toegestaan, maar kopieert alleen een verwijzing naar dezelfde opslag. Er ontstaat geen extra kopie van de tekens.
Voeg tekst toe aan een bestaande string
strcat(dest, src) zoekt eerst het afsluitende nulteken dat al in dest staat. De functie vervangt dat nulteken door de eerste byte van de bron en schrijft een nieuw afsluitend nulteken na de toegevoegde tekst. De capaciteit van de doelarray moet voldoende zijn voor beide huidige lengtes plus één.
char full[16];
strcpy(full, "Ada");
strcat(full, " ");
strcat(full, "Lovelace");
De lengte groeit van 3 naar 4 naar 12. Het uiteindelijke “Ada Lovelace” heeft 13 bytes opslagruimte nodig, waardoor drie bytes ongebruikt blijven. Een doelarray van 12 bytes zou één byte te klein zijn, hoewel de zichtbare tekst even lang is.
Voeg nooit tekst toe aan een niet-geïnitialiseerde lokale buffer. Bij char out[20]; strcat(out, "hi"); heeft strcat geen vastgelegd teksteinde om te vinden. Begin met char out[20] = "";, schrijf out[0] = '\0'; of maak van de eerste bewerking een gecontroleerde kopieerbewerking.
Houd rekening met opslag en doorzoektijd
Bron en doel mogen bij strcpy of strcat niet overlappen. Als je tekst binnen dezelfde buffer verplaatst, kan overlap ontstaan, ook als beide locaties afzonderlijk geldig zijn. memmove is de functie die bedoeld is voor overlappende bytegebieden.
strlen moet tot het afsluitende nulteken doorzoeken. strcat moet de huidige doelstring doorzoeken voordat de functie tekst toevoegt. Herhaald toevoegen in een lus doorzoekt dus opnieuw tekst die al is opgebouwd. Als je veel stukken samenvoegt, houd dan de huidige uitvoerlengte bij en schrijf elk stuk op die index. Controleer daarbij de resterende capaciteit en zorg dat het afsluitende nulteken aanwezig blijft. Een bekende lengte is alleen bruikbaar zolang die nog overeenkomt met de werkelijke inhoud.
Belangrijkste punten
strlenmeet de huidige tekst;sizeofop een array meet de capaciteit ervan.- Een kopie heeft de bronlengte plus één byte nodig.
- Toevoegen vereist beide stringlengtes plus één byte.
- Initialiseer de doelarray als string voordat je tekst toevoegt.
- Kopiëren of toevoegen met overlappende stringgebieden is ongeldig.
3.2 Vergelijk en doorzoek strings
Stringvergelijking beantwoordt vragen over tekst, terwijl zoeken in een string een plaats binnen die tekst vindt. Geen van beide taken voer je uit door arraynamen met == te vergelijken. Gebruik het bibliotheekresultaat volgens wat het voorstelt: het teken van een vergelijkingsresultaat, een lengte of een locatie van een overeenkomst.
Vergelijk tekst en beginstukken
strcmp(a, b) vergelijkt overeenkomstige bytes als unsigned char-waarden tot er een verschil is of het einde van een string wordt bereikt. Het resultaat is nul bij gelijke tekst, negatief als a eerder komt en positief als die later komt. Alleen het teken is vastgelegd; verwacht niet precies -1 of 1.
if (strcmp(command, "quit") == 0) {
puts("Goodbye");
}
De expliciete test op nul betekent dat de tekst gelijk is. Een gewone if (strcmp(command, "quit")) voert het blok uit bij ongelijke tekst, omdat een waarde anders dan nul waar is. De vergelijking command == "quit" zou opslaglocaties vergelijken.
In ASCII-volgorde komt “apple” bij de eerste letter vóór “banana”. “Zebra” komt vóór “apple” omdat hoofdletter 'Z' code 90 heeft en kleine letter 'a' code 97. “app” komt vóór “apple” omdat de nulbyte van de eerste string wordt bereikt vóór de 'l' van de andere. Dit is ordening op bytes, geen woordenboekvergelijking.
strncmp(a, b, n) vergelijkt hoogstens n bytes. strncmp(s, "--", 2) == 0 herkent twee streepjes aan het begin, maar betekent niet dat de hele string alleen “--” is. Standaard-C heeft geen functie om hele strings te vergelijken zonder onderscheid tussen hoofdletters en kleine letters. Een programma kan zelf geconverteerde bytes vergelijken; POSIX biedt strcasecmp in <strings.h>.
Zoek een locatie
Gebruik strchr voor de eerste keer dat één teken voorkomt, strrchr voor de laatste keer en strstr voor de eerste volledige deelstring. Ze geven een pointer naar de locatie van de overeenkomst terug, of NULL als er geen overeenkomst is.
char name[] = "report.final.txt";
char *extension = strrchr(name, '.');
if (extension != NULL) {
printf("%s\n", extension);
}
Dit drukt “.txt” af, inclusief de gevonden punt. Als je met strchr bij de eerste punt zou beginnen, zou “.final.txt” worden afgedrukt. strstr(name, "final") vindt het achterste deel dat begint met “final.txt”; zoeken naar “draft” geeft NULL. Controleer op NULL voordat je een zoekresultaat afdrukt of leest.
Zoek een scheidingsteken of splits tekst
strcspn(s, set) telt de bytes aan het begin die bij geen van de tekens in set horen. Bij "oak:pine,birch" en de verzameling ":," stopt de functie bij de dubbele punt. Voor een geldige invoerstring verwijdert dit patroon het eerste nieuweregelteken:
buf[strcspn(buf, "\n")] = '\0';
Als er geen nieuweregelteken is, is de teruggegeven index de stringlengte en overschrijft de toewijzing dus het afsluitende nulteken dat daar al staat.
strtok splitst een wijzigbare string met elk teken uit een verzameling scheidingstekens:
char colors[] = "red, green,blue";
char *token = strtok(colors, " ,");
while (token != NULL) {
puts(token);
token = strtok(NULL, " ,");
}
De tokens zijn “red”, “green” en “blue”. De eerste aanroep geeft de array door; latere aanroepen geven NULL door om verder te gaan. De functie schrijft nulbytes in de invoer en bewaart een verborgen toestand tussen aanroepen. Gebruik beschrijfbare opslag en verwacht niet dat de oorspronkelijke string met scheidingstekens intact blijft. Opeenvolgende scheidingstekens leveren geen lege tokens op.
Belangrijkste punten
- Gebruik
strcmp(a, b) == 0voor gelijke tekst. - Interpreteer een vergelijkingsresultaat aan de hand van het teken, niet van de exacte grootte.
- Overeenstemming van een beginstuk bewijst niet dat de hele strings gelijk zijn.
- Controleer zoekresultaten op een nulpointer.
strcspngeeft de lengte van een beginstuk terug;strtokwijzigt de invoer en onthoudt de positie.- De ordening van strings volgt bytecodes zonder teken.
3.3 Kopieer binnen de grenzen en werk rechtstreeks met geheugenbytes
Een lengtegrens is alleen nuttig als die de juiste grootheid beschrijft. Sommige functies begrenzen bronbytes, andere de capaciteit van de doelarray, en geheugenfuncties verwerken ruwe bytes zonder stringeinden. Lees het contract van elke functie voordat je de grens kiest.
Weet wat n betekent
strncpy(dest, src, n) schrijft precies n posities als de bron korter is en vult aan met nulbytes. Als de bron minstens n bytes tekst heeft, kopieert de functie die bytes zonder afsluitend nulteken. Voor een array met een positieve capaciteit maak je zo een afgekorte kopie met afsluitend nulteken:
strncpy(dest, src, sizeof dest - 1);
dest[sizeof dest - 1] = '\0';
De laatste toewijzing is essentieel wanneer de bron de grens vult. Een naam of opdracht afkappen kan nog steeds de betekenis veranderen, dus wijs te lange invoer af als een volledige kopie vereist is.
strncat(dest, src, n) voegt hoogstens n tekstbytes toe en daarna een afsluitend nulteken. De functie ontvangt niet de totale capaciteit. Voor een geldige string die al in een doelarray staat, is de resterende ruimte voor tekst sizeof dest - strlen(dest) - 1. Als je sizeof dest als n doorgeeft, kan de doelarray overlopen.
Maak tekst op en detecteer afkapping
snprintf, gedeclareerd in <stdio.h>, ontvangt de totale capaciteit van de doelarray. Bij een capaciteit groter dan nul schrijft de functie hoogstens één tekstbyte minder en daarna een afsluitend nulteken:
char buf[8];
int needed = snprintf(buf, sizeof buf, "%s-%d", "item", 2026);
if (needed < 0) {
puts("Formatting error");
} else if ((size_t) needed >= sizeof buf) {
puts("Text did not fit");
}
Het volledige resultaat “item-2026” heeft negen tekstbytes. De buffer slaat “item-20” en de nulbyte op, terwijl needed gelijk is aan 9. De retourwaarde telt de tekst die zou zijn geproduceerd, zonder het afsluitende nulteken. Controleer of het resultaat negatief is voordat je het naar size_t converteert.
Kopieer en vul bytes
memcpy(dest, src, n) kopieert precies n bytes, inclusief eventuele nulbytes, zonder naar een afsluitend nulteken te zoeken. Voor twee even grote arrays van gehele getallen kopieert memcpy(b, a, sizeof a) de volledige opslag als de gebieden niet overlappen. Waar elk van vijf gehele getallen vier bytes inneemt, is dat aantal 20 bytes. memmove kopieert bytes met gedefinieerd gedrag voor overlappende gebieden.
memset(a, 0, sizeof a) vult elke byte met nul en zet een array van gehele getallen op nul. Het tweede argument beschrijft elke byte, niet elk element. Bij gehele getallen van vier bytes maakt vullen met 1 de bytes 01 01 01 01, wat bij de gebruikelijke representatie 16.843.009 oplevert, niet het gehele getal 1. Gebruik een lus om geheeltallige waarden anders dan nul toe te wijzen.
memcmp(a, b, n) vergelijkt opgeslagen bytes. Nul betekent dat die bytereeksen overeenkomen. Vergelijk elementen voor waardegelijkheid: de drijvendekommawaarden 0.0 en -0.0 zijn bij vergelijking gelijk, terwijl hun representaties kunnen verschillen.
Herken andere bibliotheekfamilies
De BSD-functies strlcpy en strlcat zijn in 2024 aan POSIX toegevoegd, maar zijn geen kernfuncties van C17. Ze geven een lengte terug die ze probeerden te maken; een resultaat dat minstens zo groot is als de opgegeven grootte duidt op afkapping. strlcpy schrijft een afsluitend nulteken als de grootte positief is. strlcat doet dat alleen als de bestaande tekst binnen die grootte eindigt. Ze zijn beschikbaar in glibc 2.38 en later. Optionele functies uit Annex K, zoals strcpy_s, ontbreken in veel bibliotheken, waaronder glibc.
Belangrijkste punten
strncpykan het afsluitende nulteken weglaten;strncatheeft ruimte nodig voor een nieuw nulteken.snprintfgeeft de volledige benodigde tekstlengte terug, of een negatieve waarde bij een fout.- Een niet-negatief opmaakresultaat dat minstens zo groot is als de capaciteit betekent afkapping.
- Geheugenfuncties tellen bytes en stoppen niet bij nul.
- Gebruik
memmovevoor overlappende gebieden. memsetvult bytes;memcmpvergelijkt representaties.
4Orden gegevens in meerdimensionale arrays
Tabellen ordenen waarden op basis van meer dan één positie. Een C-tabel slaat rijen van gelijke breedte achter elkaar op en met geneste lussen kan een programma per rij of per kolom werken. Leer hoe je die vorm declareert, aan een functie doorgeeft en beide indexen geldig houdt. Lijsten met tekst brengen een nuttige ontwerpkeuze mee: beschrijfbare tekenrijen reserveren vaste ruimte, terwijl arrays van pointers verwijzen naar strings die elders staan.
4.1 Declareer en doorloop tweedimensionale arrays
Een tabel heeft een rij-index en een kolomindex nodig. In C is een tweedimensionale array een array waarvan de elementen zelf arrays zijn. Elke rij heeft evenveel elementen en elke index heeft een eigen grens.
Declareer rijen en kolommen
int grid[3][4];
int m[2][3] = {{1, 2, 3}, {4, 5, 6}};
grid bevat drie rijen met elk vier gehele getallen: in totaal twaalf gehele getallen. De rij-indexen lopen van 0 tot en met 2; de kolomindexen van 0 tot en met 3. grid[1][2] benadert de derde waarde in de tweede rij.
Geneste accolades in de initialisator laten de indeling in rijen zien. Ontbrekende initialisatiewaarden worden nul. Je kunt de compiler de rijen laten tellen in int m[][3] = {{1, 2, 3}, {4, 5, 6}};, maar het aantal kolommen moet je opgeven. Zonder dat aantal kan de compiler niet bepalen waar elke rij eindigt.
Volg de rijgewijze opslag
C slaat een volledige rij op voordat de volgende begint. In grid vormen de eerste vier opgeslagen gehele getallen rij 0, de volgende vier rij 1 en de laatste vier rij 2. grid[1][2] is het zevende gehele getal vanaf het begin, op elementpositie 6 bij indexering vanaf nul: één volledige rij van vier, gevolgd door nog twee elementen.
Waar gehele getallen vier bytes innemen, gebruikt één rij zestien bytes en de hele tabel achtenveertig. Op de plaats van de declaratie:
size_t rows = sizeof grid / sizeof grid[0];
size_t cols = sizeof grid[0] / sizeof grid[0][0];
De eerste deling geeft 3 en de tweede 4. Een rij is zelf een array; daarom meet sizeof grid[0] meer dan één geheel getal.
Doorloop de tabel en bereken totalen
int sales[2][3] = {{4, 0, 7}, {5, 2, 1}};
int total = 0;
for (int r = 0; r < 2; r++) {
int row_sum = 0;
for (int c = 0; c < 3; c++) {
row_sum += sales[r][c];
}
printf("%d\n", row_sum);
total += row_sum;
}
De eerste rij levert 11 op en de tweede 8. Als je die rijtotalen optelt, krijg je 19. Door row_sum binnen de buitenste lus opnieuw in te stellen, begint voor elke rij een nieuw totaal. Als de variabele slechts één keer vóór beide lussen was geïnitialiseerd, zou de tweede afgedrukte waarde ook de eerste rij bevatten.
Voor kolomtotalen zet je de kolomlus buiten en de rijlus binnen, terwijl je nog steeds sales[r][c] gebruikt. De drie totalen worden 9, 2 en 8, samen opnieuw 19. Als je de doorloopvolgorde verandert, hoef je de betekenis van de twee indexen niet te veranderen. Een doorloop met de rijen als buitenste lus volgt de aaneengesloten opslag en verbetert bij grote tabellen vaak het gebruik van de cache.
Houd elke dimensie binnen de grenzen
grid[c][r] verwisselt de betekenis van de indexen. Als c 3 bereikt, vraagt de expressie een vierde rij op die niet bestaat. Dat het volledige object twaalf gehele getallen bevat, betekent niet dat je met een kolomindex de grens van één rij mag overschrijden.
Schrijf twee afzonderlijke indexbewerkingen: grid[1][2]. In C17 evalueert grid[1, 2] de komma-expressie en selecteert grid[2], een rij, in plaats van één element. Bij meer dimensies pas je hetzelfde idee herhaaldelijk toe: int cube[2][3][4] heeft 24 geheeltallige elementen, die je met drie indexen selecteert.
Belangrijkste punten
- Een tweedimensionale array is een array van rijen met gelijke breedte.
- Rijen worden na elkaar opgeslagen in rijgewijze opslagvolgorde.
- Houd de grenzen van rijen en kolommen gescheiden.
- Stel een accumulator voor een rij of kolom opnieuw in wanneer je aan een nieuwe groep begint.
- Alleen de eerste dimensie kan uit een initialisator worden afgeleid.
4.2 Geef tabellen door aan functies en sla lijsten met strings op
Een functie die een tabel ontvangt, heeft genoeg informatie nodig om elke rij te vinden. Een lijst met strings brengt nog een keuze mee: sla de tekens op in rijen van gelijke breedte of sla verwijzingen op naar strings met verschillende lengtes.
Geef een tabelparameter zijn rijbreedte
void double_grid(int rows, int g[][4]) {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < 4; c++) {
g[r][c] *= 2;
}
}
}
De eerste dimensie kan worden weggelaten omdat het aantal rijen afzonderlijk wordt doorgegeven. De breedte 4 bepaalt het type van elke rij. Zonder die breedte zou de afstand tussen rijen voor g[r][c] niet bekend zijn. Een declaratie met int g[][] is ongeldig. Wijzigingen via deze parameter blijven bestaan in de tabel van de aanroepende functie; een tabelparameter die alleen wordt gelezen, kan const int g[][4] gebruiken.
Sinds C99 accepteren compilers die parameters met een variabel gemodificeerd type ondersteunen dimensies die eerder in de parameterlijst zijn gedeclareerd:
void print_grid(int rows, int cols, int g[rows][cols]);
GCC en Clang ondersteunen deze C17-vorm. Hiermee kan één functie verschillende rijbreedtes ontvangen; geef positieve dimensies door die overeenkomen met de werkelijke tabel. C23 vereist ondersteuning voor deze parametertypen, terwijl automatische objecten die arrays met variabele lengte zijn een afzonderlijke optionele functie blijven. Parameters met vaste breedte zijn nuttig als de compilerondersteuning beperkt is.
Sla strings op in rijen
char days[7][10] = {
"Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday", "Sunday"
};
Elke rij heeft opslagruimte voor tien tekens, ongeacht de huidige tekstlengte. “Wednesday” heeft alle tien posities nodig: negen letters en een afsluitend nulteken. days[2] selecteert die hele rij als string; days[2][0] selecteert 'W'.
Je kunt een rij afdrukken met %s, meten met strlen of vergelijken met strcmp. De rij kan ook een gecontroleerde kopie ontvangen. strcpy(days[0], "Mon"); past in tien bytes en wijzigt de tekst van rij 0. De rij blijft tien bytes breed en de volgende rij blijft op dezelfde locatie. Vervangende tekst van tien bytes zou elf bytes nodig hebben en niet passen.
Sla verwijzingen naar literals op
const char *names[] = {"Ann", "Bartholomew", "Li"};
Dit declareert een array van pointers. Elk element verwijst naar een literal met zijn eigen lengte plus een afsluitend nulteken. names[1] verwijst naar “Bartholomew” en names[1][0] is 'B'. De literals mogen niet worden gewijzigd.
De pointerelementen kunnen veranderen, hoewel de tekens van de literals dat niet kunnen. names[0] = "Anna"; verandert naar welke literal het eerste element verwijst; de instructie verlengt “Ann” niet op dezelfde locatie. In de vorm met 2D-rijen is een element een tekenarray met vaste breedte en kan het niet op die manier opnieuw worden toegewezen. Kies beschrijfbare rijen voor tekst die je op dezelfde locatie bewerkt en verwijzingen naar literals voor een lijst met vaste tekstkeuzes. De opdrachtregelparameter argv heeft de vorm van een array van pointers, hoewel de meegegeven argumenttekens wijzigbaar zijn.
Belangrijkste punten
- Tabelparameters hebben elke dimensie na de eerste nodig.
- Een afzonderlijk doorgegeven dimensie moet overeenkomen met de werkelijke tabel.
- Elke stringrij heeft binnen zijn vaste breedte een eigen afsluitend nulteken nodig.
- Een array van pointers slaat verwijzingen op, geen tekenrijen met gelijke breedte.
5Verwerk opdrachtregelargumenten
Een opdrachtregel voorziet een programma bij het starten van tekst. Met aantallen argumenten, groepering door de shell en stringbewerkingen kan het programma die tekst interpreteren zonder aan te nemen dat een argument bestaat of al een getal bevat. Volg een gecontroleerd pad van argv naar een bruikbare waarde: controleer of het argument aanwezig is, converteer de volledige tekst, detecteer conversiefouten en dwing het bereik af dat het programma daadwerkelijk accepteert.
5.1 Lees argc en argv
Met opdrachtregelargumenten kan de aanroepende partij bij het starten van een programma tekst meegeven. De besturingsomgeving maakt die strings beschikbaar voor main. Controleer hoeveel argumenten zijn aangekomen voordat je ze met een index benadert.
Lees de argumentenlijst
int main(int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
printf("%d: %s\n", i, argv[i]);
}
return 0;
}
Neem <stdio.h> op voor de uitvoer. argc is het aantal argumenten en argv is de lijst met strings. De gelijkwaardige schrijfwijze char **argv voor de parameter beschrijft dezelfde interface. De lus begint bij 1 omdat index 0 normaal de naam bevat waarmee het programma is gestart.
In een gewone shell levert ./greet Ada Lovelace drie strings op: “./greet”, “Ada” en “Lovelace”. Dus argc is 3 en het laatste gebruikersargument is argv[2]. Op argv[argc], hier argv[3], staat een nulpointer; die is een stopwaarde na de eigenlijke argumentstrings.
Laat de shell tekst groeperen
Aanhalingstekens beïnvloeden hoe de shell argumenten opbouwt. Als je ./greet "Ada Lovelace" uitvoert, geef je één gebruikersargument met een spatie mee. De aanhalingstekens groeperen de woorden en worden geen onderdeel van de argumenttekst. argc is nu 2.
Unix-achtige shells kunnen ook patronen uitbreiden voordat het programma start. Bij ./count *.txt ontvangt het programma doorgaans de namen die de shell vindt als afzonderlijke argumenten. Het ontvangt de resulterende strings, geen verzoek om het patroon zelf uit te breiden. Het precieze uitbreidingsgedrag hangt af van de shell en de instellingen ervan.
Wijs een ontbrekend of extra argument af
Als een programma precies één gebruikersargument nodig heeft, vereis dan argc == 2 voordat je het gebruikt:
if (argc != 2) {
printf("Usage: %s name\n", argv[0]);
return 1;
}
printf("Hello, %s\n", argv[1]);
Als argc gelijk is aan 1, is argv[1] de nulpointer die als stopwaarde dient. Je kunt die niet aan strlen doorgeven of met %s afdrukken. Indexen voorbij de stopwaarde liggen buiten de argumentarray.
Nul teruggeven vanuit main geeft aan dat het programma is geslaagd. Een status anders dan nul, zoals de 1 hierboven, laat de shell weten dat het programma niet succesvol is voltooid. <stdlib.h> biedt ook EXIT_SUCCESS en EXIT_FAILURE.
Behandel elk argument als een string
argv[i][0] benadert het eerste teken van het argument; strlen(argv[i]) meet de tekstbytes; strcmp(argv[i], "-v") == 0 controleert een volledige optie. Een argument dat eruitziet als een getal is nog steeds tekst en moet vóór een berekening worden geconverteerd.
argv[0] legt meestal vast hoe het programma is gestart, maar kan leeg zijn als die informatie niet beschikbaar is. Het is nuttig voor berichten, niet als vaste identiteitscontrole. Argumenttekens mogen tijdens het programma worden gewijzigd, maar de meegeleverde opslag biedt geen grond om aan te nemen dat een langere vervangende tekst past. Om een extensie toe te voegen of tekst op een andere manier langer te maken, kopieer je die eerst naar een afzonderlijke buffer met een passende grootte.
Belangrijkste punten
argctelt de meegegeven argumentstrings, inclusief de gebruikelijke vermelding van de startnaam.- Controleer het aantal argumenten voordat je een gebruikersargument leest.
argv[argc]is een nulpointer, geen lege argumentstring.- Aanhalingstekens in de shell kunnen spaties binnen één argument houden.
- Gebruik stringbewerkingen voor argumenttekst en conversie voor getallen.
5.2 Converteer en valideer numerieke argumenten
Een numeriek argument komt binnen als tekens, niet als geheel getal. Een betrouwbare conversie controleert drie afzonderlijke vragen: vormden cijfers een getal, gebruikte de conversie de vereiste tekst en is de resulterende waarde toegestaan?
Voorkom verlies van foutinformatie
atoi, gedeclareerd in <stdlib.h>, voert een eenvoudige conversie uit. De functie zet “13” om in 13, maar ook “12abc” in 12. Ze geeft zowel voor “0” als voor tekst zoals “abc” die niet met een getal begint nul terug. Een resultaat buiten het waardenbereik is ongedefinieerd gedrag, dus een test op alleen cijfers gevolgd door atoi is bij zeer lange invoer nog steeds onveilig.
Een vormregel zoals “alleen één of meer cijfers” vereist een afzonderlijke controle. Wijs een lege string af en vereis dat elke byte voldoet aan isdigit((unsigned char) c). Die regel accepteert “13” en wijst “13a”, “-5” en “” af. De regel controleert de schrijfwijze, niet of de waarde in een geheel getal van de machine past.
Gebruik strtol en bekijk waar de conversie stopte
#include <errno.h>
#include <stdlib.h>
char *end;
errno = 0;
long count = strtol(argv[1], &end, 10);
if (end == argv[1] || *end != '\0' || errno == ERANGE) {
puts("Enter a whole number");
return 1;
}
if (count < 1 || count > 100) {
puts("Count must be from 1 to 100");
return 1;
}
Dit fragment volgt op een controle van het aantal argumenten en gebruikt <stdio.h> voor puts. De 10 kiest decimale conversie. end ontvangt de locatie waar de conversie stopte; met &end kan de functie die locatie opslaan. *end leest het teken op die locatie. Pointerrekenen is niet nodig.
Voor “13a” is de teruggegeven waarde 13, maar is *end gelijk aan 'a', dus wordt de tekst afgewezen. Voor een lege string of “abc” is end gelijk aan het begin van het argument. Dat laat zien dat geen getal is verwerkt. Beide controles zijn nodig: alleen op de afsluitende nul testen zou een lege string ten onrechte accepteren.
Zet vóór elke conversie errno terug op nul. Een waarde buiten het bereik van long zorgt ervoor dat strtol een grenswaarde teruggeeft en ERANGE instelt. Zonder die reset kan een oude fout bij deze conversie lijken te horen. Controleer het resultaat voordat je het naar int vernauwt; gebruik INT_MIN en INT_MAX uit <limits.h> als het volledige bereik van int het toegestane bereik is.
Pas de eigen regel van het programma toe
strtol accepteert witruimte aan het begin en een optioneel teken. Bepaal of die vormen zijn toegestaan. Als de interface alleen cijfers vereist, voer dan naast de conversiecontroles ook de controle op een niet-lege reeks cijfers uit. Controleer na een geslaagde conversie het toegestane waardenbereik van de toepassing voordat je een waarde als aantal of index gebruikt. “0” kan volkomen geldige numerieke tekst zijn en toch ongeldig zijn voor een aantal dat positief moet zijn.
Een Caesarprogramma dat een niet-negatieve sleutel accepteert, controleert eerst argc, dan of de invoer alleen cijfers bevat en daarna het volledige resultaat van strtol en het bereik. Door een geldige sleutel met % 26 te reduceren, krijg je vóór de letterberekening een verschuiving van 0 tot en met 25. Sleutel 27 heeft het effect van sleutel 1. Voer de bereikcontrole uit vóór een expliciete typeconversie naar een smaller type of een berekening die kan overlopen. Voor decimale waarden biedt strtod de bijbehorende interface voor eindpositie en bereikfout.
Belangrijkste punten
- Argumenten die eruitzien als getallen moeten nog steeds worden geconverteerd.
atoikan geldige nul niet onderscheiden van een mislukte conversie.- Controleer of
strtoliets heeft gelezen en alle vereiste tekst heeft verwerkt. - Zet
errnoterug, controleerERANGEen controleer daarna het toegestane waardenbereik van de toepassing. - Een controle op alleen cijfers sluit overloop niet uit.
- Valideer een waarde voordat je die naar een smaller type converteert of als index gebruikt.
6Voorkom toegang buiten de grenzen en bufferoverloop
Grensfouten verbinden verschillende eerdere ideeën: een lus kan een extra iteratie uitvoeren, tekst kan een extra byte nodig hebben en een functie kan de capaciteit van een array uit het oog verliezen. Leer de ongeldige toegang te herkennen voordat je de gevolgen voorspelt. Lees en kopieer invoer daarna binnen bekende grenzen en controleer afzonderlijk of de bewerking is geslaagd en of de invoer volledig is. Zo bevat een buffer waarin de gegevens passen ook de gegevens die het programma bedoelde te accepteren.
6.1 Herken toegang buiten de grenzen en de gevolgen daarvan
Elke toegang tot een array vereist een geldige index. C vereist tijdens de uitvoering geen grenscontrole, dus moet de programmeur de index binnen het object houden. Toegang buiten het bereik heeft ongedefinieerd gedrag: de taal garandeert geen resultaat.
Herken ongeldige toegang
Voor int a[5] zijn de geldige indexen 0 tot en met 4. Index 5 is al te groot en -1 is negatief. Een compiler kan een zichtbare fout melden, maar veel ongeldige indexen hangen af van invoer tijdens de uitvoering en worden niet tijdens het compileren afgewezen.
Een programma met een fout kan goed lijken te werken, vastlopen of onverwachte waarden opleveren. Een schrijfbewerking kan nabijgelegen gegevens aantasten; het verschijnsel kan pas later in een niet-gerelateerde berekening optreden. Een leesbewerking kan bytes buiten het bedoelde object benaderen. Geen van beide bewerkingen heeft een betrouwbaar resultaat. Herhaling van een geslaagde uitvoering kan niet vaststellen dat de toegang geldig is.
Tel elke schrijfbewerking, inclusief het afsluitende nulteken
char name[8];
strcpy(name, "Christopher");
“Christopher” heeft elf tekstbytes. Bij het kopiëren wordt ook het afsluitende nulteken geschreven, dus probeert deze aanroep twaalf bytes in acht posities te plaatsen. Dat is een bufferoverloop. Op echte systemen kan een overloop andere gegevens of besturingsinformatie beschadigen. In het verleden hebben aanvallen, waaronder die van de Morris-worm uit 1988, zulke fouten in de invoerverwerking uitgebuit.
Een overloop kan slechts één byte zijn:
char s[5];
for (int i = 0; i <= 5; i++) {
s[i] = 'x';
}
De lusinhoud wordt zes keer uitgevoerd en schrijft naar index 5. Als je de test verandert in i < 5, blijven vijf schrijfbewerkingen voor tekens binnen de array, maar ontstaat nog steeds geen string. Schrijf voor een string van vier 'x'-tekens alleen naar de indexen 0 tot en met 3 en sla daarna '\0' op bij index 4.
Valideer berekende indexen
Een frequentietabel kan een teken omzetten in een index, maar aftrekken alleen garandeert geen geldig bereik:
int counts[26] = {0};
if (c >= 'a' && c <= 'z') {
counts[c - 'a']++;
}
Bij ASCII-volgorde beperkt die test het resultaat tot 0 tot en met 25. Voor 'A' of een byte met een leesteken kan c - 'a' zonder de test een negatieve index opleveren. Test de oorspronkelijke waarde voordat je een index gebruikt; controleren na het schrijven is te laat.
Valideer bij een tabel de rij en kolom afzonderlijk. In int g[2][3] is een kolomindex van 3 ongeldig, ook als de volgende rij ernaast in het geheugen staat. Gebruik de opslagruimte van de volledige tabel niet als reden om de grens van een rij te overschrijden.
Gebruik controles die bij de bewerking passen
Een arraylus gebruikt een strikte bovengrens; bij toevoegen controleer je het aantal tegenover de capaciteit; bij een string kopiëren controleer je de tekstlengte plus één. Functies ontvangen werkelijke lengtes of capaciteiten van hun aanroepende functies. Deze controles gaan over verschillende grootheden, dus één vast in de code opgenomen grootte kan ze niet allemaal vervangen.
Compileer met waarschuwingen zoals -Wall -Wextra. Met -fsanitize=address -g kunnen GCC en Clang veel ongeldige toegangen op uitgevoerde paden melden en de bronlocatie tonen. Zulke tests helpen fouten te vinden, maar over niet-uitgevoerde paden moet je nog steeds redeneren om de grenzen te controleren. Beoordeel elke lees- en schrijfbewerking met een index door het object, de grens en de voorwaarde die de index geldig houdt te bepalen.
Belangrijkste punten
- Lezen en schrijven buiten de grenzen heeft ongedefinieerd gedrag.
- Een geslaagde uitvoering is geen bewijs dat een index geldig is.
- Bij een gekopieerde string telt het afsluitende nulteken mee in het aantal geschreven bytes.
- Valideer gegevens voordat je er een array-index uit afleidt.
- Controleer elke tabeldimensie afzonderlijk.
- Waarschuwingen en sanitizers helpen programmeerfouten op geteste paden te detecteren.
6.2 Lees en kopieer tekst binnen de grenzen van de buffer
Degene die invoer aanlevert, bepaalt de lengte ervan. Geef leesfuncties een werkelijke buffergrens en controleer wat ze teruggeven. Bepaal daarna of de gegevens een volledige regel vormen en of ze binnen de eigen regels van het programma passen.
Lees één woord met een veldbreedte
Voor char word[16]; leest scanf("%15s", word) hoogstens vijftien tekens die geen witruimte zijn en voegt '\0' toe. De veldbreedte laat één van de zestien posities vrij voor het afsluitende nulteken. %s zonder veldbreedte heeft geen maximale lengte; gets had hetzelfde fundamentele probleem voor regels en is in C11 uit C verwijderd.
Controleer of scanf 1 teruggeeft voordat je een woord gebruikt. De functie leest een woord, geen hele regel met spaties. Overtollige bytes van het woord kunnen ongelezen blijven, dus een veldbreedte beschermt de opslag zonder te bepalen of de hele invoer aanvaardbaar is.
Lees een regel met fgets
char buf[8];
if (fgets(buf, sizeof buf, stdin) == NULL) {
return 1;
}
fgets leest hier hoogstens zeven tekens en schrijft een afsluitende nulbyte. De functie behoudt een nieuweregelteken als ze dat vóór de grens bereikt. Een regel met “hello” en een nieuweregelteken wordt "hello\n" plus het afsluitende nulteken. Een laatste regel die bij het bestandseinde zonder nieuweregelteken eindigt, kan nog steeds met succes worden gelezen. Als vóór het bestandseinde geen tekens zijn gelezen of als een leesfout optrad, is het resultaat NULL; verwerk die buffer dan niet als nieuwe invoer.
Onderscheid een opgeslagen nieuweregelteken van een onvolledige regel
Zoek een nieuweregelteken voordat je het verwijdert:
size_t end = strcspn(buf, "\n");
int had_newline = buf[end] == '\n';
buf[end] = '\0';
Neem <string.h> op. Als er geen nieuweregelteken is opgeslagen, is end de tekstlengte en overschrijft de toewijzing het bestaande afsluitende nulteken. Een ontbrekend nieuweregelteken kan duiden op een onvolledige regel, een buffer die precies vóór een nieuweregelteken is gevuld of een laatste regel die bij het bestandseinde eindigde. Op zichzelf bewijst dit niet dat er nog tekens over zijn.
Voor de invoerregel “abcdefghij” en een buffer van acht bytes slaat de eerste leesbewerking “abcdefg” op en kan de volgende “hij\n” lezen. Als je het tweede deel als een afzonderlijk antwoord behandelt, splits je één logische invoer. Een programma kan een regel zonder vereist nieuweregelteken afwijzen of de rest ervan lezen en weggooien voordat het opnieuw om invoer vraagt. Leg het invoerbeleid vast voordat je het implementeert.
Gebruik 32 bytes voor maximaal dertig ASCII-tekens in een naam plus een nieuweregelteken en een afsluitend nulteken. Voor UTF-8 is dit een grens in bytes: dertig weergegeven tekens kunnen meer opslagruimte nodig hebben.
Kopieer pas na controle van alle vereisten
char user[10];
if (argc != 2) return 1;
if (strlen(argv[1]) >= sizeof user) {
puts("Name too long");
return 1;
}
strcpy(user, argv[1]);
De controle van het aantal argumenten komt eerst. De lengtecontrole laat daarna hoogstens negen tekstbytes toe en laat de tiende positie vrij voor nul. Een schrijffunctie moet de capaciteit expliciet ontvangen, zoals in read_name(out, capacity), omdat sizeof out daarbinnen een pointerparameter meet.
Lees voor numerieke invoer een volledige regel en converteer die met strtol. Controleer daarbij de eindpositie, een eventuele bereikfout en het toegestane waardenbereik. Een mislukte scanf("%d", &n) kan de problematische tekst ongelezen laten staan; als je de aanroep blindelings herhaalt, kan die op dezelfde bytes eindeloos blijven mislukken. Controleer minimaal het aantal geslaagde toewijzingen en handel de ongeldige invoer af voordat je het opnieuw probeert.
Belangrijkste punten
- Stel de veldbreedte voor het lezen van een woord in op één minder dan de buffercapaciteit.
- Controleer een leesresultaat voordat je de buffer gebruikt.
fgetsbehoudt een nieuweregelteken alleen als de functie er binnen de grens één bereikt.- Een ontbrekend nieuweregelteken bewijst op zichzelf niet dat invoer overblijft.
- Houd rekening met tekstbytes, een eventueel behouden nieuweregelteken en het afsluitende nulteken.
- Controleer of een argument aanwezig is voordat je de tekst meet en kopieert.
- Geef de buffercapaciteit door aan een functie die naar de buffer schrijft.
Arrays en strings in C: voorbeelden
1Volg een array van declaratie tot functieaanroep
13 stappen
- 1IntroductieGeef meerdere waarden één naam
Een array bevat een vast aantal elementen van één type. Een lus selecteert posities, terwijl een functie via een arrayparameter op dezelfde opslag kan werken.
Volg vier sensormetingen vanaf hun declaratie via een totaal naar een gemiddelde. Houd bij elke stap drie grootheden apart: het aantal elementen, de laatste geldige index en het aantal bytes dat voor opslag wordt gebruikt.
- 2VoorbeeldLees de beginposities
int readings[4] = {11, 16, 13};Er zijn vier elementen, met indexen 0 tot en met 3. De initialisator geeft 11, 16 en 13 op de eerste drie posities. De weggelaten waarde wordt nul, dus de array is
{11, 16, 13, 0}.De nul volgt uit een initialisatieregel en is geen teken dat de array maar drie elementen heeft. Bij een lokale array zonder initialisator moet je de waarden vóór gebruik schrijven.
- 3UitlegTel elementen bij de declaratie
size_t n = sizeof readings / sizeof readings[0];De teller meet alle vier de elementen en de noemer meet er één. Waar
intvier bytes inneemt, is dit zestien gedeeld door vier, met 4 als resultaat. Dezelfde expressie werkt bij een andere grootte van een geheel getal.readings[3]is het laatste element.readings[4]ligt voorbij het einde, ook al is het aantal elementen van de array 4.size_tis het type zonder teken dat voor dit grootteloopresultaat wordt gebruikt. - 4UitdagingWijzig de laatste meting
De declaratie is nog steeds
int readings[4] = {11, 16, 13};. Welke toewijzing vervangt de nul door 20 en wat is het resulterende aantal?---reveal---
Gebruik
readings[3] = 20;. De resulterende waarden zijn{11, 16, 13, 20}en het aantal blijft 4. Een toewijzing aan een element wijzigt een waarde, niet het aantal posities. Index 4 zou één positie te ver zijn en kan geen opslag aan deze array toevoegen. - 5VoorbeeldBouw het totaal iteratie voor iteratie op
int sum = 0; for (size_t i = 0; i < n; i++) { sum += readings[i]; }Bij
{11, 16, 13, 20}wordt de lopende som achtereenvolgens 11, 27, 40 en 60. Na index 3 wordt i gelijk aan 4 en mislukt de test vóór een volgende toegang.Door de som bij nul te laten beginnen, heeft de eerste waarde een schoon startpunt. De strikte bovengrens laat de lus precies de vier bestaande elementen bezoeken.
- 6KernpuntBehoud een gemiddelde met decimalen
Voor deze vier metingen geeft
(double) sum / nde waarde 15,0. De expliciete typeconversie vindt vóór de deling plaats, zodat de bewerking een resultaat met decimalen kan opleveren wanneer het totaal verandert.Als het totaal 61 was, zou geheeltallige deling
sum / 4de waarde 15 opleveren, terwijlsum / 4.015,25 zou opleveren. Als je het al afgeknotte geheeltallige resultaat aan een double toewijst, krijg je alleen 15,0; het weggelaten deel achter de komma komt niet terug. - 7TipKies een geldige beginkandidaat
Een zoekopdracht naar het maximum heeft een beginwaarde uit een niet-lege array nodig. Initialiseer voor
{-6, -2, -9}maxmet -6 en vervang die waarde door -2 wanneer die grotere waarde verschijnt. De laatste vergelijking laat -2 ongewijzigd.Als je max met nul initialiseert, krijg je nul terug, terwijl die waarde niet voorkomt. Bij lineair zoeken is de bijbehorende stopregel ook belangrijk: één afwijkende waarde bewijst niet dat de zoekopdracht is mislukt; latere elementen moeten nog worden gecontroleerd.
- 8UitdagingBlijf zoeken
Een zoekopdracht naar 13 controleert
{11, 16, 13, 20}. Na controle van index 0 geeft de zoekopdracht -1 terug omdat 11 verschilt van 13. Wat moet veranderen en waar staat de overeenkomst?---reveal---
Blijf na een verschil controleren en geef pas -1 terug als geen enkele kandidaat voldoet. Hier verschilt ook index 1, maar index 2 komt overeen. Een geslaagde zoekopdracht kan daar stoppen. De mislukte eerste vergelijking beschrijft één element, niet de volledige array.
- 9VerbandBreng de gemiddeldeberekening onder in een functie
double mean(const int a[], size_t n);De arrayparameter deelt de toegang tot de elementen van de aanroepende functie. De parameter bevat hun aantal niet, dus geeft de tweede parameter dat door.
constvoorkomt onbedoeld schrijven via a in deze bewerking die alleen leest.Bereken het aantal waar
readingsis gedeclareerd en roepmean(readings, n)aan. Binnen mean meetsizeof aeen pointerparameter in plaats van de array met vier elementen van de aanroepende functie. - 10VoorbeeldHandel het lege bereik af vóór de deling
double mean(const int a[], size_t n) { if (n == 0) return 0.0; int sum = 0; for (size_t i = 0; i < n; i++) sum += a[i]; return (double) sum / n; }Voor de vier kleine metingen blijft het totaal 60 en is het resultaat 15,0. Als n gelijk is aan nul, is het gekozen resultaat 0,0 en vindt geen arraytoegang of deling plaats. De aanroepende functie moet een correct bruikbaar aantal doorgeven.
- 11UitdagingLeg een gewijzigde array van de aanroepende functie uit
Een andere functie ontvangt
int a[], size_t nen zet elke bezochtea[i]op nul. Wat gebeurt er met de metingen van de aanroepende functie en hoe kan een functie die alleen een totaal berekent zulke schrijfbewerkingen voorkomen?---reveal---
De elementen van de aanroepende functie worden nul omdat de functie naar de gedeelde arrayopslag schrijft. De vier posities bestaan nog steeds. Een functie die alleen een totaal berekent, moet
const int a[]gebruiken, waardoor toewijzingen aan elementen via a ongeldig worden. Een scalaire kopie van n wijzigen zou de tellervariabele van de aanroepende functie niet veranderen. - 12UitdagingGebruik alleen de metingen die bestaan
Een buffer heeft capaciteit 10, maar slechts vier metingen zijn in gebruik. Voordat je een gemiddelde berekent, moet een nieuwe meting worden toegevoegd. Welke controles en welk aantal moet het programma gebruiken?
---reveal---
Controleer of het aantal gebruikte elementen, 4, kleiner is dan capaciteit 10. Schrijf op index 4 en werk daarna het aantal bij naar 5. Geef dat aantal gebruikte elementen door aan mean, zodat de functie precies de vijf waarden verwerkt. Als je de capaciteit zou doorgeven, zouden posities worden meegenomen waarvoor geen metingen zijn opgegeven.
- 13SamenvattingVerbind elk aantal met zijn taak
Een declaratie maakt de posities, een lus bezoekt de gebruikte posities en een functie ontvangt het bruikbare aantal expliciet. Een parameter die alleen wordt gelezen, voorkomt dat berekeningen de invoer overschrijven.
Houd bij het beoordelen van arraycode de eerste en laatste bezochte index en de toestand van elke accumulator bij. Begin bij achterwaartse
size_t-lussen op n, ga door zolang i positief is en benadera[i - 1], zodat je bij een leeg bereik niets van nul hoeft af te trekken.
2Voer tekstbewerkingen uit op opgeslagen bytes
16 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieLet op zowel tekst als opslag
- 2UitlegLees een teken als code
- 3UitdagingLoop terug binnen het alfabet
- 4VoorbeeldMaak een beschrijfbare string
- 5KernpuntVerplaats het einde zonder de opslag te verplaatsen
- 6UitdagingLaat een positie voor het einde vrij
- 7VoorbeeldHoud lezen en schrijven gescheiden
- 8VoorbeeldMaak de nieuwe string af
- 9UitdagingKeer letters om zonder het afsluitende nulteken
- 10TipClassificeer bytes met geldige argumenten
- 11VoorbeeldBreng een UTF-8-letter met accent in beeld
- 12UitlegHerken vervolgbytes
- 13UitdagingMeet een nieuw gecodeerd woord
- 14VerbandKies bewerkingen die tekens heel houden
- 15UitdagingControleer een voorgestelde kortere aanpak voor tekst
- 16SamenvattingZoek het einde en de tekengrenzen
3Stel tekst samen, doorzoek die en maak die veilig op
14 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieBepaal het contract van elke functie
- 2VoorbeeldBegin met een volledige kopie
- 3VoorbeeldVoeg toe bij het bestaande einde
- 4UitdagingBepaal of nog iets toevoegen past
- 5UitlegGebruik nul om gelijke tekst te herkennen
- 6VoorbeeldLees vanaf een gevonden locatie
- 7UitdagingOnderzoek een opdrachtcontrole op basis van een beginstuk
- 8TipVerwacht dat tokenisatie tekst verandert
- 9VoorbeeldMaak tekst op binnen een bekende capaciteit
- 10UitdagingInterpreteer dezelfde opmaak met minder ruimte
- 11KernpuntEen grens kan bronbytes tellen
- 12VoorbeeldVerplaats een overlappend gebied
- 13UitdagingBehoud een volledig resultaat na het verschuiven
- 14SamenvattingOnderscheid bytes van tekstresultaten
4Lees een tabel en kies een opslagvorm voor een lijst met strings
10 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieGeef elke positie twee indexen
- 2VoorbeeldPlaats waarden in rijen
- 3VoorbeeldStel een rijtotaal opnieuw in aan het begin van de rij
- 4UitdagingVerander de groepering en behoud de indexen
- 5UitlegGeef een functie de rijbreedte door
- 6VoorbeeldReserveer per rij één string met afsluitend nulteken
- 7KernpuntVerwijzingen staan verschillende stringlengtes toe
- 8UitdagingVervang tekst in de juiste opslag
- 9UitdagingHoud beide dimensies geldig in een functie
- 10SamenvattingHoud de vorm van de tabel zichtbaar
5Valideer een selectie via de opdrachtregel
11 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieOntvang tekst voordat je die interpreteert
- 2VoorbeeldKoppel een shellopdracht aan elementen
- 3UitlegControleer het aantal vóór de conversie
- 4UitdagingGroepeer één naam correct
- 5TipEen teruggegeven geheel getal is niet genoeg
- 6VoorbeeldOnderzoek een volledige conversie
- 7UitlegControleer het eigen bereik van de selectie
- 8UitdagingHerken tekst die gedeeltelijk numeriek lijkt
- 9KernpuntSchrijfwijze en waarde zijn afzonderlijke regels
- 10UitdagingCombineer groepering en numerieke validatie
- 11SamenvattingControleer aanwezigheid, conversie en doel
6Herstel een begrensde invoerroutine
13 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieBegrens de schrijfbewerking en controleer het resultaat
- 2VoorbeeldZoek de extra schrijfbewerking
- 3KernpuntEen geldige laatste positie kan het einde bevatten
- 4UitdagingControleer een index die uit een byte is afgeleid
- 5UitlegLees een woord met ruimte voor het afsluitende nulteken
- 6VoorbeeldLees één begrensd deel van een regel
- 7VoorbeeldBekijk waar een lange regel wordt gesplitst
- 8TipOnderzoek een nieuweregelteken voordat je het verwijdert
- 9UitdagingReserveer ruimte voor een volledige regel
- 10VoorbeeldControleer een kopie vóór het schrijven
- 11UitdagingOnderscheid een veilig beginstuk van een geaccepteerd antwoord
- 12VerbandGebruik diagnostische meldingen en redeneer over grenzen
- 13SamenvattingHoud vier controles apart
Arrays en strings in C: oefenvragen
Set 1: Arraywaarden, lussen en functieaanroepen10 Oefenvragen
Vraag 1 van 10
a[3] na int a[5] = {6, 9};?Toon antwoordVerberg antwoord
Vraag 2 van 10
int a[7];, waarbij int 4 bytes inneemt. Welk paar geeft sizeof a en de laatste geldige index?Toon antwoordVerberg antwoord
Vraag 3 van 10
int a[] = {-12, -4, -9}; teruggeven?Toon antwoordVerberg antwoord
Vraag 4 van 10
Wat drukt deze code af?
int a[] = {3, 8, 5, 2};
int sum = 0;
for (int i = 1; i < 4; i++) sum += a[i];
printf("%d", sum);
Toon antwoordVerberg antwoord
Vraag 5 van 10
{2, 9, 7, 4} geeft bij het eerste ongelijke element -1 terug. Waar moet de retour bij mislukking plaatsvinden?Toon antwoordVerberg antwoord
Vraag 6 van 10
a[i] met a[5 - 1 - i] wisselt voor i = 0 en i = 1, uitgaande van {4, 7, 1, 8, 6}?Toon antwoordVerberg antwoord
Vraag 7 van 10
void set_first(int a[]) voert a[0] = 11; uit. Wat is het eerste element van de array van de aanroepende functie na de aanroep?Toon antwoordVerberg antwoord
Vraag 8 van 10
void f(int a[], size_t n) nemen pointers 8 bytes en gehele getallen 4 bytes in. Wat is sizeof a / sizeof a[0]?Toon antwoordVerberg antwoord
Vraag 9 van 10
size_t voor n en i. Ze moet een array achterwaarts afdrukken en werken voor n = 0. Welke parameter en lus voldoen aan beide vereisten?Toon antwoordVerberg antwoord
Vraag 10 van 10
a[4] uit int a[4] leest?Toon antwoordVerberg antwoord
Set 2: Tekens, stringeinden en UTF-810 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
'6' - '0' op?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
('W' - 'A' + 5) % 26 + 'A'?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
c aan isalpha worden doorgegeven zonder risico op een negatief byteargument?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
char color[] = "amber";?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
char s[8] = "planet"; s[3] = '\0'; s[0] = 'P';?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
char tag[4] = "east"; printf("%s", tag); onveilig?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
"m8n2p" en schrijft die naar een uitvoerarray die groot genoeg is. Wat moet het na de laatste p schrijven?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
char s[] = "lamp"; om door s[i] te wisselen met s[len - i] zolang i < len / 2, waarbij len gelijk is aan strlen(s). Wat zijn de uiteindelijke strlen(s) en de ongewijzigde capaciteit?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
41 C3 B1 42 00. Een programma schrijft nul op byte-index 2. Wat zijn de nieuwe strlen en de UTF-8-geldigheid van de tekst?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Set 3: Kies en controleer bibliotheekbewerkingen10 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
"silver"?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
char label[10] = "blue"; strcat(label, "berry"); het volledige resultaat opslaan?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
char out[20]; strcat(out, "go");. Waarom is dit een ongeldige manier om een string op te bouwen?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
char *p = strrchr("archive.backup.bin", '.');?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
"on,,off;wait". Aanroepen gebruiken strtok(s, ",;") en herhalen daarna strtok(NULL, ",;") tot NULL. Welke tokens ontstaan en blijft s behouden?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
char b[6]; int r = snprintf(b, sizeof b, "%s:%d", "job", 84); op en wat geeft de aanroep terug?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
"AB". Het programma voert strncat(b, "123456", sizeof b - strlen(b) - 1) uit. Wat is de resulterende tekst en hoeveel opgeslagen bytes zijn er inclusief nul?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
char s[] = "wxyz"; memmove(s, &s[1], 4);?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Set 4: Tabellen, tekstlijsten en invoer bij het starten10 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
int table[4][6]?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
sizeof table[0] voor int table[3][5]?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
{{2, 7, 4}, {6, 1, 5}}. Een lus initialiseert sum één keer op nul vóór beide lussen, telt telkens één rij op en drukt na elke rij af zonder sum opnieuw in te stellen. Welke waarden worden afgedrukt en hoe wordt dit gecorrigeerd?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
char names[3][width] om “Iris”, “Magnolia” en “Ash” als volledige ASCII-strings op te slaan?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
char rows[2][5] = {"oak", "elm"}; en const char *refs[] = {"oak", "elm"};. Het moet het eerste woord in de lijst vervangen door de volledige tekst “cedar”. Welke aanpak is geldig voor elke opslagvorm?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
./mark "West Room" 9. Wat zijn argc en argv[2]?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Set 5: Invoergrenzen en volledige resultaten10 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
char word[18] een positie vrij voor een afsluitend nulteken?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
"pine\n" naar een array van 10 bytes. Wat zijn strlen van het resultaat en de index van het afsluitende nulteken?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
char b[6] zonder andere leesbewerkingen. Welke tekst slaat de tweede aanroep op?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
counts[c - 'a']++ onveilig voor ongecontroleerde tekeninvoer?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
char out[6]. Op de aanroep snprintf(out, sizeof out, "%s%d", "R-", 1234) volgt if (r > sizeof out) reject();, waarbij r de niet-negatieve retourwaarde is. Wat wordt opgeslagen, wijst die test het af en wat moet veranderen?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
ERANGE af en vereist *end == '\0', maar controleert niet op end == start. Welke ongeldige invoer kan toch als nul worden geaccepteerd?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
41 C3 A9 E2 82 AC 00. Een programma kopieert die naar char b[5] en reserveert de laatste positie voor nul. Wat zijn de resulterende strlen, het aantal beginbytes en de geldigheid van de codering?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Set 6: Volg en herstel gecombineerde C-bewerkingen10 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
int a[4] = {[2] = 9};?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
int g[3][4] de elementpositie van g[2][1] bij indexering vanaf nul in rijgewijze opslag?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
./pick "" blue uit. Hoe verschillen argv[1] en argv[argc]?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
int a[], size_t n en voert a[0] = 0; n = 0; uit. De aanroepende functie gaf {5, 8, 2} en aantal 3 door en berekent daarna de geheeltallige som van de elementen gedeeld door het aantal. Welk gemiddelde en welk aantal bij de aanroepende functie ontstaan?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
strncpy(b, "planet", sizeof b);. Het programma vereist het volledige oorspronkelijke woord. Welke oplossing voldoet aan die eis?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
int values[4] = {14, 28, 35, 49};. Het converteert “04” volledig met decimale strtol, accepteert selecties 1–4 en leest daarna values[selected]. Het moet alle vier de selecties toestaan en selectie 1 aan de eerste waarde koppelen. Wat gebeurt er en welke indexregel herstelt dit?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Kom je niet uit je eigen opgave? Huiswerkhulp
Kernbegrippen
A
Aaneenschakeling
Aantal gebruikte elementen
Aantal geslaagde toewijzingen
scanf met succes heeft voltooid en wordt gebruikt om te controleren of gevraagde gegevens daadwerkelijk zijn gelezen.Accumulator
sum bij nul te laten beginnen, kan elke sum += a[i] het volgende arrayelement aan het huidige totaal toevoegen.Afkapping
Afsluitend nulteken
text[2] = '\0' te schrijven, stoppen stringfuncties na de eerste twee tekens in die array.Afsluitstatus
main geeft een succesvolle voltooiing aan.argc
argc geeft het aantal argumentstrings dat aan main is doorgegeven, normaal inclusief de string waarmee het programma is gestart../label red blue uitvoeren in een gewone shell geeft argc gelijk aan 3: de startnaam en twee kleuren.argv
argv geeft via indexen toegang tot argumentstrings, gevolgd door een nulpointer op de positie die argc aangeeft.argc kan een programma strcmp(argv[1], "-v") gebruiken om de eerste optie te herkennen.Array
int levels[6] reserveert zes gehele getallen; als je levels[2] wijzigt, verandert de derde opgeslagen waarde.Array met variabele lengte
const int n = 6; int a[n]; een array met variabele lengte omdat n geen constante expressie is.Array van stringpointers
const char *names[] = {"Al", "Mina"} slaat twee verwijzingen op en maakt het mogelijk een verwijzing te vervangen.Arrayparameter
int a[] is gedeclareerd, heeft nog steeds een afzonderlijke lengte nodig voordat ze haar invoer kan doorlopen.ASCII
'8' - '0' levert 8 op omdat codes van cijfertekens opeenvolgend zijn.atoi
atoi converteert een numeriek begindeel naar int zonder betrouwbare foutmelding en heeft ongedefinieerd gedrag bij overloop.atoi 18 op, dus een teruggegeven getal bewijst niet dat de volledige invoer numeriek was.B
Bestandseinde
fgets kan nog steeds slagen als de functie tekens heeft gelezen voordat die toestand werd bereikt.fgets-buffer nog steeds die laatste tekst ontvangen.Bitmasker
0xC0 behoudt de twee hoogste bits zodat een programma het UTF-8-vervolgpatroon kan herkennen.Buffer
Bufferoverloop
C
C-string
char pet[] = "dog" bevat drie letters gevolgd door een teken met waarde nul.Caesarverschuiving
Capaciteit
D
Deelstring
strstr vindt de eerste overeenkomende beginlocatie.E
Eén-ernaastfout
i <= n laat een doorloop van n elementen vanaf index nul één extra toegang op index n proberen.Eindpointer
strtol 9 terug, maar verwijst de eindpointer naar de z die niet is verwerkt.Element
int a[3] = {8, 1, 6} bevat element a[1] de waarde 1 en kun je er een ander geheel getal aan toewijzen.ERANGE
ERANGE duidt een bereikfout aan die via errno wordt gemeld, zoals een strtol-resultaat dat te groot of te klein is voor long.errno vóór de conversie op nul en test daarna op ERANGE voordat je een lange reeks cijfers accepteert.Escapesequentie
"A\nB" bevat een nieuweregelteken tussen de letters; de backslash en n coderen één teken.F
fgets
fgets leest begrensde regelinvoer, behoudt een bereikt nieuweregelteken en voegt een afsluitend nulteken toe wanneer ze met succes tekst leest.Filteren
Frequentiearray
counts[4]++ één voorkomen toe aan de telling voor dat cijfer.G
Geneste lussen
I
Index
Initialisator
int hits[4] = {3} initialiseert de eerste teller op 3 en de andere drie tellers op nul.K
Kolom
g[r][c].g[r][c] leest.L
Lege string
char message[20] = "" biedt een geldige lege doelstring om later tekst toe te voegen die binnen de capaciteit past.Lineair zoeken
{3, 8, 2} slaagt op index 2 nadat de eerdere ongelijke elementen zijn gecontroleerd.Locale
toupper in de locale “C” zet een volledige UTF-8-letter met accent niet om in de hoofdlettervorm.M
memcmp
memcmp vergelijkt een vast aantal bytes en meldt hun volgorde. Ze test opslagrepresentaties in plaats van numerieke waarden.memcmp verschillende opgeslagen bytes vindt.memcpy
memcpy kopieert precies een gevraagd aantal bytes tussen niet-overlappende gebieden zonder afsluitende stringtekens te interpreteren.memcpy(b, a, sizeof a) kopieert de volledige opslag van array a wanneer b genoeg ruimte heeft en een afzonderlijk gebied is.memmove
memmove kopieert een gevraagd aantal bytes met gedefinieerd gedrag, ook wanneer bron- en doelgebied overlappen.memmove.memset
memset vult een gebied met een herhaalde bytewaarde zonder die numerieke waarde afzonderlijk aan elk arrayelement toe te wijzen.memset(counts, 0, sizeof counts) zet een array van gehele getallen op nul; bytewaarde 1 zou niet het gehele getal 1 toewijzen.Modulaire terugloop bij gehele getallen zonder teken
size_t kan niet stoppen doordat de waarde negatief wordt; gebruik i > 0 en benader positie i - 1.N
Nulpointer
strchr(name, '.') != NULL voordat je het resultaat gebruikt als begin van het achterste deel van een bestandsnaam.O
Omzetting van tekst naar een getal
% 26 kan reduceren.Ongedefinieerd gedrag
Onvolledige regel
fgets-delen aankomen, dus mag het tweede deel geen nieuw antwoord worden.Opdrachtregelargument
P
Parameter met const-kwalificatie
const int a[] omdat de invoerwaarden optellen geen wijziging ervan vereist.Parameter met een variabel gemodificeerd type
int g[rows][cols] na parameters die positieve, overeenkomende aantallen rijen en kolommen definiëren.R
Rij
int table[2][5] duidt table[1] de tweede rij aan, die vijf posities voor gehele getallen bevat.Rijbreedte
int g[][6] accepteert rijen van zes gehele getallen breed, terwijl de aanroepende functie het aantal rijen afzonderlijk doorgeeft.Rijgewijze opslagvolgorde
grid[0][3] in de opslag van een tabel met vier kolommen is grid[1][0].S
Scheidingsteken
size_t
size_t is een geheelgetaltype zonder teken dat wordt gebruikt voor objectgroottes en door sizeof wordt teruggegeven; het wordt vaak gebruikt voor arraylengtes.printf("%zu", sizeof data) gebruikt het formaat voor groottes om het aantal bytes af te drukken dat data inneemt.snprintf
snprintf maakt tekst op binnen een opgegeven capaciteit en geeft de volledig benodigde tekstlengte of een negatief foutresultaat terug.strcat
strcat voegt een bronstring toe bij het bestaande afsluitende nulteken van een doelstring en schrijft na de gecombineerde tekst een nieuw afsluitend nulteken.strchr
strchr vindt het eerste overeenkomende teken in een string en geeft de locatie ervan terug, of een nulpointer als er geen overeenkomst is.strchr naar een punt zoeken in “name.part.ext” vindt het achterste deel “.part.ext”, inclusief de eerste punt.strcmp
strcmp vergelijkt strings met afsluitend nulteken als bytes zonder teken en geeft afhankelijk van hun volgorde een negatief resultaat, nul of een positief resultaat terug.strcmp("oak", "oak") == 0 test gelijke inhoud, ook wanneer de twee strings afzonderlijke opslag innemen.strcpy
strcpy kopieert een volledige bronstring en het afsluitende nulteken naar een niet-overlappend doel met voldoende beschikbare opslag.char out[5].strcspn
strcspn meet het eerste deel van een string dat geen van de tekens bevat die in het tweede argument zijn opgegeven.strcspn("fir:oak", ":,") geeft 3 terug omdat het eerste opgegeven scheidingsteken na de drie letters van fir staat.Stringlengte
Stringlijst met vaste rijbreedte
char labels[5][12] heeft elk label twaalf bytes opslagruimte, ook wanneer de huidige tekst korter is.Stringliteral
const char *label = "ready" verwijst naar een literal; een beschrijfbare kopie kan char label[] = "ready" gebruiken.strlen
strlen doorzoekt een geldige string tot het afsluitende nulteken en geeft het aantal voorafgaande bytes terug als een size_t-waarde.char tag[30] = "oak" is strlen(tag) gelijk aan 3, terwijl sizeof tag de volledige capaciteit van 30 bytes meldt.strncat
strncat voegt hoogstens een opgegeven aantal tekstbytes uit de bron toe en schrijft daarna een afsluitend nulteken.strncmp
strncmp vergelijkt hoogstens een opgegeven aantal stringbytes en stopt eerder bij een einde of verschil.strncpy
strncpy kopieert tot een grens en vult kortere tekst aan met nullen, maar schrijft geen afsluitend nulteken als de bron die grens vult.strrchr
strrchr vindt het laatste overeenkomende teken in een string en geeft de locatie ervan terug, of een nulpointer als er geen overeenkomst is.strrchr het scheidingsteken van de extensie vinden.strtol
strtol converteert tekst naar long met een gekozen grondtal en rapporteert een stoplocatie en informatie over bereikfouten.strtol(text, &end, 10) kan het programma een overgebleven letter na verder geldige decimale cijfers afwijzen.T
Tekenclassificatie
<ctype.h> of een tekencode tot een categorie behoort, zoals cijfers, letters of witruimte.isdigit((unsigned char) c) geeft een resultaat anders dan nul wanneer de opgeslagen byte een decimaal cijfer voorstelt.Tekencodering
Tekenconstante
int die een tekencode voorstelt, zoals de code voor een letter.printf("%c %d", 'B', 'B') de letter B en de numerieke waarde 66.Toegang buiten de grenzen
a[8] benaderen in een array met acht elementen is ongeldig, ook als een testuitvoering een bruikbare waarde lijkt terug te geven.Toegestaan waardenbereik van de toepassing
Tokenisatie
strtok doet dit door de invoer te wijzigen en een positie te onthouden.strtok(NULL, ",") gaat verder met het splitsen van dezelfde beschrijfbare invoer in plaats van opnieuw te beginnen.Transformatie op dezelfde geheugenlocatie
Tweedimensionale array
int board[4][6] biedt 24 gehele getallen, bereikbaar via vier geldige rij-indexen en zes geldige kolomindexen.U
Uitvoerarray
out[i] schrijven terwijl het eigenaarschap van de array bij de aanroepende functie blijft.Unicode-codepunt
UTF-8
V
Veldbreedte
%s-conversie begrenst het aantal invoertekens dat wordt opgeslagen vóór de extra afsluitende nulbyte.char word[10] reserveert de conversie %9s de tiende beschikbare byte voor het afsluitende nulteken.Vergelijking op bytewaarden
strcmp een Latijnse letter met accent na ASCII-z omdat de beginbyte een hogere waarde heeft.Vervolgbyte
10 en volgt op een beginbyte binnen een codepunt dat met meerdere bytes is gecodeerd.W
Woordgrens
Over deze les
Door StudeliFout melden
Maak je eigen Studiemateriaal
Maak van je aantekeningen, slides en documenten Leermodules, Oefenvragen, Flashcards en 6 andere tools.