Hoofdstuk – 5
Introductie van C-programmering
Introductie
'C' is een van de meest populaire computertalen in de computerwereld van vandaag. De programmeertaal 'C' is in 1972 ontworpen en ontwikkeld door Brian Kernighan en Dennis Ritchie in The Bell Research Labs.
'C' is een taal die speciaal is gemaakt om de programmeur toegang te geven tot bijna alle interne onderdelen van de machine - registers, I/O-slots en absolute adressen. Tegelijkertijd maakt 'C' zoveel gegevensverwerking en geprogrammeerde tekstmodularisatie mogelijk als nodig is om zeer complexe multi-programmeerprojecten op een georganiseerde en tijdige manier te bouwen.
Hoewel deze taal oorspronkelijk bedoeld was om onder UNIX te draaien, was er grote belangstelling voor het draaien onder het MS-DOS-besturingssysteem op de IBM-pc en compatibele apparaten. Het is een uitstekende taal voor deze omgeving vanwege de eenvoud van expressie, de compactheid van de code en het brede scala aan toepasbaarheid.
Ook, vanwege de eenvoud en het gemak van het schrijven van een C-compiler, is het meestal de eerste taal op hoog niveau die beschikbaar is op elke nieuwe computer, inclusief microcomputers, minicomputers en mainframes.
Waarom C gebruiken bij het programmeren van gegevensherstel
In de huidige wereld van computerprogrammering zijn er veel talen op hoog niveau beschikbaar. Deze talen zijn goed met veel functies die geschikt zijn voor de meeste programmeertaken. Toch zijn er verschillende redenen waarom C de eerste keuze is van programmeurs die willen programmeren voor gegevensherstel, systeemprogrammering, apparaatprogrammering of hardwareprogrammering:
- C is een populaire taal die de voorkeur heeft van professionele programmeurs. Als gevolg hiervan is er een grote verscheidenheid aan C-compilers en handige accessoires beschikbaar.
- C is een draagbare taal. Een C-programma dat voor het ene computersysteem is geschreven, kan met weinig of geen wijziging worden gecompileerd en op een ander systeem worden uitgevoerd. De draagbaarheid wordt verbeterd door de ANSI-standaard voor C, de set regels voor C-compilers.
- C staat een breed gebruik van modules toe bij het programmeren. C-code kan worden geschreven in routines die functies worden genoemd. Deze functies kunnen opnieuw worden gebruikt in andere applicaties of programma's. U hoeft geen extra inspanningen te leveren bij het programmeren van een nieuwe applicatie om dezelfde module te maken die u eerder in een andere applicatieprogrammering hebt ontwikkeld.
U kunt deze functie in een nieuw programma gebruiken zonder enige wijziging of enkele kleine wijzigingen. In het geval van programmeren voor gegevensherstel, zult u merken dat deze kwaliteit erg nuttig is wanneer u dezelfde functies meerdere keren in verschillende toepassingen van verschillende programma's moet uitvoeren.
- C is een krachtige en flexibele taal. Dit is de reden waarom C wordt gebruikt voor projecten die zo divers zijn als besturingssystemen, tekstverwerkers, afbeeldingen, spreadsheets en zelfs compilers voor andere talen.
- C is een taal van weinig woorden, die slechts een handvol termen bevat, trefwoorden genaamd, die dienen als de basis waarop de functionaliteit van de taal is gebouwd. Deze trefwoorden, ook wel gereserveerde woorden genoemd, maken het krachtiger en geven het brede gebied van programmeren en een programmeur het gevoel om elk type programmering in C te doen.
Laat me aannemen dat je niets weet in C
Ik neem aan dat je niets weet van programmeren in C en ook geen idee hebt van programmeren. Ik zal beginnen met de meest elementaire concepten van C en je meenemen naar het hoge niveau van C-programmering, inclusief de meestal intimiderende concepten van aanwijzers, structuren en dynamische toewijzing.
Om deze concepten volledig te begrijpen, zal het wat tijd en werk van uw kant vergen, omdat ze niet bijzonder gemakkelijk te begrijpen zijn, maar het zijn zeer krachtige hulpmiddelen.
Programmeren in C is een enorme troef in die gebieden waar je misschien assembler moet gebruiken, maar het liever een eenvoudig te schrijven en gemakkelijk te onderhouden programma wilt houden. De tijdwinst bij het coderen van C kan in dergelijke gevallen enorm zijn.
Hoewel de C-taal een goede reputatie geniet wanneer programma's van de ene implementatie naar de andere worden getransporteerd, zijn er verschillen in compilers die u zult tegenkomen wanneer u een andere compiler probeert te gebruiken.
De meeste verschillen worden duidelijk wanneer u niet-standaard extensies gebruikt, zoals oproepen naar het DOS BIOS bij gebruik van MS-DOS, maar zelfs deze verschillen kunnen worden geminimaliseerd door zorgvuldige keuze van programmeerconstructies.
Toen duidelijk werd dat de programmeertaal C een zeer populaire taal aan het worden was die op een groot aantal computers beschikbaar was, kwam een groep bezorgde individuen bijeen om een standaardreeks regels voor het gebruik van de programmeertaal C voor te stellen.
De groep vertegenwoordigde alle sectoren van de software-industrie en na vele vergaderingen en vele voorontwerpen schreven ze uiteindelijk een aanvaardbare standaard voor de C-taal. Deze is aanvaard door het American National Standards Institute (ANSI) en door de International Standards Organization (ISO).
Het wordt aan geen enkele groep of gebruiker opgedrongen, maar aangezien het zo algemeen aanvaard is, zou het economische zelfmoord zijn voor elke compilerschrijver om te weigeren zich aan de norm te houden.
De programma's die in dit boek zijn geschreven, zijn voornamelijk bedoeld voor gebruik op een IBM-PC of compatibele computer, maar kunnen worden gebruikt met elke ANSI-standaardcompiler omdat deze zo nauw aansluit bij de ANSI-standaard.
Laten we beginnen
Voordat je iets in welke taal dan ook kunt doen en beginnen met programmeren, moet je weten hoe je een identifier een naam geeft. Een identifier wordt gebruikt voor elke variabele, functie, datadefinitie, enz. In de programmeertaal C is een identifier een combinatie van alfanumerieke tekens, waarbij de eerste een letter van het alfabet of een onderstreping is, en de resterende elke letter van de alfabet, een willekeurig numeriek cijfer of de onderstreping.
Twee regels moeten in gedachten worden gehouden bij het benoemen van identifiers.
- Het geval van alfabetische tekens is significant. C is een hoofdlettergevoelige taal. Dat betekent dat Herstel anders is dan herstel en dat HERSTEL anders is dan beide eerder genoemd.
- Volgens de ANSI-C-standaard kunnen ten minste 31 significante tekens worden gebruikt en worden deze als significant beschouwd door een conforme ANSI-C-compiler. Als er meer dan 31 worden gebruikt, kunnen alle tekens na de 31e door een willekeurige compiler worden genegeerd.
Zoekwoorden
Er zijn 32 woorden gedefinieerd als trefwoorden in C. Deze hebben een vooraf gedefinieerd gebruik en kunnen niet voor andere doeleinden in een C-programma worden gebruikt. Ze worden door de compiler gebruikt als hulpmiddel bij het compileren van het programma. Ze worden altijd in kleine letters geschreven. Een volledige lijst volgt:
auto |
break |
case |
char |
const |
continue |
default |
do |
double |
else |
enum |
extern |
float |
for |
goto |
if |
int |
long |
register |
return |
short |
signed |
sizeof |
static |
struct |
switch |
typedef |
union |
unsigned |
void |
volatile |
while |
Hier zien we de magie van C. De prachtige verzameling van slechts 32 trefwoorden geeft een breed gebruik in verschillende toepassingen. Elk computerprogramma heeft twee entiteiten om te overwegen, de gegevens en het programma. Ze zijn sterk van elkaar afhankelijk en een zorgvuldige planning van beide leidt tot een goed gepland en goed geschreven programma.
Laten we beginnen met een eenvoudig C-programma:
/* Eerste programma om C te leren */
#include <stdio.h>
void main()
{
printf("This is a C program\n"); // printing a message
}
Hoewel het programma heel eenvoudig is, zijn een paar punten het vermelden waard. Laten we het bovenstaande programma eens bekijken. Alles wat in /* en */ staat, wordt als commentaar beschouwd en wordt door de compiler genegeerd. Je moet geen opmerkingen opnemen in andere opmerkingen, dus zoiets als dit is niet toegestaan:
/* dit is een /* opmerking */ in een opmerking, wat niet klopt */
Er is ook een manier van documentatie die binnen een regel werkt. Door // te gebruiken kunnen we kleine documentatie binnen die regel toevoegen.
Elk C-programma bevat een functie genaamd main. Dit is het startpunt van het programma. Elke functie zou een waarde moeten retourneren. In dit programma retourneert de functie main geen retourwaarde, daarom hebben we void main geschreven. We kunnen dit programma ook schrijven als:
/* Eerste programma om C . te leren */
#include <stdio.h>
main()
{
printf("This is a C program\n"); // printing a message
return 0;
}
Beide programma's zijn hetzelfde en voeren dezelfde taak uit. Het resultaat van beide programma's zal de volgende uitvoer op het scherm afdrukken:
Dit is een C-programma
#include<stdio.h> stelt het programma in staat om te communiceren met het scherm, toetsenbord en bestandssysteem van uw computer. Je vindt het aan het begin van bijna elk C-programma.
main() declareert het begin van de functie, terwijl de twee accolades het begin en einde van de functie aangeven. accolades in C worden gebruikt om statements samen te groeperen als in een functie, of in de body van een lus. Zo'n groepering staat bekend als een samengestelde instructie of een blok.
printf("Dit is een C-programma\n"); drukt de woorden op het scherm af. De af te drukken tekst staat tussen dubbele aanhalingstekens. De \n aan het einde van de tekst vertelt het programma om een nieuwe regel af te drukken als onderdeel van de uitvoer. printf() functie wordt gebruikt voor monitorweergave van de uitvoer.
De meeste C-programma's zijn in kleine letters. Meestal vindt u hoofdletters die worden gebruikt in preprocessor-definities die later zullen worden besproken, of tussen aanhalingstekens als onderdelen van tekenreeksen.
Het programma samenstellen
Laat de naam van ons programma CPROG.C zijn. Ga als volgt te werk om het C-programma in te voeren en te compileren:
- Maak de active directory van je C-programma's en start je editor. Hiervoor kan elke teksteditor worden gebruikt, maar de meeste C-compilers zoals Borland's Turbo C++ hebben een geïntegreerde ontwikkelomgeving (IDE) waarmee u uw programma's in één handige instelling kunt invoeren, compileren en koppelen.
- Schrijf en bewaar de broncode. Je zou het bestand CPROG.C moeten noemen.
- Compileer en koppel CPROG.C. Voer de juiste opdracht uit die is gespecificeerd in de handleidingen van uw compiler. Je zou een bericht moeten krijgen waarin staat dat er geen fouten of waarschuwingen waren.
- Controleer de compilerberichten. Als u geen fouten of waarschuwingen ontvangt, zou alles in orde moeten zijn. Als er een fout is bij het typen van het programma, zal de compiler deze opvangen en een foutmelding weergeven. Corrigeer de fout, weergegeven in de foutmelding.
- Je eerste C-programma zou nu moeten zijn gecompileerd en klaar om te worden uitgevoerd. Als u een directorylijst met alle bestanden met de naam CPROG weergeeft, krijgt u de vier bestanden met verschillende extensies die als volgt worden beschreven:
- CPROG.C, het broncodebestand
- CPROG.BAK, het back-upbestand van het bronbestand dat u met de editor hebt gemaakt
- CPROG.OBJ, bevat de objectcode voor CPROG.C
- CPROG.EXE, het uitvoerbare programma dat is gemaakt tijdens het compileren en koppelen van CPROG.C
- Om CPROG.EXE uit te voeren of uit te voeren, voert u gewoon cprog in. Het bericht Dit is een C-programma wordt op het scherm weergegeven.
Laten we nu het volgende programma bekijken:
/* Eerste programma om C te leren */ // 1
// 2
#include <stdio.h> // 3
// 4
main() // 5
{
// 6
printf("This is a C program\n"); // 7
// 8
return 0; // 9
} // 10
Wanneer u dit programma compileert, geeft de compiler een bericht weer dat lijkt op het volgende:
cprog.c(8) : Fout: `;' verwacht
laten we deze foutmelding in delen opsplitsen. cprog.c is de naam van het bestand waarin de fout is gevonden. (8) is regelnummer waar de fout is gevonden. Fout: `;' verwacht is een beschrijving van de fout.
Dit bericht is behoorlijk informatief en vertelt je dat in regel 8 van CPROG.C de compiler verwachtte een puntkomma te vinden, maar dat niet deed. U weet echter dat de puntkomma in regel 7 is weggelaten, dus er is een discrepantie.
Waarom de compiler een fout rapporteert in regel 8 terwijl in feite een puntkomma is weggelaten uit regel 7. Het antwoord ligt in het feit dat C zich niets aantrekt van zaken als pauzes tussen regels. De puntkomma die na de printf()-instructie hoort, had op de volgende regel kunnen worden geplaatst, hoewel dit in de praktijk een slechte programmering zou zijn.
Pas na het tegenkomen van het volgende commando (return) in regel 8 is de compiler er zeker van dat de puntkomma ontbreekt. Daarom meldt de compiler dat de fout in regel 8 staat.
Er kunnen een aantal mogelijkheden zijn voor verschillende soorten fouten. Laten we het hebben over het koppelen van foutmeldingen. Linker-fouten zijn relatief zeldzaam en zijn meestal het gevolg van het verkeerd spellen van de naam van een C-bibliotheekfunctie. In dit geval krijgt u een Error: undefined symbolen: foutmelding, gevolgd door de verkeerd gespelde naam. Zodra u de spelling corrigeert, zou het probleem moeten verdwijnen.
Nummers afdrukken
Laten we het volgende voorbeeld bekijken:
// Hoe de cijfers af te drukken? //
#include<stdio.h>
void main()
{
int num = 10;
printf(“ The Number Is %d”, num);
}
De uitvoer van het programma wordt als volgt op het scherm weergegeven:
Het nummer is 10
Het %-teken wordt gebruikt om de uitvoer van veel verschillende soorten variabelen aan te geven. Het teken na het %-teken is een d, die de uitvoerroutine signaleert om een decimale waarde te krijgen en deze uit te voeren.
Variabelen gebruiken
In C moet een variabele worden gedeclareerd voordat deze kan worden gebruikt. Variabelen kunnen aan het begin van elk codeblok worden gedeclareerd, maar de meeste zijn te vinden aan het begin van elke functie. De meeste lokale variabelen worden gemaakt wanneer de functie wordt aangeroepen en worden vernietigd bij terugkeer van die functie.
Als u variabelen in uw C-programma's wilt gebruiken, moet u de volgende regels kennen wanneer u variabelen in C een naam geeft:
- De naam mag letters, cijfers en het onderstrepingsteken (_) bevatten.
- Het eerste teken van de naam moet een letter zijn. Het onderstrepingsteken is ook een wettelijk eerste teken, maar het gebruik ervan wordt niet aanbevolen.
- C is hoofdlettergevoelig, daarom is de variabele naam num Anders dan Num.
- C-sleutelwoorden kunnen niet worden gebruikt als variabelenamen. Een trefwoord is een woord dat deel uitmaakt van de C-taal.
De volgende lijst bevat enkele voorbeelden van legale en illegale namen van C-variabelen:
Variable Name |
Legal or Not |
Num |
Legal |
Ttpt2_t2p |
Legal |
Tt pt |
Illegal: Space is not allowed |
_1990_tax |
Legal but not advised |
Jack_phone# |
Illegal: Contains the illegal character # |
Case |
Illegal: Is a C keyword |
1book |
Illegal: First character is a digit |
Het eerste nieuwe dat opvalt, is de eerste regel van de hoofdtekst van main():
int num = 10;
Deze regel definieert een variabele met de naam 'num' van het type int en initialiseert deze met de waarde 10. Dit kan ook zijn geschreven als:
int num; /* define uninitialized variable 'num' */
/* and after all variable definitions: */
num = 10; /* assigns value 10 to variable 'num' */
Variabelen kunnen worden gedefinieerd aan het begin van een blok (tussen de accolades {en}), meestal is dit aan het begin van een functietekst, maar het kan ook aan het begin van een ander type blok zijn.
Variabelen die aan het begin van een blok zijn gedefinieerd, krijgen standaard de status 'auto'. Dit betekent dat ze alleen bestaan tijdens de uitvoering van het blok. Wanneer de uitvoering van de functie begint, worden de variabelen gemaakt, maar hun inhoud is niet gedefinieerd. Wanneer de functie terugkeert, worden de variabelen vernietigd. De definitie had ook kunnen worden geschreven als:
auto int num = 10;
Aangezien de definitie met of zonder het auto-trefwoord volledig equivalent is, is het auto-trefwoord natuurlijk nogal overbodig.
Soms is dit echter niet wat u wilt. Stel dat u wilt dat een functie bijhoudt hoe vaak deze wordt aangeroepen. Als de variabele elke keer dat de functie terugkeert zou worden vernietigd, zou dit niet mogelijk zijn.
Daarom is het mogelijk om de variabele een zogenaamde statische duur te geven, wat betekent dat deze gedurende de hele uitvoering van het programma intact blijft. Bijvoorbeeld:
static int num = 10;
Dit initialiseert de variabele num op 10 aan het begin van de uitvoering van het programma. Vanaf dat moment blijft de waarde onaangetast; de variabele wordt niet opnieuw geïnitialiseerd als de functie meerdere keren wordt aangeroepen.
Soms is het niet voldoende dat de variabele alleen toegankelijk is vanuit één functie of is het misschien niet handig om de waarde via een parameter door te geven aan alle andere functies die deze nodig hebben.
Maar als je toegang nodig hebt tot de variabele van alle functies in het hele bronbestand, kan dit ook met het statische sleutelwoord, maar door de definitie buiten alle functies te plaatsen. Bijvoorbeeld:
#include <stdio.h>
static int num = 10; /* will be accessible from entire source file */
int main(void)
{
printf("The Number Is: %d\n", num);
return 0;
}
En er zijn ook gevallen waarin een variabele toegankelijk moet zijn vanuit het hele programma, dat uit meerdere bronbestanden kan bestaan. Dit wordt een globale variabele genoemd en moet worden vermeden als het niet vereist is.
Dit wordt ook gedaan door de definitie buiten alle functies te plaatsen, maar zonder het statische sleutelwoord te gebruiken:
#include <stdio.h>
int num = 10; /* will be accessible from entire program! */
int main(void)
{
printf("The Number Is: %d\n", num);
return 0;
}
Er is ook het externe sleutelwoord, dat wordt gebruikt voor toegang tot globale variabelen in andere modules. Er zijn ook enkele kwalificaties die u aan variabeledefinities kunt toevoegen. De belangrijkste daarvan is const. Een variabele die is gedefinieerd als const mag niet worden gewijzigd.
Er zijn nog twee modifiers die minder vaak worden gebruikt. De vluchtige en registermodifier. De vluchtige modifier vereist dat de compiler daadwerkelijk toegang heeft tot de variabele elke keer dat deze wordt gelezen. Het kan zijn dat het de variabele niet optimaliseert door het in een register of zo te plaatsen. Dit wordt voornamelijk gebruikt voor multithreading en interruptverwerkingsdoeleinden enz.
De registermodifier vraagt de compiler om de variabele in een register te optimaliseren. Dit is alleen mogelijk met auto-variabelen en in veel gevallen kan de compiler beter de variabelen selecteren om te optimaliseren in registers, dus dit sleutelwoord is verouderd. Het enige directe gevolg van het maken van een variabel register is dat het adres niet kan worden ingenomen.
De tabel met variabelen op de volgende pagina beschrijft de opslagklasse van vijf soorten opslagklassen.
In de tabel zien we dat het trefwoord extern in twee rijen is geplaatst. Het sleutelwoord extern wordt in functies gebruikt om een statische externe variabele te declareren die elders is gedefinieerd.
Numerieke variabele typen
C biedt verschillende soorten numerieke variabelen omdat verschillende numerieke waarden verschillende geheugenopslagvereisten hebben. Deze numerieke typen verschillen in het gemak waarmee bepaalde wiskundige bewerkingen erop kunnen worden uitgevoerd.
Kleine gehele getallen hebben minder geheugen nodig om op te slaan, en uw computer kan heel snel wiskundige bewerkingen uitvoeren met dergelijke getallen. Grote gehele getallen en drijvende-kommawaarden vereisen meer opslagruimte en meer tijd voor wiskundige bewerkingen. Door de juiste variabele typen te gebruiken, zorgt u ervoor dat uw programma zo efficiënt mogelijk werkt.
De numerieke variabelen van C vallen in de volgende twee hoofdcategorieën:
- Integer variabelen
- Variabelen met drijvende komma
Binnen elk van deze categorieën zijn twee of meer specifieke typen variabelen. De volgende tabel toont de hoeveelheid geheugen, in bytes, die nodig is om een enkele variabele van elk type te bevatten.
Het type char kan gelijk zijn aan ondertekend char of unsigned char, maar het is altijd een apart type van een van beide.
In C is er geen verschil tussen het opslaan van karakters of hun corresponderende numerieke waarden in een variabele, dus er is ook geen noodzaak voor een functie om te converteren tussen een karakter en zijn numerieke waarde of vice versa. Voor de andere integer-typen, als u ondertekend of niet-ondertekend weglaat, wordt de standaard ondertekend, dus b.v. int en ondertekend int zijn equivalent.
Het type int moet groter dan of gelijk zijn aan het type short en kleiner dan of gelijk aan het type long. Als je gewoon wat waarden wilt opslaan die niet enorm groot zijn, is het vaak een goed idee om het type int; het is meestal de grootte die de processor het gemakkelijkst aankan, en daarom de snelste.
Bij meerdere compilers zijn double en long double equivalent. Dat in combinatie met het feit dat de meeste standaard wiskundige functies werken met type double, is een goede reden om altijd het type double te gebruiken als je met fractionele getallen moet werken.
De volgende tabel is bedoeld om de typen variabelen beter te beschrijven:
Veelgebruikte typen voor speciale doeleinden:
Variable Type |
Description |
size_t |
unsigned type used for storing the sizes of objects in bytes |
time_t |
used to store results of the time() function |
clock_t |
used to store results of the clock() function |
FILE |
used for accessing a stream (usually a file or device) |
ptrdiff_t |
signed type of the difference between 2 pointers |
div_t |
used to store results of the div() function |
ldiv_t |
used to store results of ldiv() function |
fpos_t |
used to hold file position information |
va_list |
used in variable argument handling |
wchar_t |
wide character type (used for extended character sets) |
sig_atomic_t |
used in signal handlers |
Jmp_buf |
used for non-local jumps |
Laten we een voorbeeld nemen om deze variabelen beter te begrijpen:
/* Programma om het bereik en de grootte in bytes van de C-variabele te vertellen */
#include <stdio.h>
int main()
{
int a; /* simple integer type */
long int b; /* long integer type */
short int c; /* short integer type */
unsigned int d; /* unsigned integer type */
char e; /* character type */
float f; /* floating point type */
double g; /* double precision floating point */
a = 1023;
b = 2222;
c = 123;
d = 1234;
e = 'X';
f = 3.14159;
g = 3.1415926535898;
printf( "\nA char is %d bytes", sizeof( char ));
printf( "\nAn int is %d bytes", sizeof( int ));
printf( "\nA short is %d bytes", sizeof( short ));
printf( "\nA long is %d bytes", sizeof( long ));
printf( "\nAn unsigned char is %d bytes",
sizeof( unsigned char ));
printf( "\nAn unsigned int is %d bytes",
sizeof( unsigned int ));
printf( "\nAn unsigned short is %d bytes",
sizeof( unsigned short ));
printf( "\nAn unsigned long is %d bytes",
sizeof( unsigned long ));
printf( "\nA float is %d bytes", sizeof( float ));
printf( "\nA double is %d bytes\n", sizeof( double ));
printf("a = %d\n", a); /* decimal output */
printf("a = %o\n", a); /* octal output */
printf("a = %x\n", a); /* hexadecimal output */
printf("b = %ld\n", b); /* decimal long output */
printf("c = %d\n", c); /* decimal short output */
printf("d = %u\n", d); /* unsigned output */
printf("e = %c\n", e); /* character output */
printf("f = %f\n", f); /* floating output */
printf("g = %f\n", g); /* double float output */
printf("\n");
printf("a = %d\n", a); /* simple int output */
printf("a = %7d\n", a); /* use a field width of 7 */
printf("a = %-7d\n", a); /* left justify in
field of 7 */
c = 5;
d = 8;
printf("a = %*d\n", c, a); /* use a field width of 5*/
printf("a = %*d\n", d, a); /* use a field width of 8 */
printf("\n");
printf("f = %f\n", f); /* simple float output */
printf("f = %12f\n", f); /* use field width of 12 */
printf("f = %12.3f\n", f); /* use 3 decimal places */
printf("f = %12.5f\n", f); /* use 5 decimal places */
printf("f = %-12.5f\n", f); /* left justify in field */
return 0;
}
Het resultaat van het programma na uitvoering wordt weergegeven als:
A char is 1 bytes
An int is 2 bytes
A short is 2 bytes
A long is 4 bytes
An unsigned char is 1 bytes
An unsigned int is 2 bytes
An unsigned short is 2 bytes
An unsigned long is 4 bytes
A float is 4 bytes
A double is 8 bytes
a = 1023
a = 1777
a = 3ff
b = 2222
c = 123
d = 1234
e = X
f = 3.141590
g = 3.141593
a = 1023
a = 1023
a = 1023
a = 1023
a = 1023
f = 3.141590
f = 3.141590
f = 3.142
f = 3.14159
f = 3.14159 |
Voor het gebruik ervan, een variabele in een C-programma, moet deze worden gedeclareerd. Een variabeledeclaratie vertelt de compiler de naam en het type van een variabele en initialiseert de variabele optioneel naar een specifieke waarde.
Als uw programma een variabele probeert te gebruiken die niet is gedeclareerd, genereert de compiler een foutmelding. Een variabele declaratie heeft de volgende vorm:
typename varname;
typename specificeert het type variabele en moet een van de trefwoorden zijn. varname is de variabelenaam. U kunt meerdere variabelen van hetzelfde type op één regel declareren door de variabelenamen met komma's te scheiden:
int count, number, start; /* three integer variables */
float percent, total; /* two float variables */
Het typedef-zoekwoord
Het sleutelwoord typedef wordt gebruikt om een nieuwe naam te maken voor een bestaand gegevenstype. Typedef creëert in feite een synoniem. Bijvoorbeeld de verklaring
typedef int geheel getal;
hier zien we dat typedef integer maakt als synoniem voor int. U kunt dan integer gebruiken om variabelen van het type int te definiëren, zoals in dit voorbeeld:
aantal gehele getallen;
Typedef maakt dus geen nieuw datatype aan, het laat je alleen een andere naam gebruiken voor een vooraf gedefinieerd datatype.
Numerieke variabelen initialiseren
Wanneer een variabele wordt gedeclareerd, krijgt de compiler de opdracht om opslagruimte voor de variabele opzij te zetten. De waarde die in die ruimte is opgeslagen, de waarde van de variabele, is echter niet gedefinieerd. Het kan nul zijn, of het kan een willekeurige "vuilnis" zijn. waarde. Voordat u een variabele gebruikt, moet u deze altijd initialiseren met een bekende waarde. Laten we dit voorbeeld nemen:
int count; /* Set aside storage space for count */
count = 0; /* Store 0 in count */
Deze instructie gebruikt het gelijkteken (=), wat de toewijzingsoperator van C is. U kunt een variabele ook initialiseren wanneer deze is gedeclareerd. Volg hiervoor de variabelenaam in de declaratieverklaring met een gelijkteken en de gewenste beginwaarde:
int count = 0;
double rate = 0.01, complexity = 28.5;
Zorg ervoor dat u geen variabele initialiseert met een waarde buiten het toegestane bereik. Hier zijn twee voorbeelden van initialisaties buiten het bereik:
int amount = 100000;
unsigned int length = -2500;
De C-compiler vangt dergelijke fouten niet op. Uw programma kan compileren en linken, maar u kunt onverwachte resultaten krijgen wanneer het programma wordt uitgevoerd.
Laten we het volgende voorbeeld nemen om het totale aantal sectoren in een schijf te berekenen:
// Modelprogramma om sectoren op een schijf te berekenen //
#include<stdio.h>
#define SECTOR_PER_SIDE 63
#define SIDE_PER_CYLINDER 254
void main()
{
int cylinder=0;
clrscr();
printf("Enter The No. of Cylinders in the Disk \n\n\t");
scanf("%d",&cylinder); // Get the value from the user //
printf("\n\n\t Total Number of Sectors in the disk = %ld", (long)SECTOR_PER_SIDE*SIDE_PER_CYLINDER* cylinder);
getch();
}
De output van het programma is als volgt:
Enter The No. of Cylinders in the Disk
1024
Total Number of Sectors in the disk = 16386048
In dit voorbeeld zien we drie nieuwe dingen om te leren. #define wordt gebruikt om symbolische constanten in het programma te gebruiken of in sommige gevallen om tijd te besparen door lange woorden in kleine symbolen te definiëren.
Hier hebben we het aantal sectoren per zijde gedefinieerd dat 63 is als SECTOR_PER_SIDE om het programma gemakkelijk te begrijpen te maken. Hetzelfde geldt voor #define SIDE_PER_CYLINDER 254. scanf() wordt gebruikt om de invoer van de gebruiker te krijgen.
Hier nemen we het aantal cilinders als invoer van de gebruiker. * wordt gebruikt om twee of meer waarden te vermenigvuldigen, zoals in het voorbeeld.
getch() functie krijgt in feite een enkele tekeninvoer van het toetsenbord. Door getch(); hier stoppen we het scherm totdat een toets van het toetsenbord wordt geraakt.
Operators
Een operator is een symbool dat C instrueert om een bewerking of actie uit te voeren op een of meer operanden. Een operand is iets waar een operator op reageert. In C zijn alle operanden uitdrukkingen. C-operators zijn van de volgende vier categorieën:
- De toewijzingsoperator
- Wiskundige operatoren
- Relationele operatoren
- Logische operatoren
Opdrachtoperator
De toewijzingsoperator is het gelijkteken (=). Het gebruik van het gelijkteken bij het programmeren verschilt van het gebruik in reguliere wiskundige algebraïsche relaties. Als je schrijft
x = y;
In een C-programma betekent dit niet dat "x gelijk is aan y." In plaats daarvan betekent het "wijs de waarde van y toe aan x." In een C-toewijzingsinstructie kan de rechterkant een willekeurige uitdrukking zijn en moet de linkerkant een variabelenaam zijn. De vorm is dus als volgt:
variabele = uitdrukking;
Tijdens de uitvoering wordt expressie geëvalueerd en wordt de resulterende waarde toegewezen aan variabele.
Wiskundige operatoren
De wiskundige operatoren van C voeren wiskundige bewerkingen uit, zoals optellen en aftrekken. C heeft twee unaire wiskundige operatoren en vijf binaire wiskundige operatoren. De unaire wiskundige operatoren worden zo genoemd omdat ze een enkele operand aannemen. C heeft twee unaire wiskundige operatoren.
De operatoren voor verhogen en verlagen kunnen alleen worden gebruikt met variabelen, niet met constanten. De uitgevoerde bewerking is om één op te tellen bij of af te trekken van de operand. Met andere woorden, de uitspraken ++x; en --y; zijn de equivalenten van deze uitspraken:
x = x + 1;
y = y - 1;
binaire wiskundige operatoren nemen twee operanden. De eerste vier binaire operatoren, waaronder de veelvoorkomende wiskundige bewerkingen die u op een rekenmachine vindt (+, -, *, /), zijn u bekend. De vijfde operator Modulus retourneert de rest wanneer de eerste operand wordt gedeeld door de tweede operand. Bijvoorbeeld, 11 modulus 4 is gelijk aan 3 (11 wordt gedeeld door 4, twee keer en 3 over).
Relationele operators
De relationele operatoren van C worden gebruikt om uitdrukkingen te vergelijken. Een expressie die een relationele operator bevat, evalueert ofwel waar (1) of onwaar (0). C heeft zes relationele operatoren.
Logische operators
Met logische operatoren van C kunt u twee of meer relationele expressies combineren in een enkele expressie die evalueert naar waar of onwaar. Logische operatoren evalueren naar waar of onwaar, afhankelijk van de waarde waar of onwaar van hun operanden.
Als x een integer-variabele is, kunnen expressies die logische operatoren gebruiken op de volgende manieren worden geschreven:
(x > 1) && (x < 5)
(x >= 2) && (x <= 4)
Operator |
Symbol |
Description |
Example |
Assignment operators |
equal |
= |
assign the value of y to x |
x = y |
Mathematical operators |
Increment |
++ |
Increments the operand by one |
++x, x++ |
Decrement |
-- |
Decrements the operand by one |
--x, x-- |
Addition |
+ |
Adds two operands |
x + y |
Subtraction |
- |
Subtracts the second operand from the first |
x - y |
Multiplication |
* |
Multiplies two operands |
x * y |
Division |
/ |
Divides the first operand by the second operand |
x / y |
Modulus |
% |
Gives the remainder when the first operand is divided by the second operand |
x % y |
Relational operators |
Equal |
= = |
Equality |
x = = y |
Greater than |
> |
Greater than |
x > y |
Less than |
< |
Less than |
x < y |
Greater than or equal to |
>= |
Greater than or equal to |
x >= y |
Less than or equal to |
<= |
Less than or equal to |
x <= y |
Not equal |
!= |
Not equal to |
x != y |
Logical operators |
AND |
&& |
True (1) only if both exp1 and exp2 are true; false (0) otherwise |
exp1 && exp2 |
OR |
|| |
True (1) if either exp1 or exp2 is true; false (0) only if both are false |
exp1 || exp2 |
NOT |
! |
False (0) if exp1 is true; true (1) if exp1 is false |
!exp1 |
Dingen om te onthouden over logische uitdrukkingen
x * = y |
is same as |
x = x * y |
y - = z + 1 |
is same as |
y = y - z + 1 |
a / = b |
is same as |
a = a / b |
x + = y / 8 |
is same as |
x = x + y / 8 |
y % = 3 |
is same as |
y = y % 3 |
De komma-operator
De komma wordt vaak gebruikt in C als een eenvoudig leesteken, om variabele declaraties, functieargumenten, enz. te scheiden. In bepaalde situaties fungeert de komma als een operator.
U kunt een uitdrukking vormen door twee subuitdrukkingen te scheiden met een komma. Het resultaat is als volgt:
- Beide uitdrukkingen worden geëvalueerd, waarbij de linkeruitdrukking als eerste wordt geëvalueerd.
- De hele expressie evalueert tot de waarde van de juiste expressie.
Bijvoorbeeld, de volgende instructie wijst de waarde van b toe aan x, verhoogt vervolgens a en verhoogt vervolgens b:
x = (a++, b++);
C-operatorprioriteit (Samenvatting van C-operators)
Rank and Associativity |
Operators |
1(left to right) |
() [] -> . |
2(right to left) |
! ~ ++ -- * (indirection) & (address-of) (type)
sizeof + (unary) - (unary) |
3(left to right) |
* (multiplication) / % |
4(left to right) |
+ - |
5(left to right) |
<< >> |
6(left to right) |
< <= > >= |
7(left to right) |
= = != |
8(left to right) |
& (bitwise AND) |
9(left to right) |
^ |
10(left to right) |
| |
11(left to right) |
&& |
12(left to right) |
|| |
13(right to left) |
?: |
14(right to left) |
= += -= *= /= %= &= ^= |= <<= >>= |
15(left to right) |
, |
() is the function operator; [] is the array operator. |
|
Laten we een voorbeeld nemen van het gebruik van operators:
/* Gebruik van operators */
int main()
{
int x = 0, y = 2, z = 1025;
float a = 0.0, b = 3.14159, c = -37.234;
/* incrementing */
x = x + 1; /* This increments x */
x++; /* This increments x */
++x; /* This increments x */
z = y++; /* z = 2, y = 3 */
z = ++y; /* z = 4, y = 4 */
/* decrementing */
y = y - 1; /* This decrements y */
y--; /* This decrements y */
--y; /* This decrements y */
y = 3;
z = y--; /* z = 3, y = 2 */
z = --y; /* z = 1, y = 1 */
/* arithmetic op */
a = a + 12; /* This adds 12 to a */
a += 12; /* This adds 12 more to a */
a *= 3.2; /* This multiplies a by 3.2 */
a -= b; /* This subtracts b from a */
a /= 10.0; /* This divides a by 10.0 */
/* conditional expression */
a = (b >= 3.0 ? 2.0 : 10.5 ); /* This expression */
if (b >= 3.0) /* And this expression */
a = 2.0; /* are identical, both */
else /* will cause the same */
a = 10.5; /* result. */
c = (a > b ? a : b); /* c will have the max of a or b */
c = (a > b ? b : a); /* c will have the min of a or b */
printf("x=%d, y=%d, z= %d\n", x, y, z);
printf("a=%f, b=%f, c= %f", a, b, c);
return 0;
}
en het resultaat van dit programma wordt op het scherm weergegeven als:
x=3, y=1, z=1
a=2.000000, b=3.141590, c=2.000000
Iets meer over printf() en Scanf()
Beschouw de volgende twee printf-statements:
printf(“\t %d\n”, num);
printf(“%5.2f”, fract);
in de eerste printf-opdracht \t vraagt om de tabverplaatsing op het scherm, het argument %d vertelt de compiler dat de waarde van num moet worden afgedrukt als decimaal geheel getal. \n zorgt ervoor dat de nieuwe uitvoer vanaf een nieuwe regel begint.
In de tweede printf-instructie vertelt %5.2f de compiler dat de uitvoer in drijvende komma moet zijn, met in totaal vijf plaatsen en twee plaatsen rechts van de komma. Meer over het backslash-teken is weergegeven in de volgende tabel:
Constant |
Meaning |
‘\a’ |
Audible alert (bell) |
‘\b’ |
Backspace |
‘\f’ |
Form feed |
‘\n’ |
New line |
‘\r’ |
Carriage return |
‘\t’ |
Horizontal tab |
‘\v’ |
Vertical tab |
‘\’’ |
Single quote |
‘\”’ |
Double quote |
‘\?’ |
Question mark |
‘\\’ |
Backslash |
‘\0’ |
Null |
Laten we de volgende scanf-verklaring bekijken:
scanf(“%d”, &num);
De gegevens van het toetsenbord worden ontvangen door de scanf-functie. In het bovenstaande formaat, de & (ampersand) symbool voor elke variabelenaam is een operator die het adres van de variabelenaam specificeert.
Hierdoor stopt de uitvoering en wacht op de waarde van de variabele num die wordt ingetypt. Wanneer de integerwaarde wordt ingevoerd en de return-toets wordt ingedrukt, gaat de computer door naar de volgende instructie. De scanf- en printf-formaatcodes staan vermeld in de volgende tabel:
Code |
Reads... |
%c |
Single character |
%d |
Decimal integer |
%e |
Floating point value |
%f |
Floating point value |
%g |
Floating point value |
%h |
Short integer |
%i |
Decimal, hexadecimal or octal integer |
%o |
Octal integer |
%s |
String |
%u |
Unsigned decimal integer |
%x |
Hexadecimal integer |
Controleverklaringen
Een programma bestaat uit een aantal statements die meestal achter elkaar worden uitgevoerd. Programma's kunnen veel krachtiger zijn als we de volgorde kunnen bepalen waarin instructies worden uitgevoerd.
Verklaringen vallen in drie algemene typen:
- Toewijzing, waarbij waarden, meestal de resultaten van berekeningen, worden opgeslagen in variabelen.
- Invoer / Uitvoer, gegevens worden ingelezen of uitgeprint.
- Controle, het programma neemt een beslissing over wat te doen.
In deze sectie wordt het gebruik van controle-statements in C besproken. We laten zien hoe ze kunnen worden gebruikt om krachtige programma's te schrijven door;
- Herhalen van belangrijke delen van het programma.
- Kiezen tussen optionele secties van een programma.
De if else-verklaring
Dit wordt gebruikt om te beslissen of iets op een speciaal punt moet worden gedaan, of om te kiezen tussen twee manieren van handelen.
De volgende test bepaalt of een student geslaagd is voor een examen met een voldoende van 45
if (result >= 45)
printf("Pass\n");
else
printf("Fail\n");
It is possible to use the if part without the else.
if (temperature < 0)
print("Frozen\n");
Elke versie bestaat uit een test, tussen haakjes na de if. Als de test waar is, wordt aan de volgende uitspraak gehoorzaamd. Als het onwaar is, wordt de verklaring die volgt op de else gehoorzaamd, indien aanwezig. Hierna gaat de rest van het programma gewoon door.
Als we meer dan één statement willen hebben na de if of the else, dan moeten ze gegroepeerd worden tussen accolades. Zo'n groepering wordt een samengestelde instructie of een blok genoemd.
if (result >= 45)
{ printf("Passed\n");
printf("Congratulations\n");
}
else
{ printf("Failed\n");
printf("Better Luck Next Time\n");
}
Soms willen we een meervoudige beslissing nemen op basis van meerdere voorwaarden. De meest algemene manier om dit te doen is door de else if-variant op het if-statement te gebruiken.
Dit werkt door verschillende vergelijkingen te cascaderen. Zodra een van deze een echt resultaat geeft, wordt het volgende statement of blok uitgevoerd en worden er geen vergelijkingen meer uitgevoerd. In het volgende voorbeeld kennen we cijfers toe op basis van het examenresultaat.
if (result <=100 && result >= 75)
printf("Passed: Grade A\n");
else if (result >= 60)
printf("Passed: Grade B\n");
else if (result >= 45)
printf("Passed: Grade C\n");
else
printf("Failed\n");
In dit voorbeeld testen alle vergelijkingen een enkele variabele met de naam resultaat. In andere gevallen kan elke test een andere variabele of een combinatie van tests omvatten. Hetzelfde patroon kan worden gebruikt met meer of minder andere if's, en de finale alleen kan worden weggelaten.
Het is aan de programmeur om voor elk programmeerprobleem de juiste structuur te bedenken. Om het gebruik van if else beter te begrijpen, laten we het voorbeeld zien
#include <stdio.h>
int main()
{
int num;
for(num = 0 ; num < 10 ; num = num + 1)
{
if (num == 2)
printf("num is now equal to %d\n", num);
if (num < 5)
printf("num is now %d, which is less than 5\n", num);
else
printf("num is now %d, which is greater than 4\n", num);
} /* end of for loop */
return 0;
}
Resultaat van het programma
num is now 0, which is less than 5
num is now 1, which is less than 5
num is now equal to 2
num is now 2, which is less than 5
num is now 3, which is less than 5
num is now 4, which is less than 5
num is now 5, which is greater than 4
num is now 6, which is greater than 4
num is now 7, which is greater than 4
num is now 8, which is greater than 4
num is now 9, which is greater than 4
De switchverklaring
Dit is een andere vorm van de meervoudige beslissing. Het is goed gestructureerd, maar kan alleen worden gebruikt in bepaalde gevallen waar;
- Er wordt slechts één variabele getest, alle takken moeten afhankelijk zijn van de waarde van die variabele. De variabele moet een integraal type zijn. (int, lang, kort of char).
- Elke mogelijke waarde van de variabele kan een enkele tak besturen. Een laatste, vang alles, standaard vertakking kan optioneel worden gebruikt om alle niet-gespecificeerde gevallen op te vangen.
Het onderstaande voorbeeld zal dingen verduidelijken. Dit is een functie die een geheel getal omzet in een vage beschrijving. Het is nuttig wanneer we ons alleen bezighouden met het meten van een hoeveelheid als deze vrij klein is.
estimate(number)
int number;
/* Estimate a number as none, one, two, several, many */
{ switch(number) {
case 0 :
printf("None\n");
break;
case 1 :
printf("One\n");
break;
case 2 :
printf("Two\n");
break;
case 3 :
case 4 :
case 5 :
printf("Several\n");
break;
default :
printf("Many\n");
break;
}
}
Elk interessant geval wordt vermeld met een bijbehorende actie. De break-instructie voorkomt dat verdere instructies worden uitgevoerd door de switch te verlaten. Aangezien geval 3 en geval 4 geen volgende pauze hebben, blijven ze dezelfde actie toestaan voor verschillende waarden van het getal.
Zowel if als switch constructies stellen de programmeur in staat een selectie te maken uit een aantal mogelijke acties. Laten we een voorbeeld zien:
#include <stdio.h>
int main()
{
int num;
for (num = 3 ; num < 13 ; num = num + 1)
{
switch (num)
{
case 3 :
printf("The value is three\n");
break;
case 4 :
printf("The value is four\n");
break;
case 5 :
case 6 :
case 7 :
case 8 :
printf("The value is between 5 and 8\n");
break;
case 11 :
printf("The value is eleven\n");
break;
default :
printf("It is one of the undefined values\n");
break;
} /* end of switch */
} /* end of for loop */
return 0;
}
De uitvoer van het programma zal zijn:
The value is three
The value is four
The value is between 5 and 8
The value is between 5 and 8
The value is between 5 and 8
The value is between 5 and 8
It is one of the undefined values
It is one of the undefined values
The value is eleven
It is one of the undefined values
De breukverklaring
We hebben al een break ontmoet in de bespreking van de switch-statement. Het wordt gebruikt om een lus of een schakelaar te verlaten, waarbij de besturing wordt doorgegeven aan de eerste instructie voorbij de lus of een schakelaar.
Met lussen kan pauze worden gebruikt om een vroege exit uit de lus te forceren, of om een lus te implementeren met een test om in het midden van de lus te eindigen. Een onderbreking binnen een lus moet altijd worden beschermd binnen een if-statement dat de test levert om de exit-voorwaarde te controleren.
De continue verklaring
Dit lijkt op breken, maar komt minder vaak voor. Het werkt alleen binnen lussen waar het effect is dat een onmiddellijke sprong naar de luscontrole-instructie wordt geforceerd.
- Spring in een while-lus naar het teststatement.
- Spring in een do while-lus naar het teststatement.
- Spring in een for-lus naar de test en voer de iteratie uit.
Net als een onderbreking, moet continue worden beschermd door een if-statement. Je zult het waarschijnlijk niet vaak gebruiken. Laten we, om het gebruik van pauze en doorgaan beter te begrijpen, het volgende programma eens bekijken:
#include <stdio.h>
int main()
{
int value;
for(value = 5 ; value < 15 ; value = value + 1)
{
if (value == 8)
break;
printf("In the break loop, value is now %d\n", value);
}
for(value = 5 ; value < 15 ; value = value + 1)
{
if (value == 8)
continue;
printf("In the continue loop, value is now %d\n", value);
}
return 0;
}
De uitvoer van het programma is als volgt:
In the break loop, value is now 5
In the break loop, value is now 6
In the break loop, value is now 7
In the continue loop, value is now 5
In the continue loop, value is now 6
In the continue loop, value is now 7
In the continue loop, value is now 9
In the continue loop, value is now 10
In the continue loop, value is now 11
In the continue loop, value is now 12
In the continue loop, value is now 13
In the continue loop, value is now 14
Lussen
Het andere belangrijke type control statement is de lus. Met lussen kan een instructie, of een blok met instructies, worden herhaald. Computers zijn erg goed in het vaak herhalen van eenvoudige taken. De lus is C's manier om dit te bereiken.
C geeft je de keuze uit drie soorten lussen, while, do-while en for.
- De while-lus blijft een actie herhalen totdat een bijbehorende test false retourneert. Dit is handig wanneer de programmeur niet van tevoren weet hoe vaak de lus zal worden doorlopen.
- De do while-lussen zijn vergelijkbaar, maar de test vindt plaats nadat de hoofdtekst van de lus is uitgevoerd. Dit zorgt ervoor dat de loop-body minstens één keer wordt uitgevoerd.
- De for-lus wordt vaak gebruikt, meestal waar de lus een vast aantal keren wordt doorlopen. Het is erg flexibel, en beginnende programmeurs moeten oppassen dat ze de kracht die het biedt niet misbruiken.
De while-lus
De while-lus herhaalt een instructie totdat de test bovenaan niet waar blijkt te zijn. Als voorbeeld is hier een functie om de lengte van een string te retourneren. Onthoud dat de tekenreeks wordt weergegeven als een reeks tekens die wordt afgesloten met een null-teken '\0'.
int string_length(char string[])
{ int i = 0;
while (string[i] != '\0')
i++;
return(i);
}
De string wordt als argument aan de functie doorgegeven. De grootte van de array is niet gespecificeerd, de functie werkt voor een string van elke grootte.
De while-lus wordt gebruikt om de tekens in de tekenreeks één voor één te bekijken totdat het nulteken is gevonden. Vervolgens wordt de lus afgesloten en wordt de index van de null geretourneerd.
Hoewel het teken niet null is, wordt de index verhoogd en wordt de test herhaald. We gaan later dieper in op arrays. Laten we een voorbeeld bekijken voor een while-lus:
#include <stdio.h>
int main()
{
int count;
count = 0;
while (count < 6)
{
printf("The value of count is %d\n", count);
count = count + 1;
}
return 0;
}
en het resultaat wordt als volgt weergegeven:
The value of count is 0
The value of count is 1
The value of count is 2
The value of count is 3
The value of count is 4
The value of count is 5
De doe-terwijl-lus
Dit lijkt erg op de while-lus, behalve dat de test plaatsvindt aan het einde van de body van de lus. Dit garandeert dat de lus minstens één keer wordt uitgevoerd voordat u verder gaat.
Een dergelijke opstelling wordt vaak gebruikt waar gegevens moeten worden gelezen. De test verifieert vervolgens de gegevens en keert terug om opnieuw te lezen als het onaanvaardbaar was.
do
{
printf("Enter 1 for yes, 0 for no :");
scanf("%d", &input_value);
} while (input_value != 1 && input_value != 0)
Laten we het volgende voorbeeld bekijken om de do while-lus beter te begrijpen:
#include <stdio.h>
int main()
{
int i;
i = 0;
do
{
printf("The value of i is now %d\n", i);
i = i + 1;
} while (i < 5);
return 0;
}
Het resultaat van het programma wordt als volgt weergegeven:
The value of i is now 0
The value of i is now 1
The value of i is now 2
The value of i is now 3
The value of i is now 4
De for Loop
De for-lus werkt goed als het aantal iteraties van de lus bekend is voordat de lus wordt ingevoerd. De kop van de lus bestaat uit drie delen, gescheiden door puntkomma's.
- De eerste wordt uitgevoerd voordat de lus wordt ingevoerd. Dit is meestal de initialisatie van de lusvariabele.
- De tweede is een test, de lus wordt verlaten wanneer deze false retourneert.
- De derde is een instructie die moet worden uitgevoerd telkens wanneer de hoofdtekst van de lus is voltooid. Dit is meestal een verhoging van de lusteller.
Het voorbeeld is een functie die het gemiddelde berekent van de getallen die in een array zijn opgeslagen. De functie neemt de array en het aantal elementen als argumenten.
float average(float array[], int count)
{
float total = 0.0;
int i;
for(i = 0; i < count; i++)
total += array[i];
return(total / count);
}
De for-lus zorgt ervoor dat het juiste aantal array-elementen wordt opgeteld voordat het gemiddelde wordt berekend.
De drie instructies aan het begin van een for-lus doen meestal elk maar één ding, maar ze kunnen allemaal leeg worden gelaten. Een lege eerste of laatste instructie betekent dat er geen initialisatie of lopende increment is. Een blanco vergelijkingsverklaring wordt altijd als waar behandeld. Hierdoor loopt de lus voor onbepaalde tijd, tenzij deze op een andere manier wordt onderbroken. Dit kan een return- of een break-statement zijn.
Het is ook mogelijk om meerdere uitspraken in de eerste of derde positie te persen, gescheiden door komma's. Dit maakt een lus mogelijk met meer dan één controlerende variabele. Het onderstaande voorbeeld illustreert de definitie van zo'n lus, met variabelen hi en lo die respectievelijk beginnen bij 100 en 0 en convergeren.
De for-lus geeft een verscheidenheid aan steno die erin kan worden gebruikt. Let op de volgende uitdrukking, in deze uitdrukking bevat de enkele lus twee for-lussen. Hier is hi-- hetzelfde als hi = hi - 1 en lo++ is hetzelfde als lo = lo + 1,
for(hi = 100, lo = 0; hi >= lo; hi--, lo++)
De for-lus is extreem flexibel en maakt het mogelijk om veel soorten programmagedrag eenvoudig en snel te specificeren. Laten we een voorbeeld bekijken van for loop
#include <stdio.h>
int main()
{
int index;
for(index = 0 ; index < 6 ; index = index + 1)
printf("The value of the index is %d\n", index);
return 0;
}
Het resultaat van het programma wordt als volgt weergegeven:
The value of the index is 0
The value of the index is 1
The value of the index is 2
The value of the index is 3
The value of the index is 4
The value of the index is 5
De goto-verklaring
C heeft een goto-statement waarmee ongestructureerde sprongen kunnen worden gemaakt. Om een goto-statement te gebruiken, gebruikt u gewoon het gereserveerde woord goto gevolgd door de symbolische naam waarnaar u wilt springen. De naam wordt dan ergens in het programma geplaatst, gevolgd door een dubbele punt. Je kunt bijna overal binnen een functie springen, maar het is niet toegestaan om in een lus te springen, hoewel je wel uit een lus mag springen.
Dit specifieke programma is echt een puinhoop, maar het is een goed voorbeeld van waarom softwareschrijvers proberen het gebruik van het goto-statement zoveel mogelijk te elimineren. De enige plaats in dit programma waar het redelijk is om de goto te gebruiken, is waar het programma in één sprong uit de drie geneste lussen springt. In dit geval zou het nogal rommelig zijn om een variabele in te stellen en achtereenvolgens uit elk van de drie geneste lussen te springen, maar één goto-instructie haalt u op een zeer beknopte manier uit alle drie.
Sommige mensen zeggen dat de goto-verklaring onder geen enkele omstandigheid mag worden gebruikt, maar dit is bekrompen denken. Als er een plaats is waar een goto duidelijk een netter controlestroom zal uitvoeren dan een andere constructie, voel je dan vrij om het echter te gebruiken, net als in de rest van het programma op je monitor. Laten we het voorbeeld bekijken:
#include <stdio.h>
int main()
{
int dog, cat, pig;
goto real_start;
some_where:
printf("This is another line of the mess.\n");
goto stop_it;
/* the following section is the only section with a useable goto */
real_start:
for(dog = 1 ; dog < 6 ; dog = dog + 1)
{
for(cat = 1 ; cat < 6 ; cat = cat + 1)
{
for(pig = 1 ; pig < 4 ; pig = pig + 1)
{
printf("Dog = %d Cat = %d Pig = %d\n", dog, cat, pig);
if ((dog + cat + pig) > 8 ) goto enough;
}
}
}
enough: printf("Those are enough animals for now.\n");
/* this is the end of the section with a useable goto statement */
printf("\nThis is the first line of the code.\n");
goto there;
where:
printf("This is the third line of the code.\n");
goto some_where;
there:
printf("This is the second line of the code.\n");
goto where;
stop_it:
printf("This is the last line of this mess.\n");
return 0;
}
Laten we de resultaten bekijken
Dog = 1 Cat = 1 Pig = 1
Dog = 1 Cat = 1 Pig = 2
Dog = 1 Cat = 1 Pig = 3
Dog = 1 Cat = 2 Pig = 1
Dog = 1 Cat = 2 Pig = 2
Dog = 1 Cat = 2 Pig = 3
Dog = 1 Cat = 3 Pig = 1
Dog = 1 Cat = 3 Pig = 2
Dog = 1 Cat = 3 Pig = 3
Dog = 1 Cat = 4 Pig = 1
Dog = 1 Cat = 4 Pig = 2
Dog = 1 Cat = 4 Pig = 3
Dog = 1 Cat = 5 Pig = 1
Dog = 1 Cat = 5 Pig = 2
Dog = 1 Cat = 5 Pig = 3
Those are enough animals for now.
This is the first line of the code.
This is the second line of the code.
This is the third line of the code.
This is another line of the mess.
This is the last line of this mess.
Aanwijzingen
Soms willen we weten waar een variabele zich in het geheugen bevindt. Een aanwijzer bevat het adres van een variabele die een specifieke waarde heeft. Bij het declareren van een aanwijzer wordt een asterisk direct voor de aanwijzernaam geplaatst .
Het adres van de geheugenlocatie waar de variabele is opgeslagen, kan worden gevonden door een ampersand voor de variabelenaam te plaatsen.
int num; /* Normal integer variable */
int *numPtr; /* Pointer to an integer variable */
In het volgende voorbeeld worden de variabelewaarde en het adres in het geheugen van die variabele afgedrukt.
printf("The value %d is stored at address %X\n", num, &num);
Om het adres van de variabele num toe te wijzen aan de aanwijzer numPtr, wijst u het adres van de variabele num toe, zoals in het volgende voorbeeld:
numPtr = #
Om erachter te komen wat er is opgeslagen op het adres waarnaar wordt verwezen door numPtr, moet de referentie van de variabele worden verwijderd. Dereferentie wordt bereikt met het sterretje waarmee de aanwijzer is gedeclareerd.
printf("The value %d is stored at address %X\n", *numPtr, numPtr);
Alle variabelen in een programma bevinden zich in het geheugen. De onderstaande instructies vragen de compiler om 4 bytes geheugen op een 32-bits computer te reserveren voor de drijvende-kommavariabele x en vervolgens de waarde 6.5 erin te plaatsen.
float x;
x = 6.5;
Omdat de adreslocatie in het geheugen van een variabele wordt verkregen door de operator & voor de naam dus &x is het adres van x. Met C kunnen we nog een stap verder gaan en een variabele definiëren, een aanwijzer genaamd, die het adres van andere variabelen bevat. We kunnen eerder zeggen dat de aanwijzer naar een andere variabele verwijst. Bijvoorbeeld:
float x;
float* px;
x = 6.5;
px = &x;
definieert px als een aanwijzer naar objecten van het type float, en stelt deze in op het adres van x. Dus *px verwijst naar de waarde van x:
Laten we de volgende uitspraken eens bekijken:
int var_x;
int* ptrX;
var_x = 6;
ptrX = &var_x;
*ptrX = 12;
printf("value of x : %d", var_x);
De eerste regel zorgt ervoor dat de compiler een ruimte in het geheugen reserveert voor een geheel getal. De tweede regel vertelt de compiler om ruimte te reserveren om een pointer op te slaan.
Een aanwijzer is een opslaglocatie voor een adres. De derde regel zou u aan de scanf-instructies moeten herinneren. Het adres "&" operator vertelt de compiler om naar de plaats te gaan waar het var_x heeft opgeslagen en vervolgens het adres van de opslaglocatie aan ptrX te geven.
De asterisk * voor een variabele vertelt de compiler om de verwijzing naar de aanwijzer te verwijderen en naar het geheugen te gaan. Vervolgens kun je toewijzingen maken aan variabelen die op die locatie zijn opgeslagen. U kunt naar een variabele verwijzen en toegang krijgen tot de gegevens via een aanwijzer. Laten we een voorbeeld van pointers bekijken:
/* illustration of pointer use */
#include <stdio.h>
int main()
{
int index, *pt1, *pt2;
index = 39; /* any numerical value */
pt1 = &index; /* the address of index */
pt2 = pt1;
printf("The value is %d %d %d\n", index, *pt1, *pt2);
*pt1 = 13; /* this changes the value of index */
printf("The value is %d %d %d\n", index, *pt1, *pt2);
return 0;
}
De uitvoer van het programma wordt als volgt weergegeven:
The value is 39 39 39
The value is 13 13 13
Laten we nog een voorbeeld bekijken om het gebruik van aanwijzers beter te begrijpen:
#include <stdio.h>
#include <string.h>
int main()
{
char strg[40], *there, one, two;
int *pt, list[100], index;
strcpy(strg, "This is a character string.");
/* the function strcpy() is to copy one string to another. we’ll read about strcpy() function in String Section later */
one = strg[0]; /* one and two are identical */
two = *strg;
printf("The first output is %c %c\n", one, two);
one = strg[8]; /* one and two are identical */
two = *(strg+8);
printf("The second output is %c %c\n", one, two);
there = strg+10; /* strg+10 is identical to &strg[10] */
printf("The third output is %c\n", strg[10]);
printf("The fourth output is %c\n", *there);
for (index = 0 ; index < 100 ; index++)
list[index] = index + 100;
pt = list + 27;
printf("The fifth output is %d\n", list[27]);
printf("The sixth output is %d\n", *pt);
return 0;
}
De uitvoer van het programma ziet er als volgt uit:
The first output is T T
The second output is a a
The third output is c
The fourth output is c
The fifth output is 127
The sixth output is 127
Arrays
Een array is een verzameling variabelen van hetzelfde type. Individuele array-elementen worden geïdentificeerd door een integer-index. In C begint de index bij nul en wordt altijd tussen vierkante haken geschreven.
We hebben al enkeldimensionale arrays ontmoet die als volgt worden gedeclareerd
int resultaten[20];
Arrays kunnen meer dimensies hebben, in welk geval ze kunnen worden gedeclareerd als
int results_2d[20][5];
int results_3d[20][5][3];
Elke index heeft zijn eigen set vierkante haken. Een array wordt gedeclareerd in de hoofdfunctie en bevat meestal details van afmetingen. Het is mogelijk om een ander type, een pointer genaamd, te gebruiken in plaats van een array. Hierdoor staan afmetingen niet direct vast, maar kan de ruimte naar behoefte worden toegewezen. Dit is een geavanceerde techniek die alleen nodig is in bepaalde gespecialiseerde programma's.
Als voorbeeld is hier een eenvoudige functie om alle gehele getallen in een enkeldimensionaal array bij elkaar op te tellen.
int add_array(int array[], int size)
{
int i;
int total = 0;
for(i = 0; i < size; i++)
total += array[i];
return(total);
}
Het programma dat hierna wordt gegeven, zal een string maken, toegang krijgen tot enkele gegevens erin en deze afdrukken. Open het opnieuw met behulp van aanwijzers en druk de tekenreeks vervolgens af. Het zou "Hallo!" moeten afdrukken. en “012345678” op verschillende lijnen. Laten we de codering van het programma eens bekijken:
#include <stdio.h>
#define STR_LENGTH 10
void main()
{
char Str[STR_LENGTH];
char* pStr;
int i;
Str[0] = 'H';
Str[1] = 'i';
Str[2] = '!';
Str[3] = '\0'; // special end string character NULL
printf("The string in Str is : %s\n", Str);
pStr = &Str[0];
for (i = 0; i < STR_LENGTH; i++)
{
*pStr = '0'+i;
pStr++;
}
Str[STR_LENGTH-1] = '\0';
printf("The string in Str is : %s\n", Str);
}
[] (vierkante accolades) worden gebruikt om de array te declareren. De regel van het programma char Str[STR_LENGTH]; declareert een array van tien tekens. Dit zijn tien individuele karakters, die allemaal in het geheugen op dezelfde plek zijn samengebracht. Ze zijn allemaal toegankelijk via onze variabelenaam Str samen met een [n] waarbij n het elementnummer is.
Als we het over array hebben, moet je er altijd rekening mee houden dat wanneer C een array van tien declareert, de elementen waartoe je toegang hebt genummerd zijn van 0 tot 9. Toegang tot het eerste element komt overeen met toegang tot het 0e element. Dus in het geval van arrays, tel altijd van 0 tot grootte van array - 1.
Merk vervolgens op dat we de letters "Hi!" in de array, maar als we een '\0' invoeren, vraagt u zich waarschijnlijk af wat dit is. "\0" staat voor NULL en vertegenwoordigt het einde van een string. Alle tekenreeksen moeten eindigen met dit speciale teken '\0'. Als ze dat niet doen, en dan roept iemand printf op de string, dan zou printf beginnen op de geheugenlocatie van je string, en doorgaan met printen, vertel dat het '\0' tegenkomt en dus eindig je met een hoop rotzooi aan het einde van je snaar. Zorg er dus voor dat je je strings correct beëindigt.
Tekenreeksen
Een tekenreeksconstante , zoals
"Ik ben een string"
is een array van karakters. Het wordt intern in C weergegeven door de ASCII-tekens in de tekenreeks, dwz "I", blanco, "a", "m", ... of de bovenstaande tekenreeks, en beëindigd door het speciale null-teken "\0", zodat programma's zoek het einde van de string.
Stringconstanten worden vaak gebruikt om de uitvoer van code begrijpelijk te maken met printf:
printf("Hello, world\n");
printf("The value of a is: %f\n", a);
Stringconstanten kunnen aan variabelen worden gekoppeld. C biedt de tekentypevariabele, die één teken (1 byte) tegelijk kan bevatten. Een tekenreeks wordt opgeslagen in een array van tekentypes, één ASCII-teken per locatie.
Vergeet nooit dat, aangezien strings conventioneel worden afgesloten met het null-teken "\0", we één extra opslaglocatie in de array nodig hebben.
C biedt geen enkele operator die hele strings tegelijk manipuleert. Strings worden gemanipuleerd via pointers of via speciale routines die beschikbaar zijn in de standaard stringbibliotheek string.h.
Het gebruik van karakteraanwijzers is relatief eenvoudig, aangezien de naam van een array slechts een verwijzing is naar het eerste element. Overweeg het volgende programma:
#include<stdio.h>
void main()
{
char text_1[100], text_2[100], text_3[100];
char *ta, *tb;
int i;
/* set message to be an arrray */
/* of characters; initialize it */
/* to the constant string "..." */
/* let the compiler decide on */
/* its size by using [] */
char message[] = "Hello, I am a string; what are
you?";
printf("Original message: %s\n", message);
/* copy the message to text_1 */
i=0;
while ( (text_1[i] = message[i]) != '\0' )
i++;
printf("Text_1: %s\n", text_1);
/* use explicit pointer arithmetic */
ta=message;
tb=text_2;
while ( ( *tb++ = *ta++ ) != '\0' )
;
printf("Text_2: %s\n", text_2);
}
De uitvoer van het programma is als volgt:
Original message: Hello, I am a string; what are you?
Text_1: Hello, I am a string; what are you?
Text_2: Hello, I am a string; what are you?
De standaard "string"-bibliotheek bevat veel handige functies om strings te manipuleren, die we later in de stringsectie zullen leren.
Toegang tot de elementen
Om toegang te krijgen tot een afzonderlijk element in de array, volgt het indexnummer de naam van de variabele tussen vierkante haken. De variabele kan dan worden behandeld als elke andere variabele in C. In het volgende voorbeeld wordt een waarde toegewezen aan het eerste element in de array.
x[0] = 16;
In het volgende voorbeeld wordt de waarde van het derde element in een array afgedrukt.
printf("%d\n", x[2]);
In het volgende voorbeeld wordt de scanf-functie gebruikt om een waarde van het toetsenbord in te lezen in het laatste element van een array met tien elementen.
scanf("%d", &x[9]);
Array-elementen initialiseren
Arrays kunnen worden geïnitialiseerd zoals alle andere variabelen door toewijzing. Omdat een array meer dan één waarde bevat, worden de afzonderlijke waarden tussen accolades geplaatst en gescheiden door komma's. In het volgende voorbeeld wordt een tiendimensionale array geïnitialiseerd met de eerste tien waarden van de drievoudige tabel.
int x[10] = {3, 6, 9, 12, 15, 18, 21, 24, 27, 30};
Dit bespaart het afzonderlijk toewijzen van de waarden, zoals in het volgende voorbeeld.
int x[10];
x[0] = 3;
x[1] = 6;
x[2] = 9;
x[3] = 12;
x[4] = 15;
x[5] = 18;
x[6] = 21;
x[7] = 24;
x[8] = 27;
x[9] = 30;
Een array doorlopen
Omdat de array sequentieel wordt geïndexeerd, kunnen we de for-lus gebruiken om alle waarden van een array weer te geven. In het volgende voorbeeld worden alle waarden van een array weergegeven:
#include <stdio.h>
int main()
{
int x[10];
int counter;
/* Randomise the random number generator */
srand((unsigned)time(NULL));
/* Assign random values to the variable */
for (counter=0; counter<10; counter++)
x[counter] = rand();
/* Display the contents of the array */
for (counter=0; counter<10; counter++)
printf("element %d has the value %d\n", counter, x[counter]);
return 0;
}
hoewel de uitvoer elke keer de verschillende waarden afdrukt, wordt het resultaat ongeveer als volgt weergegeven:
element 0 has the value 17132
element 1 has the value 24904
element 2 has the value 13466
element 3 has the value 3147
element 4 has the value 22006
element 5 has the value 10397
element 6 has the value 28114
element 7 has the value 19817
element 8 has the value 27430
element 9 has the value 22136
Multidimensionale arrays
Een array kan meer dan één dimensie hebben. Door de array meer dan één dimensie te laten hebben, wordt meer flexibiliteit geboden. Spreadsheets zijn bijvoorbeeld gebouwd op een tweedimensionale array; een array voor de rijen en een array voor de kolommen.
In het volgende voorbeeld wordt een tweedimensionale array gebruikt met twee rijen, die elk vijf kolommen bevatten:
#include <stdio.h>
int main()
{
/* Declare a 2 x 5 multidimensional array */
int x[2][5] = { {1, 2, 3, 4, 5},
{2, 4, 6, 8, 10} };
int row, column;
/* Display the rows */
for (row=0; row<2; row++)
{
/* Display the columns */
for (column=0; column<5; column++)
printf("%d\t", x[row][column]);
putchar('\n');
}
return 0;
}
De uitvoer van dit programma wordt als volgt weergegeven:
1 2 3 4 5
2 4 6 8 10
Snaren
Een string is een groep karakters, meestal letters van het alfabet. Om uw printdisplay zo op te maken dat het er mooi uitziet, betekenisvolle namen en titels heeft en esthetisch aangenaam is voor u en de mensen die de uitvoer van uw programma.
In feite heb je al strings gebruikt in de voorbeelden van de vorige onderwerpen. Maar het is niet de volledige introductie van strijkers. Er zijn veel mogelijke gevallen in de programmering, waarbij het gebruik van geformatteerde strings de programmeur helpt om de te veel complicaties in het programma en te veel bugs natuurlijk te vermijden.
Een volledige definitie van een tekenreeks is een reeks gegevens van het tekentype die worden afgesloten met een null-teken ('\0').
Als C op de een of andere manier een reeks gegevens gaat gebruiken, hetzij om deze te vergelijken met een andere reeks, deze uit te voeren, naar een andere reeks te kopiëren of wat dan ook, zijn de functies ingesteld om te doen waarvoor ze zijn geroepen totdat er een null wordt gedetecteerd.
Er is in plaats daarvan geen basisgegevenstype voor een string in C; strings in C worden geïmplementeerd als een array van karakters. Als u bijvoorbeeld een naam wilt opslaan, kunt u een tekenreeks declareren die groot genoeg is om de naam op te slaan, en vervolgens de juiste bibliotheekfuncties gebruiken om de naam te manipuleren.
In het volgende voorbeeld wordt de tekenreeks op het scherm weergegeven, ingevoerd door de gebruiker:
#include <stdio.h>
int main()
{
char name[80]; /* Create a character array
called name */
printf("Enter your name: ");
gets(name);
printf("The name you entered was %s\n", name);
return 0;
}
De uitvoering van het programma zal zijn:
Enter your name: Tarun Tyagi
The name you entered was Tarun Tyagi
Enkele veelvoorkomende tekenreeksfuncties
De standaard string.h bibliotheek bevat veel handige functies om strings te manipuleren. Enkele van de handigste functies zijn hier als voorbeeld gegeven.
De strlen-functie
De strlen-functie wordt gebruikt om de lengte van een string te bepalen. Laten we het gebruik van strlen leren met een voorbeeld:
#include <stdio.h>
#include <string.h>
int main()
{
char name[80];
int length;
printf("Enter your name: ");
gets(name);
length = strlen(name);
printf("Your name has %d characters\n", length);
return 0;
}
En de uitvoering van het programma zal als volgt zijn:
Enter your name: Tarun Subhash Tyagi
Your name has 19 characters
Enter your name: Preeti Tarun
Your name has 12 characters
De strcpy-functie
De strcpy-functie wordt gebruikt om de ene string naar de andere te kopiëren. Laten we het gebruik van deze functie leren met een voorbeeld:
#include <stdio.h>
#include <string.h>
int main()
{
char first[80];
char second[80];
printf("Enter first string: ");
gets(first);
printf("Enter second string: ");
gets(second);
printf("first: %s, and second: %s Before strcpy()\n "
, first, second);
strcpy(second, first);
printf("first: %s, and second: %s After strcpy()\n",
first, second);
return 0;
}
en de uitvoer van het programma zal zijn als:
Enter first string: Tarun
Enter second string: Tyagi
first: Tarun, and second: Tyagi Before strcpy()
first: Tarun, and second: Tarun After strcpy()
De strcmp-functie
De functie strcmp wordt gebruikt om twee strings met elkaar te vergelijken. De variabelenaam van een array verwijst naar het basisadres van die array. Daarom, als we proberen twee strings te vergelijken met behulp van het volgende, zouden we twee adressen vergelijken, wat natuurlijk nooit hetzelfde zou zijn, aangezien het niet mogelijk is om twee waarden op dezelfde locatie op te slaan.
if (first == second) /* Het is nooit mogelijk om strings te vergelijken */
Het volgende voorbeeld gebruikt de functie strcmp om twee strings te vergelijken:
#include <string.h>
int main()
{
char first[80], second[80];
int t;
for(t=1;t<=2;t++)
{
printf("\nEnter a string: ");
gets(first);
printf("Enter another string: ");
gets(second);
if (strcmp(first, second) == 0)
puts("The two strings are equal");
else
puts("The two strings are not equal");
}
return 0;
}
En de uitvoering van het programma zal als volgt zijn:
Enter a string: Tarun
Enter another string: tarun
The two strings are not equal
Enter a string: Tarun
Enter another string: Tarun
The two strings are equal
De strcat-functie
De strcat-functie wordt gebruikt om de ene string aan de andere te koppelen. Laten we eens kijken hoe? Met behulp van voorbeeld:
#include <string.h>
int main()
{
char first[80], second[80];
printf("Enter a string: ");
gets(first);
printf("Enter another string: ");
gets(second);
strcat(first, second);
printf("The two strings joined together: %s\n",
first);
return 0;
}
En de uitvoering van het programma zal als volgt zijn:
Enter a string: Data
Enter another string: Recovery
The two strings joined together: DataRecovery
De strtok-functie
De strtok-functie wordt gebruikt om het volgende token in een string te vinden. Het token wordt gespecificeerd door een lijst met mogelijke scheidingstekens.
Het volgende voorbeeld leest een regel tekst uit een bestand en bepaalt een woord met behulp van de scheidingstekens, spatie, tab en nieuwe regel. Elk woord wordt dan op een aparte regel weergegeven:
#include <stdio.h>
#include <string.h>
int main()
{
FILE *in;
char line[80];
char *delimiters = " \t\n";
char *token;
if ((in = fopen("C:\\text.txt", "r")) == NULL)
{
puts("Unable to open the input file");
return 0;
}
/* Read each line one at a time */
while(!feof(in))
{
/* Get one line */
fgets(line, 80, in);
if (!feof(in))
{
/* Break the line up into words */
token = strtok(line, delimiters);
while (token != NULL)
{
puts(token);
/* Get the next word */
token = strtok(NULL, delimiters);
}
}
}
fclose(in);
return 0;
}
Het bovenstaande programma, in = fopen("C:\\text.txt", "r"), opent en het bestaande bestand C:\\text.txt. Als de niet bestaat in het opgegeven pad of om welke reden dan ook, kan het bestand niet worden geopend, er wordt een foutmelding op het scherm weergegeven.
Beschouw het volgende voorbeeld, waarin enkele van deze functies worden gebruikt:
#include <stdio.h>
#include <string.h>
void main()
{
char line[100], *sub_text;
/* initialize string */
strcpy(line,"hello, I am a string;");
printf("Line: %s\n", line);
/* add to end of string */
strcat(line," what are you?");
printf("Line: %s\n", line);
/* find length of string */
/* strlen brings back */
/* length as type size_t */
printf("Length of line: %d\n", (int)strlen(line));
/* find occurence of substrings */
if ( (sub_text = strchr ( line, 'W' ) )!= NULL )
printf("String starting with \"W\" ->%s\n",
sub_text);
if ( ( sub_text = strchr ( line, 'w' ) )!= NULL )
printf("String starting with \"w\" ->%s\n",
sub_text);
if ( ( sub_text = strchr ( sub_text, 'u' ) )!= NULL )
printf("String starting with \"w\" ->%s\n",
sub_text);
}
De uitvoer van het programma wordt als volgt weergegeven:
Line: hello, I am a string;
Line: hello, I am a string; what are you?
Length of line: 35
String starting with "w" ->what are you?
String starting with "w" ->u?
Functies
De beste manier om een groot programma te ontwikkelen en te onderhouden, is door het op te bouwen uit kleinere stukken die elk gemakkelijker te beheren zijn (een techniek die soms wordt aangeduid als Verdeel en heers). Functies stellen de programmeur in staat het programma te modulariseren.
Met functies kunnen ingewikkelde programma's worden opgedeeld in kleine blokken, die elk gemakkelijker te schrijven, te lezen en te onderhouden zijn. We zijn de functie main al tegengekomen en hebben gebruik gemaakt van printf uit de standaard bibliotheek. We kunnen natuurlijk onze eigen functies en header-bestanden maken. Een functie heeft de volgende indeling:
return-type function-name ( argument list if necessary )
{
local-declarations;
statements ;
return return-value;
}
Als return-type wordt weggelaten, wordt C standaard ingesteld op int. De retourwaarde moet van het gedeclareerde type zijn. Alle variabelen die binnen functies worden gedeclareerd, worden lokale variabelen genoemd, in die zin dat ze alleen bekend zijn in de functie waarvoor ze zijn gedefinieerd.
Sommige functies hebben een parameterlijst die een communicatiemethode biedt tussen de functie en de module die de functie heeft aangeroepen. De parameters zijn ook lokale variabelen, in die zin dat ze niet beschikbaar zijn buiten de functie. De programma's die tot nu toe zijn behandeld, hebben allemaal main, wat een functie is.
Een functie kan eenvoudig een taak uitvoeren zonder een waarde terug te geven, in welk geval deze de volgende lay-out heeft:
void function-name ( argument list if necessary )
{
local-declarations ;
statements;
}
Argumenten worden altijd doorgegeven door waarde in C-functieaanroepen. Dit betekent dat lokale kopieën van de waarden van de argumenten worden doorgegeven aan de routines. Elke wijziging die in de argumenten intern in de functie wordt aangebracht, wordt alleen aangebracht in de lokale kopieën van de argumenten.
Om een argument in de argumentenlijst te wijzigen of te definiëren, moet dit argument als adres worden doorgegeven. Je gebruikt reguliere variabelen als de functie de waarden van die argumenten niet verandert. Je MOET pointers gebruiken als de functie de waarden van die argumenten verandert.
Laten we leren met voorbeelden:
#include <stdio.h>
void exchange ( int *a, int *b )
{
int temp;
temp = *a;
*a = *b;
*b = temp;
printf(" From function exchange: ");
printf("a = %d, b = %d\n", *a, *b);
}
void main()
{
int a, b;
a = 5;
b = 7;
printf("From main: a = %d, b = %d\n", a, b);
exchange(&a, &b);
printf("Back in main: ");
printf("a = %d, b = %d\n", a, b);
}
En de uitvoer van dit programma wordt als volgt weergegeven:
From main: a = 5, b = 7
From function exchange: a = 7, b = 5
Back in main: a = 7, b = 5
Laten we een ander voorbeeld bekijken. In het volgende voorbeeld wordt een functie met de naam kwadraat gebruikt die het kwadraat van de getallen tussen 1 en 10 schrijft.
#include <stdio.h>
int square(int x); /* Function prototype */
int main()
{
int counter;
for (counter=1; counter<=10; counter++)
printf("Square of %d is %d\n", counter, square(counter));
return 0;
}
/* Define the function 'square' */
int square(int x)
{
return x * x;
}
De uitvoer van dit programma wordt als volgt weergegeven:
Square of 1 is 1
Square of 2 is 4
Square of 3 is 9
Square of 4 is 16
Square of 5 is 25
Square of 6 is 36
Square of 7 is 49
Square of 8 is 64
Square of 9 is 81
Square of 10 is 100
De functie prototype square declareert een functie die een integer parameter nodig heeft en een integer retourneert. Wanneer de compiler de functieaanroep bereikt in het hoofdprogramma, kan hij de functieaanroep vergelijken met de functiedefinitie.
Als het programma de regel bereikt die het functievierkant aanroept, springt het programma naar de functie en voert die functie uit voordat het zijn pad door het hoofdprogramma hervat. Programma's die geen retourtype hebben, moeten worden gedeclareerd met void. Parameters voor de functie kunnen dus Pass By Value of Pass By Reference zijn.
Een recursieve functie is een functie die zichzelf aanroept. En dit proces wordt recursie genoemd.
Pass By Value Functies
De parameters van de vierkante functie in het vorige voorbeeld worden door waarde doorgegeven. Dit betekent dat alleen een kopie van de variabele aan de functie is doorgegeven. Eventuele wijzigingen in de waarde worden niet doorgevoerd in de aanroepende functie.
In het volgende voorbeeld wordt pass-by-value gebruikt en wordt de waarde van de doorgegeven parameter gewijzigd, wat geen effect heeft op de aanroepende functie. De functie count_down is ongeldig verklaard omdat er geen retourtype is.
#include <stdio.h>
void count_down(int x);
int main()
{
int counter;
for (counter=1; counter<=10; counter++)
count_down(counter);
return 0;
}
void count_down(int x)
{
int counter;
for (counter = x; counter > 0; counter--)
{
printf("%d ", x);
x--;
}
putchar('\n');
}
De uitvoer van het programma wordt als volgt weergegeven:
1
2 1
3 2 1
4 3 2 1
5 4 3 2 1
6 5 4 3 2 1
7 6 5 4 3 2 1
8 7 6 5 4 3 2 1
9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
Laten we nog een C Pass By Value-voorbeeld bekijken om het beter te begrijpen. In het volgende voorbeeld wordt een getal tussen 1 en 30.000 dat door de gebruiker is getypt, omgezet in woorden.
#include <stdio.h>
void do_units(int num);
void do_tens(int num);
void do_teens(int num);
int main()
{
int num, residue;
do
{
printf("Enter a number between 1 and 30,000: ");
scanf("%d", &num);
} while (num < 1 || num > 30000);
residue = num;
printf("%d in words = ", num);
do_tens(residue/1000);
if (num >= 1000)
printf("thousand ");
residue %= 1000;
do_units(residue/100);
if (residue >= 100)
{
printf("hundred ");
}
if (num > 100 && num%100 > 0)
printf("and ");
residue %=100;
do_tens(residue);
putchar('\n');
return 0;
}
void do_units(int num)
{
switch(num)
{
case 1:
printf("one ");
break;
case 2:
printf("two ");
break;
case 3:
printf("three ");
break;
case 4:
printf("four ");
break;
case 5:
printf("five ");
break;
case 6:
printf("six ");
break;
case 7:
printf("seven ");
break;
case 8:
printf("eight ");
break;
case 9:
printf("nine ");
}
}
void do_tens(int num)
{
switch(num/10)
{
case 1:
do_teens(num);
break;
case 2:
printf("twenty ");
break;
case 3:
printf("thirty ");
break;
case 4:
printf("forty ");
break;
case 5:
printf("fifty ");
break;
case 6:
printf("sixty ");
break;
case 7:
printf("seventy ");
break;
case 8:
printf("eighty ");
break;
case 9:
printf("ninety ");
}
if (num/10 != 1)
do_units(num%10);
}
void do_teens(int num)
{
switch(num)
{
case 10:
printf("ten ");
break;
case 11:
printf("eleven ");
break;
case 12:
printf("twelve ");
break;
case 13:
printf("thirteen ");
break;
case 14:
printf("fourteen ");
break;
case 15:
printf("fifteen ");
break;
case 16:
printf("sixteen ");
break;
case 17:
printf("seventeen ");
break;
case 18:
printf("eighteen ");
break;
case 19:
printf("nineteen ");
}
}
en de uitvoer van het programma is als volgt:
Enter a number between 1 and 30,000: 12345
12345 in words = twelve thousand three hundred and forty five
Call-by-referentie
Om een functie call-by-reference te maken, in plaats van de variabele zelf door te geven, geeft u het adres van de variabele door. Het adres van de variabele kan worden genomen door de & exploitant. Het volgende roept een swap-functie aan die het adres van variabelen doorgeeft in plaats van de werkelijke waarden.
swap(&x, &y);
Dereferentie
Het probleem dat we nu hebben is dat de functie swap het adres heeft gekregen in plaats van de variabele, dus we moeten de variabelen dereferentie zodat we kijken naar de werkelijke waarden in plaats van de adressen van de variabelen om te wisselen hen.
Dereferentie wordt bereikt in C door gebruik te maken van de aanwijzer (*)-notatie. In eenvoudige bewoordingen betekent dit dat u een * vóór elke variabele plaatst voordat u deze gebruikt, zodat deze verwijst naar de waarde van de variabele in plaats van naar het adres. Het volgende programma illustreert pass-by-reference om twee waarden om te wisselen.
#include <stdio.h>
void swap(int *x, int *y);
int main()
{
int x=6, y=10;
printf("Before the function swap, x = %d and y =
%d\n\n", x, y);
swap(&x, &y);
printf("After the function swap, x = %d and y =
%d\n\n", x, y);
return 0;
}
void swap(int *x, int *y)
{
int temp = *x;
*x = *y;
*y = temp;
}
Laten we de uitvoer van het programma bekijken:
Before the function swap, x = 6 and y = 10
After the function swap, x = 10 and y = 6
Functies kunnen recursief zijn dat een functie zichzelf kan aanroepen. Elke aanroep naar zichzelf vereist dat de huidige status van de functie op de stapel wordt geduwd. Het is belangrijk om dit feit te onthouden, aangezien het gemakkelijk is om een stapeloverloop te creëren, d.w.z. de stapel heeft geen ruimte meer om nog meer gegevens te plaatsen.
In het volgende voorbeeld wordt de faculteit van een getal berekend met behulp van recursie. Een faculteit is een getal vermenigvuldigd met elk ander geheel getal onder zichzelf, tot 1. De faculteit van het getal 6 is bijvoorbeeld:
Faculteit 6 = 6 * 5 * 4 * 3 * 2 * 1
Daarom is de faculteit van 6 720. Uit het bovenstaande voorbeeld blijkt dat faculteit 6 = 6 * faculteit 5. Op dezelfde manier is faculteit 5 = 5 * faculteit 4, enzovoort.
Het volgende is de algemene regel voor het berekenen van faculteitsgetallen.
factorial(n) = n * factorial(n-1)
De bovenstaande regel eindigt wanneer n = 1, aangezien de faculteit van 1 1 is. Laten we proberen het beter te begrijpen met behulp van een voorbeeld:
#include <stdio.h>
long int factorial(int num);
int main()
{
int num;
long int f;
printf("Enter a number: ");
scanf("%d", &num);
f = factorial(num);
printf("factorial of %d is %ld\n", num, f);
return 0;
}
long int factorial(int num)
{
if (num == 1)
return 1;
else
return num * factorial(num-1);
}
Laten we eens kijken naar de uitvoer van de uitvoering van dit programma:
Enter a number: 7
factorial of 7 is 5040
Geheugentoewijzing in C
De C-compiler heeft een geheugentoewijzingsbibliotheek, gedefinieerd in malloc.h. Geheugen wordt gereserveerd met behulp van de malloc-functie en retourneert een aanwijzer naar het adres. Er is één parameter voor nodig, de benodigde geheugengrootte in bytes.
Het volgende voorbeeld wijst ruimte toe aan de tekenreeks, "hallo wereld".
ptr = (char *)malloc(strlen("Hello world") + 1);
De extra byte is vereist om rekening te houden met het tekenreeksbeëindigingsteken '\0'. De (char *) wordt een cast genoemd en dwingt het retourtype om char * te zijn.
Aangezien gegevenstypen verschillende groottes hebben en malloc de ruimte in bytes retourneert, is het om redenen van overdraagbaarheid een goede gewoonte om de operator sizeof te gebruiken bij het specificeren van een toe te wijzen grootte.
Het volgende voorbeeld leest een string in de karakterarraybuffer en wijst vervolgens de exacte hoeveelheid geheugen toe die nodig is en kopieert deze naar een variabele genaamd "ptr".
#include <string.h>
#include <malloc.h>
int main()
{
char *ptr, buffer[80];
printf("Enter a string: ");
gets(buffer);
ptr = (char *)malloc((strlen(buffer) + 1) *
sizeof(char));
strcpy(ptr, buffer);
printf("You entered: %s\n", ptr);
return 0;
}
De uitvoer van het programma is als volgt:
Enter a string: India is the best
You entered: India is the best
Geheugen opnieuw toewijzen
Het is tijdens het programmeren vaak mogelijk dat u geheugen opnieuw wilt toewijzen. Dit wordt gedaan met de realloc-functie. De realloc-functie heeft twee parameters, het basisadres van het geheugen waarvan u de grootte wilt wijzigen en de hoeveelheid ruimte die u wilt reserveren, en retourneert een aanwijzer naar het basisadres.
Stel dat we ruimte hebben gereserveerd voor een aanwijzer met de naam msg en we willen de ruimte opnieuw toewijzen aan de hoeveelheid ruimte die het al in beslag neemt, plus de lengte van een andere string, dan kunnen we het volgende gebruiken.
msg = (char *)realloc(msg, (strlen(msg) + strlen(buffer) + 1)*sizeof(char));
Het volgende programma illustreert het gebruik van malloc, realloc en free. De gebruiker voert een reeks tekenreeksen in die met elkaar zijn verbonden. Het programma stopt met het lezen van strings wanneer een lege string wordt ingevoerd.
#include <string.h>
#include <malloc.h>
int main()
{
char buffer[80], *msg;
int firstTime=0;
do
{
printf("\nEnter a sentence: ");
gets(buffer);
if (!firstTime)
{
msg = (char *)malloc((strlen(buffer) + 1) *
sizeof(char));
strcpy(msg, buffer);
firstTime = 1;
}
else
{
msg = (char *)realloc(msg, (strlen(msg) +
strlen(buffer) + 1) * sizeof(char));
strcat(msg, buffer);
}
puts(msg);
} while(strcmp(buffer, ""));
free(msg);
return 0;
}
De uitvoer van het programma is als volgt:
Enter a sentence: Once upon a time
Once upon a time
Enter a sentence: there was a king
Once upon a timethere was a king
Enter a sentence: the king was
Once upon a timethere was a kingthe king was
Enter a sentence:
Once upon a timethere was a kingthe king was
Geheugen vrijgeven
Als u klaar bent met het geheugen dat is toegewezen, mag u nooit vergeten het geheugen vrij te maken, omdat het bronnen vrijmaakt en de snelheid verbetert. Gebruik de vrije functie om toegewezen geheugen vrij te maken.
free(ptr);
Structuren
Naast de basisgegevenstypen heeft C een structuurmechanisme waarmee u gegevensitems die aan elkaar gerelateerd zijn onder een gemeenschappelijke naam kunt groeperen. Dit wordt gewoonlijk een door de gebruiker gedefinieerd type genoemd.
Het sleutelwoord struct start de structuurdefinitie en een tag geeft de unieke naam aan de structuur. De gegevenstypen en namen van variabelen die aan de structuur zijn toegevoegd, zijn leden van de structuur. Het resultaat is een structuursjabloon die als typespecificatie kan worden gebruikt. Het volgende is een structuur met een tag van de maand.
struct month
{
char name[10];
char abbrev[4];
int days;
};
Een structuurtype wordt meestal dichtbij het begin van een bestand gedefinieerd met behulp van een typedef-instructie. typedef definieert en benoemt een nieuw type, zodat het door het hele programma kan worden gebruikt. typedef komt meestal voor net na de #define en #include statements in een bestand.
Het sleutelwoord typedef kan worden gebruikt om een woord te definiëren om naar de structuur te verwijzen in plaats van het sleutelwoord struct te specificeren met de naam van de structuur. Het is gebruikelijk om de typedef in hoofdletters te noemen. Hier zijn de voorbeelden van structuurdefinitie.
typedef struct {
char name[64];
char course[128];
int age;
int year;
} student;
Dit definieert een nieuw type student variabelen van het type student kunnen als volgt worden gedeclareerd.
student st_rec;
Merk op hoe vergelijkbaar dit is met het declareren van een int of float. De variabelenaam is st_rec, het heeft leden met de naam naam, cursus, leeftijd en jaar. evenzo,
typedef struct element
{
char data;
struct element *next;
} STACKELEMENT;
A variable of the user defined type struct element may now be declared as follows.
STACKELEMENT *stack;
Overweeg de volgende structuur:
struct student
{
char *name;
int grade;
};
Een pointer to struct student kan als volgt worden gedefinieerd.
struct student *hnc;
When accessing a pointer to a structure, the member pointer operator, -> is used instead of the dot operator. To add a grade to a structure,
s.grade = 50;
U kunt als volgt een cijfer aan de structuur toekennen.
s->grade = 50;
Net als bij de basisgegevenstypen, moet u, als u wilt dat de wijzigingen die in een functie zijn aangebracht in doorgegeven parameters, blijvend zijn, de referentie doorgeven (het adres doorgeven). Het mechanisme is precies hetzelfde als de basisgegevenstypen. Geef het adres door en verwijs naar de variabele met behulp van aanwijzernotatie.
Nadat u de structuur hebt gedefinieerd, kunt u er een instantie van declareren en waarden toewijzen aan de leden met behulp van de puntnotatie. Het volgende voorbeeld illustreert het gebruik van de maandstructuur.
#include <stdio.h>
#include <string.h>
struct month
{
char name[10];
char abbreviation[4];
int days;
};
int main()
{
struct month m;
strcpy(m.name, "January");
strcpy(m.abbreviation, "Jan");
m.days = 31;
printf("%s is abbreviated as %s and has %d days\n", m.name, m.abbreviation, m.days);
return 0;
}
De uitvoer van het programma is als volgt:
January is abbreviated as Jan and has 31 days
Met alle ANSI C-compilers kunt u de ene structuur aan de andere toewijzen en een lidgewijze kopie uitvoeren. Als we maandstructuren hadden met de namen m1 en m2, dan zouden we de waarden van m1 tot m2 als volgt kunnen toewijzen:
- Structuur met Pointer-leden.
- Structuur wordt geïnitialiseerd.
- Een structuur doorgeven aan een functie.
- Aanwijzingen en structuren.
Structuren met Pointer-leden in C
Het vasthouden van strings in een array van vaste grootte is inefficiënt geheugengebruik. Een efficiëntere aanpak zou zijn om pointers te gebruiken. Aanwijzers worden in structuren op precies dezelfde manier gebruikt als in normale aanwijzerdefinities. Laten we een voorbeeld zien:
#include <string.h>
#include <malloc.h>
struct month
{
char *name;
char *abbreviation;
int days;
};
int main()
{
struct month m;
m.name = (char *)malloc((strlen("January")+1) *
sizeof(char));
strcpy(m.name, "January");
m.abbreviation = (char *)malloc((strlen("Jan")+1) *
sizeof(char));
strcpy(m.abbreviation, "Jan");
m.days = 31;
printf("%s is abbreviated as %s and has %d days\n",
m.name, m.abbreviation, m.days);
return 0;
}
De uitvoer van het programma is als volgt:
Januari wordt afgekort als Jan en heeft 31 dagen
Structuur-initialisatoren in C
Om een set initiële waarden voor de structuur te geven, kunnen initialisatoren aan de declaratieverklaring worden toegevoegd. Aangezien maanden beginnen bij 1, maar arrays beginnen bij nul in C, is in het volgende voorbeeld een extra element op positie nul gebruikt, junk genaamd.
#include <stdio.h>
#include <string.h>
struct month
{
char *name;
char *abbreviation;
int days;
} month_details[] =
{
"Junk", "Junk", 0,
"January", "Jan", 31,
"February", "Feb", 28,
"March", "Mar", 31,
"April", "Apr", 30,
"May", "May", 31,
"June", "Jun", 30,
"July", "Jul", 31,
"August", "Aug", 31,
"September", "Sep", 30,
"October", "Oct", 31,
"November", "Nov", 30,
"December", "Dec", 31
};
int main()
{
int counter;
for (counter=1; counter<=12; counter++)
printf("%s is abbreviated as %s and has %d days\n",
month_details[counter].name,
month_details[counter].abbreviation,
month_details[counter].days);
return 0;
}
En de uitvoer wordt als volgt weergegeven:
January is abbreviated as Jan and has 31 days
February is abbreviated as Feb and has 28 days
March is abbreviated as Mar and has 31 days
April is abbreviated as Apr and has 30 days
May is abbreviated as May and has 31 days
June is abbreviated as Jun and has 30 days
July is abbreviated as Jul and has 31 days
August is abbreviated as Aug and has 31 days
September is abbreviated as Sep and has 30 days
October is abbreviated as Oct and has 31 days
November is abbreviated as Nov and has 30 days
December is abbreviated as Dec and has 31 days
Structuren doorgeven aan functies in C
Structuren kunnen als parameter aan een functie worden doorgegeven, net als elk van de basisgegevenstypen. In het volgende voorbeeld wordt een structuur met de naam date gebruikt die is doorgegeven aan een isLeapYear-functie om te bepalen of het jaar een schrikkeljaar is.
Normaal gesproken zou u alleen de dagwaarde doorgeven, maar de hele structuur wordt doorgegeven om het doorgeven van structuren aan functies te illustreren.
#include <stdio.h>
#include <string.h>
struct month
{
char *name;
char *abbreviation;
int days;
} month_details[] =
{
"Junk", "Junk", 0,
"January", "Jan", 31,
"February", "Feb", 28,
"March", "Mar", 31,
"April", "Apr", 30,
"May", "May", 31,
"June", "Jun", 30,
"July", "Jul", 31,
"August", "Aug", 31,
"September", "Sep", 30,
"October", "Oct", 31,
"November", "Nov", 30,
"December", "Dec", 31
};
struct date
{
int day;
int month;
int year;
};
int isLeapYear(struct date d);
int main()
{
struct date d;
printf("Enter the date (eg: 11/11/1980): ");
scanf("%d/%d/%d", &d.day, &d.month, &d.year);
printf("The date %d %s %d is ", d.day,
month_details[d.month].name, d.year);
if (isLeapYear(d) == 0)
printf("not ");
puts("a leap year");
return 0;
}
int isLeapYear(struct date d)
{
if ((d.year % 4 == 0 && d.year % 100 != 0) ||
d.year % 400 == 0)
return 1;
return 0;
}
En de uitvoering van het programma zal als volgt zijn:
Enter the date (eg: 11/11/1980): 9/12/1980
The date 9 December 1980 is a leap year
In het volgende voorbeeld wordt dynamisch een reeks structuren toegewezen om namen en cijfers van studenten op te slaan. De cijfers worden vervolgens in oplopende volgorde aan de gebruiker getoond.
#include <string.h>
#include <malloc.h>
struct student
{
char *name;
int grade;
};
void swap(struct student *x, struct student *y);
int main()
{
struct student *group;
char buffer[80];
int spurious;
int inner, outer;
int counter, numStudents;
printf("How many students are there in the group: ");
scanf("%d", &numStudents);
group = (struct student *)malloc(numStudents *
sizeof(struct student));
for (counter=0; counter<numStudents; counter++)
{
spurious = getchar();
printf("Enter the name of the student: ");
gets(buffer);
group[counter].name = (char *)malloc((strlen(buffer)+1) * sizeof(char));
strcpy(group[counter].name, buffer);
printf("Enter grade: ");
scanf("%d", &group[counter].grade);
}
for (outer=0; outer<numStudents; outer++)
for (inner=0; inner<outer; inner++)
if (group[outer].grade <
group[inner].grade)
swap(&group[outer], &group[inner]);
puts("The group in ascending order of grades ...");
for (counter=0; counter<numStudents; counter++)
printf("%s achieved Grade %d \n”,
group[counter].name,
group[counter].grade);
return 0;
}
void swap(struct student *x, struct student *y)
{
struct student temp;
temp.name = (char *)malloc((strlen(x->name)+1) *
sizeof(char));
strcpy(temp.name, x->name);
temp.grade = x->grade;
x->grade = y->grade;
x->name = (char *)malloc((strlen(y->name)+1) *
sizeof(char));
strcpy(x->name, y->name);
y->grade = temp.grade;
y->name = (char *)malloc((strlen(temp.name)+1) *
sizeof(char));
strcpy(y->name, temp.name);
}
De uitvoering van de uitvoer is als volgt:
How many students are there in the group: 4
Enter the name of the student: Anuraaj
Enter grade: 7
Enter the name of the student: Honey
Enter grade: 2
Enter the name of the student: Meetushi
Enter grade: 1
Enter the name of the student: Deepti
Enter grade: 4
The group in ascending order of grades ...
Meetushi achieved Grade 1
Honey achieved Grade 2
Deepti achieved Grade 4
Anuraaj achieved Grade 7
Unie
Met een vakbond kunt u dezelfde gegevens met verschillende typen bekijken, of dezelfde gegevens met verschillende namen gebruiken. Vakbonden zijn vergelijkbaar met structuren. Een vakbond wordt op dezelfde manier verklaard en gebruikt als een structuur.
Een vakbond verschilt van een structuur doordat slechts één van haar leden tegelijk kan worden gebruikt. De reden hiervoor is simpel. Alle leden van een vakbond bezetten hetzelfde geheugengebied. Ze worden op elkaar gelegd.
Verenigingen worden op dezelfde manier gedefinieerd en gedeclareerd als structuren. Het enige verschil in de declaraties is dat het trefwoord union wordt gebruikt in plaats van struct. Om een eenvoudige unie van een char-variabele en een integer-variabele te definiëren, schrijft u het volgende:
union shared {
char c;
int i;
};
Deze unie, gedeeld, kan worden gebruikt om instanties van een unie te maken die een tekenwaarde c of een geheel getal i kunnen bevatten. Dit is een OR-conditie. In tegenstelling tot een structuur die beide waarden zou bevatten, kan de vakbond slechts één waarde tegelijk bevatten.
Een vakbond kan worden geïnitialiseerd op zijn aangifte. Omdat er slechts één lid tegelijk kan worden gebruikt en er slechts één kan worden geïnitialiseerd. Om verwarring te voorkomen, kan alleen het eerste lid van de vakbond worden geïnitialiseerd. De volgende code toont een instantie van de gedeelde unie die wordt gedeclareerd en geïnitialiseerd:
union shared generic_variable = {`@'};
Merk op dat de generieke_variabele unie werd geïnitialiseerd net zoals het eerste lid van een structuur zou worden geïnitialiseerd.
Individuele vakbondsleden kunnen op dezelfde manier worden gebruikt als structuurleden met behulp van de lidoperator (.). Er is echter een belangrijk verschil in toegang tot vakbondsleden.
Er mag maar één vakbondslid tegelijk worden benaderd. Omdat een vakbond zijn leden op elkaar slaat, is het belangrijk om slechts één lid tegelijk te benaderen.
The union Keyword
union tag {
union_member(s);
/* additional statements may go here */
}instance;
Het vakbondssleutelwoord wordt gebruikt voor het declareren van vakbonden. Een vakbond is een verzameling van een of meer variabelen (union_members) die onder één naam zijn gegroepeerd. Bovendien beslaat elk van deze vakbondsleden hetzelfde geheugengebied.
Het trefwoord unie identificeert het begin van een unie-definitie. Het wordt gevolgd door een tag die de naam is die aan de vakbond is gegeven. Na de tag staan de vakbondsleden tussen accolades.
Een instantie, de feitelijke verklaring van een vakbond, kan ook worden gedefinieerd. Als u de structuur definieert zonder de instantie, is het slechts een sjabloon die later in een programma kan worden gebruikt om structuren te declareren. Het volgende is de indeling van een sjabloon:
union tag {
union_member(s);
/* additional statements may go here */
};
Om de sjabloon te gebruiken, zou u het volgende formaat gebruiken:
instantie van union-tag;
Om dit formaat te gebruiken, moet u eerder een unie hebben verklaard met de gegeven tag.
/* Declare a union template called tag */
union tag {
int num;
char alps;
}
/* Use the union template */
union tag mixed_variable;
/* Declare a union and instance together */
union generic_type_tag {
char c;
int i;
float f;
double d;
} generic;
/* Initialize a union. */
union date_tag {
char full_date[9];
struct part_date_tag {
char month[2];
char break_value1;
char day[2];
char break_value2;
char year[2];
} part_date;
}date = {"09/12/80"};
Laten we het beter begrijpen aan de hand van voorbeelden:
#include <stdio.h>
int main()
{
union
{
int value; /* This is the first part of the union */
struct
{
char first; /* These two values are the second part of it */
char second;
} half;
} number;
long index;
for (index = 12 ; index < 300000L ; index += 35231L)
{
number.value = index;
printf("%8x %6x %6x\n", number.value,
number.half.first,
number.half.second);
}
return 0;
}
En de uitvoer van het programma wordt als volgt weergegeven:
c c 0
89ab ffab ff89
134a 4a 13
9ce9 ffe9 ff9c
2688 ff88 26
b027 27 ffb0
39c6 ffc6 39
c365 65 ffc3
4d04 4 4d
Een praktisch gebruik van een vakbond bij gegevensherstel
Laten we nu eens kijken naar een praktisch gebruik van Union is het programmeren van gegevensherstel. Laten we een klein voorbeeld nemen. Het volgende programma is het kleine model van een programma voor het scannen van slechte sectoren voor een diskettestation (a: ), maar het is niet het volledige model van software voor het scannen van slechte sectoren.
Laten we het programma eens bekijken:
#include<dos.h>
#include<conio.h>
int main()
{
int rp, head, track, sector, status;
char *buf;
union REGS in, out;
struct SREGS s;
clrscr();
/* Reset the disk system to initialize to disk */
printf("\n Resetting the disk system....");
for(rp=0;rp<=2;rp++)
{
in.h.ah = 0;
in.h.dl = 0x00;
int86(0x13,&in,&out);
}
printf("\n\n\n Now Testing the Disk for Bad Sectors....");
/* scan for bad sectors */
for(track=0;track<=79;track++)
{
for(head=0;head<=1;head++)
{
for(sector=1;sector<=18;sector++)
{
in.h.ah = 0x04;
in.h.al = 1;
in.h.dl = 0x00;
in.h.ch = track;
in.h.dh = head;
in.h.cl = sector;
in.x.bx = FP_OFF(buf);
s.es = FP_SEG(buf);
int86x(0x13,&in,&out,&s);
if(out.x.cflag)
{
status=out.h.ah;
printf("\n track:%d Head:%d Sector:%d Status ==0x%X",track,head,sector,status);
}
}
}
}
printf("\n\n\nDone");
return 0;
}
Laten we nu eens kijken hoe de uitvoer eruit zal zien als er een slechte sector op de diskette staat:
Het schijfsysteem resetten....
De schijf wordt nu getest op slechte sectoren....
track:0 Head:0 Sector:4 Status ==0xA
track:0 Head:0 Sector:5 Status ==0xA
track:1 Head:0 Sector:4 Status ==0xA
track:1 Head:0 Sector:5 Status ==0xA
track:1 Head:0 Sector:6 Status ==0xA
track:1 Head:0 Sector:7 Status ==0xA
track:1 Head:0 Sector:8 Status ==0xA
track:1 Head:0 Sector:11 Status ==0xA
track:1 Head:0 Sector:12 Status ==0xA
track:1 Head:0 Sector:13 Status ==0xA
track:1 Head:0 Sector:14 Status ==0xA
track:1 Head:0 Sector:15 Status ==0xA
track:1 Head:0 Sector:16 Status ==0xA
track:1 Head:0 Sector:17 Status ==0xA
track:1 Head:0 Sector:18 Status ==0xA
track:1 Head:1 Sector:5 Status ==0xA
track:1 Head:1 Sector:6 Status ==0xA
track:1 Head:1 Sector:7 Status ==0xA
track:1 Head:1 Sector:8 Status ==0xA
track:1 Head:1 Sector:9 Status ==0xA
track:1 Head:1 Sector:10 Status ==0xA
track:1 Head:1 Sector:11 Status ==0xA
track:1 Head:1 Sector:12 Status ==0xA
track:1 Head:1 Sector:13 Status ==0xA
track:1 Head:1 Sector:14 Status ==0xA
track:1 Head:1 Sector:15 Status ==0xA
track:1 Head:1 Sector:16 Status ==0xA
track:1 Head:1 Sector:17 Status ==0xA
track:1 Head:1 Sector:18 Status ==0xA
track:2 Head:0 Sector:4 Status ==0xA
track:2 Head:0 Sector:5 Status ==0xA
track:14 Head:0 Sector:6 Status ==0xA
Done
Het kan een beetje moeilijk zijn om functies en interrupts te begrijpen die in dit programma worden gebruikt om de schijf te controleren op slechte sectoren en het schijfsysteem te resetten enz. maar u hoeft zich geen zorgen te maken, we gaan al deze dingen in het BIOS leren en het programmeren onderbreken secties verderop in de volgende hoofdstukken.
Bestandsverwerking in C
Bestandstoegang in C wordt bereikt door een stream aan een bestand te koppelen. C communiceert met bestanden met behulp van een nieuw gegevenstype dat een bestandsaanwijzer wordt genoemd. Dit type wordt gedefinieerd in stdio.h en geschreven als FILE *. Een bestandsaanwijzer genaamd output_file wordt gedeclareerd in een instructie zoals
FILE *output_file;
De bestandsmodi van de fopen-functie
Uw programma moet een bestand openen voordat het er toegang toe heeft. Dit wordt gedaan met behulp van de fopen-functie, die de vereiste bestandsaanwijzer retourneert. Als het bestand om welke reden dan ook niet kan worden geopend, wordt de waarde NULL geretourneerd. Meestal gebruik je fopen als volgt:
if ((output_file = fopen("output_file", "w")) == NULL)
fprintf(stderr, "Cannot open %s\n",
"output_file");
fopen heeft twee argumenten, beide zijn strings, de eerste is de naam van het bestand dat moet worden geopend, de tweede is een toegangsteken, meestal een van r, a of w enz. Bestanden kunnen in een aantal modi worden geopend, zoals weergegeven in de volgende tabel.
File Modes |
r |
Open a text file for reading. |
w |
Create a text file for writing. If the file exists, it is overwritten. |
a |
Open a text file in append mode. Text is added to the end of the file. |
rb |
Open a binary file for reading. |
wb |
Create a binary file for writing. If the file exists, it is overwritten. |
ab |
Open a binary file in append mode. Data is added to the end of the file. |
r+ |
Open a text file for reading and writing. |
w+ |
Create a text file for reading and writing. If the file exists, it is overwritten. |
a+ |
Open a text file for reading and writing at the end. |
r+b or rb+ |
Open binary file for reading and writing. |
w+b or wb+ |
Create a binary file for reading and writing. If the file exists, it is overwritten. |
a+b or ab+ |
Open a text file for reading and writing at the end. |
De update-modi worden gebruikt met functies voor fseek, fsetpos en terugspoelen. De fopen-functie retourneert een bestandsaanwijzer, of NULL als er een fout optreedt.
Het volgende voorbeeld opent een bestand, tarun.txt in alleen-lezen modus. Het is een goede programmeerpraktijk om te testen of het bestand bestaat.
if ((in = fopen("tarun.txt", "r")) == NULL)
{
puts("Unable to open the file");
return 0;
}
Bestanden sluiten
Bestanden worden gesloten met de fclose-functie. De syntaxis is als volgt:
fclose(in);
Bestanden lezen
De functie feof wordt gebruikt om te testen op het einde van het bestand. De functies fgetc, fscanf en fgets worden gebruikt om gegevens uit het bestand te lezen.
Het volgende voorbeeld geeft de inhoud van een bestand op het scherm weer, waarbij fgetc wordt gebruikt om het bestand letter voor letter te lezen.
#include <stdio.h>
int main()
{
FILE *in;
int key;
if ((in = fopen("tarun.txt", "r")) == NULL)
{
puts("Unable to open the file");
return 0;
}
while (!feof(in))
{
key = fgetc(in);
/* The last character read is the end of file marker so don't print it */
if (!feof(in))
putchar(key);
}
fclose(in);
return 0;
}
De functie fscanf kan worden gebruikt om verschillende gegevenstypen uit het bestand te lezen, zoals in het volgende voorbeeld, op voorwaarde dat de gegevens in het bestand de indeling hebben van de opmaakreeks die wordt gebruikt met fscanf.
fscanf(in, "%d/%d/%d", &day, &month, &year);
De functie fgets wordt gebruikt om een aantal karakters uit een bestand te lezen. stdin is de standaard invoerbestandsstroom en de functie fgets kan worden gebruikt om invoer te regelen.
Schrijven naar bestanden
Gegevens kunnen naar het bestand worden geschreven met fputc en fprintf. In het volgende voorbeeld worden de functies fgetc en fputc gebruikt om een kopie van een tekstbestand te maken.
#include <stdio.h>
int main()
{
FILE *in, *out;
int key;
if ((in = fopen("tarun.txt", "r")) == NULL)
{
puts("Unable to open the file");
return 0;
}
out = fopen("copy.txt", "w");
while (!feof(in))
{
key = fgetc(in);
if (!feof(in))
fputc(key, out);
}
fclose(in);
fclose(out);
return 0;
}
De functie fprintf kan worden gebruikt om geformatteerde gegevens naar een bestand te schrijven.
fprintf(out, "Date: %02d/%02d/%02d\n",
day, month, year);
Commandoregelargumenten met C
De ANSI C-definitie voor het declareren van de functie main( ) is ofwel:
int main() of int main(int argc, char **argv)
In de tweede versie kunnen argumenten worden doorgegeven vanaf de opdrachtregel. De parameter argc is een argumententeller en bevat het aantal parameters dat vanaf de opdrachtregel is doorgegeven. De parameter argv is de argumentvector die een array is van verwijzingen naar strings die de daadwerkelijk doorgegeven parameters vertegenwoordigen.
In het volgende voorbeeld kan een willekeurig aantal argumenten worden doorgegeven vanaf de opdrachtregel en worden ze afgedrukt. argv[0] is het eigenlijke programma. Het programma moet worden uitgevoerd vanaf een opdrachtprompt.
#include <stdio.h>
int main(int argc, char **argv)
{
int counter;
puts("The arguments to the program are:");
for (counter=0; counter<argc; counter++)
puts(argv[counter]);
return 0;
}
If the program name was count.c, it could be called as follows from the command line.
count 3
or
count 7
or
count 192 etc.
Het volgende voorbeeld gebruikt de bestandsverwerkingsroutines om een tekstbestand naar een nieuw bestand te kopiëren. Het opdrachtregelargument kan bijvoorbeeld worden aangeroepen als:
txtcpy one.txt two.txt
#include <stdio.h>
int main(int argc, char **argv)
{
FILE *in, *out;
int key;
if (argc < 3)
{
puts("Usage: txtcpy source destination\n");
puts("The source must be an existing file");
puts("If the destination file exists, it will be
overwritten");
return 0;
}
if ((in = fopen(argv[1], "r")) == NULL)
{
puts("Unable to open the file to be copied");
return 0;
}
if ((out = fopen(argv[2], "w")) == NULL)
{
puts("Unable to open the output file");
return 0;
}
while (!feof(in))
{
key = fgetc(in);
if (!feof(in))
fputc(key, out);
}
fclose(in);
fclose(out);
return 0;
}
Bitsgewijze manipulatoren
Op hardwareniveau worden gegevens weergegeven als binaire getallen. De binaire weergave van het getal 59 is 111011. Bit 0 is het minst significante bit, en in dit geval is bit 5 het meest significante bit.
Elke bitset wordt berekend als 2 tot de macht van de bitset. Met bitsgewijze operators kunt u integervariabelen op bitniveau manipuleren. Het volgende toont de binaire weergave van het getal 59.
binary representation of the number 59 |
bit 5 4 3 2 1 0 |
2 power n 32 16 8 4 2 1 |
set 1 1 1 0 1 1 |
Met drie bits is het mogelijk om de getallen 0 tot 7 weer te geven. De volgende tabel toont de getallen 0 tot 7 in hun binaire vorm.
Binary Digits |
000 |
0 |
001 |
1 |
010 |
2 |
011 |
3 |
100 |
4 |
101 |
5 |
110 |
6 |
111 |
7 |
De volgende tabel bevat de bitsgewijze operatoren die kunnen worden gebruikt om binaire getallen te manipuleren.
Binary Digits |
& |
Bitwise AND |
| |
Bitwise OR |
^ |
Bitwise Exclusive OR |
~ |
Bitwise Complement |
<< |
Bitwise Shift Left |
>> |
Bitwise Shift Right |
Bitwise AND
The bitwise AND is True only if both bits are set. The following example shows the result of a bitwise AND on the numbers 23 and 12.
10111 (23)
01100 (12) AND
____________________
00100 (result = 4) |
U kunt een maskerwaarde gebruiken om te controleren of bepaalde bits zijn ingesteld. Als we wilden controleren of bits 1 en 3 waren ingesteld, konden we het getal maskeren met 10 (de waarde als bits 1 en 3) en het resultaat testen tegen het masker.
#include <stdio.h>
int main()
{
int num, mask = 10;
printf("Enter a number: ");
scanf("%d", &num);
if ((num & mask) == mask)
puts("Bits 1 and 3 are set");
else
puts("Bits 1 and 3 are not set");
return 0;
}
Bitsgewijze OF
De bitsgewijze OR is waar als een van beide bits is ingesteld. Het volgende toont het resultaat van een bitsgewijze OR op de nummers 23 en 12.
10111 (23)
01100 (12) OR
______________________
11111 (result = 31) |
U kunt een masker gebruiken om ervoor te zorgen dat een bit of bits zijn ingesteld. Het volgende voorbeeld zorgt ervoor dat bit 2 is ingesteld.
#include <stdio.h>
int main()
{
int num, mask = 4;
printf("Enter a number: ");
scanf("%d", &num);
num |= mask;
printf("After ensuring bit 2 is set: %d\n", num);
return 0;
}
Exclusief voor Bitwise OF
De bitsgewijze exclusieve OR is waar als een van beide bits is ingesteld, maar niet beide. Het volgende toont het resultaat van een bitsgewijze exclusieve OF op de nummers 23 en 12.
10111 (23)
01100 (12) Exclusive OR (XOR)
_____________________________
11011 (result = 27) |
De Exclusive OK heeft een aantal interessante eigenschappen. Als je exclusief OF een getal op zichzelf bent, stelt het zichzelf in op nul, omdat de nullen nul blijven en de enen niet allebei kunnen worden ingesteld, dus worden ze op nul gezet.
Als gevolg hiervan, als je Exclusief OF een nummer met een ander nummer hebt, en dan Exclusief OF het resultaat met het andere nummer weer, is het resultaat het originele nummer. U kunt dit proberen met de getallen die in het bovenstaande voorbeeld zijn gebruikt.
23 XOR 12 = 27
27 XOR 12 = 23
27 XOR 23 = 12
Deze functie kan worden gebruikt voor codering. Het volgende programma gebruikt een coderingssleutel van 23 om de eigenschap te illustreren op een nummer dat door de gebruiker is ingevoerd.
#include <stdio.h>
int main()
{
int num, key = 23;
printf("Enter a number: ");
scanf("%d", &num);
num ^= key;
printf("Exclusive OR with %d gives %d\n", key, num);
num ^= key;
printf("Exclusive OR with %d gives %d\n", key, num);
return 0;
}
Bitgewijs compliment
Het bitsgewijze compliment is een 'one's compliment'-operator die het bit in- of uitschakelt. Als het 1 is, wordt het ingesteld op 0, als het 0 is, wordt het ingesteld op 1.
#include <stdio.h>
int main()
{
int num = 0xFFFF;
printf("The compliment of %X is %X\n", num, ~num);
return 0;
}
Bitsgewijze verschuiving naar links
De operator Bitwise Shift Left verplaatst het getal naar links. De meest significante bits gaan verloren als het getal naar links beweegt, en de vrijgekomen minst significante bits zijn nul. Het volgende toont de binaire representatie van 43.
0101011 (decimaal 43)
Door de bits naar links te schuiven, verliezen we het meest significante bit (in dit geval een nul) en wordt het getal opgevuld met een nul bij het minst significante bit. Het volgende is het resulterende getal.
1010110 (decimaal 86)
Bitsgewijze verschuiving naar rechts
De Bitwise Shift Right-operator verplaatst het getal naar rechts. Nul wordt geïntroduceerd bij de vrijgekomen meest significante bits en de vrijgekomen minst significante bits gaan verloren. Het volgende toont de binaire weergave van het getal 43.
0101011 (decimaal 43)
Door de bits naar rechts te schuiven, verliezen we de minst significante bit (in dit geval een één), en het getal wordt opgevuld met een nul bij de meest significante bit. Het volgende is het resulterende getal.
0010101 (decimaal 21)
Het volgende programma gebruikt Bitwise Shift Right en Bitwise AND om een getal weer te geven als een 16-bits binair getal. Het nummer wordt achtereenvolgens naar rechts verschoven van 16 naar nul en Bitwise ANDed met 1 om te zien of de bit is ingesteld. Een alternatieve methode zou zijn om opeenvolgende maskers te gebruiken met de Bitwise OR-operator.
#include <stdio.h>
int main()
{
int counter, num;
printf("Enter a number: ");
scanf("%d", &num);
printf("%d is binary: ", num);
for (counter=15; counter>=0; counter--)
printf("%d", (num >> counter) & 1);
putchar('\n');
return 0;
}
Functies voor binair - decimale conversies
De volgende twee functies zijn voor binair naar decimaal en decimaal naar binair conversie. De functie die naast het converteren van een decimaal getal naar een corresponderend binair getal wordt gegeven, ondersteunt maximaal 32 - bits binair getal. U kunt dit of het eerder gegeven programma gebruiken voor conversie volgens uw vereisten.
Functie voor decimaal naar binair conversie:
void Decimal_to_Binary(void)
{
int input =0;
int i;
int count = 0;
int binary [32]; /* 32 Bit, MAXIMUM 32 elements */
printf ("Enter Decimal number to convert into
Binary :");
scanf ("%d", &input);
do
{
i = input%2; /* MOD 2 to get 1 or a 0*/
binary[count] = i; /* Load Elements into the Binary Array */
input = input/2; /* Divide input by 2 to decrement via binary */
count++; /* Count how many elements are needed*/
}while (input > 0);
/* Reverse and output binary digits */
printf ("Binary representation is: ");
do
{
printf ("%d", binary[count - 1]);
count--;
} while (count > 0);
printf ("\n");
}
Functie voor binaire naar decimale conversie:
De volgende functie is om een willekeurig binair getal om te zetten in het bijbehorende decimale getal:
void Binary_to_Decimal(void)
{
char binaryhold[512];
char *binary;
int i=0;
int dec = 0;
int z;
printf ("Please enter the Binary Digits.\n");
printf ("Binary digits are either 0 or 1 Only ");
printf ("Binary Entry : ");
binary = gets(binaryhold);
i=strlen(binary);
for (z=0; z<i; ++z)
{
dec=dec*2+(binary[z]=='1'? 1:0); /* if Binary[z] is
equal to 1,
then 1 else 0 */
}
printf ("\n");
printf ("Decimal value of %s is %d",
binary, dec);
printf ("\n");
}
Debuggen en testen
Syntaxisfouten
Syntaxis verwijst naar de grammatica, structuur en volgorde van de elementen in een statement. Er treedt een syntaxisfout op wanneer we de regels overtreden, zoals het vergeten om een instructie te beëindigen met een puntkomma. Wanneer u het programma compileert, zal de compiler een lijst produceren van eventuele syntaxisfouten die het kan tegenkomen.
Een goede compiler geeft de lijst weer met een beschrijving van de fout en kan een mogelijke oplossing bieden. Het oplossen van de fouten kan ertoe leiden dat er meer fouten worden weergegeven bij het opnieuw compileren. De reden hiervoor is dat de vorige fouten de structuur van het programma veranderden, wat betekent dat verdere fouten werden onderdrukt tijdens de oorspronkelijke compilatie.
Evenzo kan een enkele fout resulteren in meerdere fouten. Probeer een puntkomma aan het einde van de hoofdfunctie van een programma dat correct compileert en draait. Wanneer je het opnieuw compileert, krijg je een enorme lijst met fouten, en toch is het slechts een misplaatste puntkomma.
Naast syntaxisfouten kunnen compilers ook waarschuwingen geven. Een waarschuwing is geen fout, maar kan problemen veroorzaken tijdens de uitvoering van uw programma. Als u bijvoorbeeld een drijvende-kommagetal met dubbele precisie toewijst aan een drijvende-kommagetal met enkele precisie, kan dit leiden tot een verlies aan precisie. Het is geen syntaxisfout, maar kan tot problemen leiden. In dit specifieke voorbeeld kunt u uw intentie tonen door de variabele naar het juiste gegevenstype te casten.
Beschouw het volgende voorbeeld waarin x een drijvende-kommagetal met enkele precisie is en y een drijvende-kommagetal met dubbele precisie is. y wordt tijdens de toewijzing expliciet naar een float gecast, waardoor eventuele compilerwaarschuwingen worden geëlimineerd.
x = (float)y;
Logische fouten
Logische fouten treden op wanneer er een fout in de logica zit. Je zou bijvoorbeeld kunnen testen of een getal kleiner dan 4 en groter dan 8 is. Dat kan nooit waar zijn, maar als het syntactisch correct is, zal het programma succesvol compileren. Beschouw het volgende voorbeeld:
if (x < 4 && x > 8)
puts("Will never happen!");
De syntaxis is correct, dus het programma compileert, maar het puts-statement wordt nooit afgedrukt, aangezien de waarde van x onmogelijk tegelijkertijd kleiner dan vier en groter dan acht kan zijn.
De meeste logische fouten worden ontdekt tijdens de eerste test van het programma. Als het zich niet gedraagt zoals je had verwacht, bekijk je de logische uitspraken nauwkeuriger en corrigeer je ze. Dit geldt alleen voor duidelijke logische fouten. Hoe groter het programma, hoe meer paden er doorheen zullen zijn, hoe moeilijker het wordt om te controleren of het programma zich gedraagt zoals verwacht.
Testen
In het softwareontwikkelingsproces kunnen fouten in elke fase van de ontwikkeling worden geïnjecteerd. Dit komt omdat de verificatiemethoden van eerdere fasen van de ontwikkeling van software handmatig zijn. Vandaar dat de code die tijdens de codeeractiviteit is ontwikkeld, waarschijnlijk enkele vereistenfouten en ontwerpfouten bevat, naast fouten die tijdens de codeeractiviteit zijn geïntroduceerd. Tijdens het testen wordt het te testen programma uitgevoerd met een set testgevallen en wordt de output van het programma voor de testgevallen geëvalueerd om te bepalen of de programmering presteert zoals verwacht.
Testen is dus het proces van het analyseren van een software-item om het verschil tussen bestaande en vereiste voorwaarden (d.w.z. bugs) te detecteren en om de kenmerken van de software-items te evalueren. Testen is dus het proces van het analyseren van een programma met de bedoeling fouten te vinden.
Enkele testprincipes
- Tests kunnen de afwezigheid van defecten niet aantonen, alleen hun aanwezigheid.
- Hoe eerder een fout wordt gemaakt, hoe duurder het is.
- Hoe later een fout wordt ontdekt, hoe duurder het is.
Laten we nu enkele testtechnieken bespreken:
White Box-testen
White box testing is een techniek waarbij alle paden door het programma met elke mogelijke waarde worden getest. Deze aanpak vereist enige kennis van hoe het programma zich zou moeten gedragen. Als uw programma bijvoorbeeld een geheel getal tussen 1 en 50 heeft geaccepteerd, zou een white box-test het programma testen met alle 50 waarden om er zeker van te zijn dat het voor elk correct was, en vervolgens elke andere mogelijke waarde testen die een geheel getal kan hebben en die testen. het gedroeg zich zoals verwacht. Gezien het aantal gegevensitems dat een typisch programma kan hebben, maken de mogelijke permutaties het testen van witte dozen extreem moeilijk voor grote programma's.
White box-testen kunnen worden toegepast op veiligheidskritieke functies van een groot programma, en veel van de rest worden getest met behulp van black-boxtesten, zoals hieronder wordt besproken. Vanwege het aantal permutaties wordt white box-testen meestal uitgevoerd met behulp van een testharnas, waarbij reeksen waarden snel naar het programma worden gevoerd via een speciaal programma, waarbij uitzonderingen op het verwachte gedrag worden geregistreerd. White box-testen worden soms structurele, heldere of open-boxtesten genoemd.
Black Box-testen
Black box-testen zijn vergelijkbaar met white-box-testen, behalve dat in plaats van elke mogelijke waarde te testen, geselecteerde waarden worden getest. Bij dit type test kent de tester de invoer en wat de verwachte resultaten zouden moeten zijn, maar niet noodzakelijkerwijs hoe het programma hiertoe is gekomen. Black box-testen wordt ook wel functioneel testen genoemd.
De testgevallen voor black box-testen worden normaal gesproken bedacht zodra de programmaspecificaties compleet zijn. De testgevallen zijn gebaseerd op equivalentieklassen.
Gelijkwaardigheidsklassen
Voor elke invoer identificeert een equivalentieklasse de geldige en ongeldige statussen. Er zijn over het algemeen drie scenario's om rekening mee te houden bij het definiëren van equivalentieklassen.
Als de invoer een bereik of een specifieke waarde specificeert, is er één geldige status en zijn er twee ongeldige statussen gedefinieerd. Als een getal bijvoorbeeld tussen 1 en 20 moet liggen, de geldige staat tussen 1 en 20, is er een ongeldige staat voor minder dan 1 en een ongeldige staat die groter is dan 20.
Als de invoer een bereik of specifieke waarde uitsluit, zijn er twee geldige statussen en een ongeldige status gedefinieerd. Als een getal bijvoorbeeld niet tussen 1 en 20 mag liggen, zijn de geldige toestanden kleiner dan één en groter dan 20, en de ongeldige toestand tussen 1 en 20.
Als de invoer een Booleaanse waarde specificeert, zijn er slechts twee toestanden, een geldige en een ongeldige.
Grenswaarde-analyse
Grenswaarde-analyse houdt alleen rekening met de waarden op de grens van de ingangen. In het geval van een getal tussen 1 en 20, kunnen de testgevallen bijvoorbeeld 1, 20, 0 en 21 zijn. De gedachte erachter is dat als het programma werkt zoals verwacht met deze waarden, de andere waarden ook werk zoals verwacht.
De volgende tabel geeft een overzicht van de typische grenzen die u mogelijk wilt identificeren.
Testing Ranges |
Input type |
Test Values |
Range |
- x[lower_bound]-1
- x[lower_bound]
- x[upper_bound]
- x[upper_bound]+1
|
Boolean |
|
Een testplan opstellen
Identificeer de equivalentieklassen en identificeer voor elke klasse de grenzen. Nadat u de grenzen voor de klasse hebt geïdentificeerd, schrijft u een lijst met geldige en ongeldige waarden op de grens en wat het verwachte gedrag zou moeten zijn. De tester kan dan het programma draaien met de grenswaarden, en aangeven wat er gebeurde toen de grenswaarde werd getoetst aan de gewenste uitkomst.
Het volgende kan een typisch testplan zijn dat wordt gebruikt om te controleren of een leeftijd wordt ingevoerd waarbij de acceptabele waarden in het bereik van 10 tot 110 liggen.
Equivalence Class |
Valid |
Invalid |
Between 10 and 110 |
> 110 |
|
< 10 |
Nadat we onze equivalentieklasse hebben gedefinieerd, kunnen we nu een testplan opstellen voor leeftijd.
Test Plan |
Value |
State |
Expected Result |
Actual Result |
10 |
Valid |
Continue execution to get name |
|
110 |
Valid |
Continue execution to get name |
|
9 |
Invalid |
Ask for age again |
|
111 |
Invalid |
Ask for age again |
|
Het "werkelijke resultaat" kolom is leeg gelaten, omdat deze wordt ingevuld tijdens het testen. Als het resultaat is zoals verwacht, wordt de kolom aangevinkt. Zo niet, dan moet een opmerking worden ingevoerd die aangeeft wat er is gebeurd.
Pagina aangepast op: 07/01/2022