Hein Pragt Heinpragt.com    © Hein Pragt ( Facebook ,  )
Taalfoutje melden 
Volg site op Facebook 
 

De programmeertaal 'C' en 'C++'

© 2010-2015 Hein Pragt

programmeertaal c Deze pagina gaat over mijn oude liefde, de programmeertaal C. Ik leerde de taal C kennen in 1986 door het werk wat is toen deed. Ik was programmeur van embedded software en schreef hoofdzakelijk in Z80 assembler code maar langzaam ging dit steeds meer richting C. De taal C is ook maar één stap hoger dat assembler dus het was ook een logische stap. Naderhand ben ik ook PC applicaties gaan schrijven in C en er was zelfs een tijd dat ik de compiler als rekenmachine gebruikte. Na het lezen van de C bijbel, het bekende witte boekje van Kernighan en Ritchie was ik een totale fan van de programmeertaal C. Samen met de collega's probeerden we steeds meer geavanceerde dingen te doen en werd het schrijven van code in C een soort van kunst. We probeerden steeds beter te worden en steeds mooiere en meer efficiënte code te schrijven. Uiteindelijk heb ik een compleet datacommunicatie pakket "mightycom" in C geschreven met vele terminal emulaties, allerlei download protocollen, data compressie layers als MNP en zelfs een eigen script interpreter en TCP/IP stack.

We leverden onze eigen tekstverwerker, onze eigen installers en collega's schreven zelfs in C en compleet eigen besturingsysteem. Voor Sony hebben we een compleet office pakket geschreven voor de MSX ook geheel in de taal C. Ook schreef ik complete command interpreters, protocol stacks zoals mnp, v42bis en adpcm compressie software voor de roms van modems die we ontwikkelden en zelfs een complete tiny basic interpreter. In de jaren daarna heb ik in C (inmiddels ook C++) geprogrammeerd op Digital VMS machines, op Unix systemen, op Sun solaris systemen en op IBM Pc's onder Microsoft Windows. Het hoogtepunt van mijn C++ tijd was dat ik een half jaar moest meeprogrammeren met het ontwikkelteam van Psion in Londen, waar ik de GSM protocol stacks gemaakt heb voor Epoc32, het latere symbian besturing systeem dat geheel in C++ geschreven is. Naast de taal C heb ik in bijna elke andere taal geprogrammeerd, maar de taal C en "C++" zijn nog steeds mijn grote (oude) liefde. Meer over C++ kunt u vinden op mijn C++ pagina.

In mijn vrije tijd schreef ik grafische demo's en spelletjes en ik heb zelf een tijd 3D programma's geprogrammeerd, wanneer het op snelheid en efficiënte code aankomt, is er nog geen enkele andere programmeertaal die de taal C kan verslaan. Toen de taal Java opkwam zag ik, en veel van mijn collega's, deze taal als C min min of C++ for dummies. Dat de taal Java een dergelijk grote invloed zou krijgen hadden we nooit gedacht maar inmiddels heb ik ook regelmatig code in Java geschreven, (ook voor Android) maar nooit van harte. Binnen de sector van besturingsystemen, compilers, systeemsoftware en vooral de game industrie is de taal C en "C++" niet weg te denken em is het nog steeds de meest gebruikte programmeertaal. Als het om snelheid en compacte code aankomt, kan er nog steeds geen enkele taal tippen aan de taal C. De beste 3D engines zijn dan ook allemaal in C of "C++" geschreven. Linux en Unix en zelfs Windows zijn voor het grootste gedeelte in C en "C++" geschreven. Soms noem ik de taal c wel eens de moeder van alle andere programmeertalen omdat de meeste compilers en tools voor andere programmeertalen en bijna altijd de runtime bibliotheken in de taal C geschreven zijn.

Ik geef ruiterlijk toe dat de taal niet eenvoudig is, erg cryptisch kan zijn, zeer veel vrijheden aan de programmeur geeft en (bijna) geen enkele runtime controle kent. De taal is zo krachtig dat u alles maar dan ook alles fout kunt doen, het vergt een goede kennis, netheid en discipline van de programmeur. Als resultaat van deze inspanning krijgt u de meest snelle en compacte code die mogelijk is. Ook geef ik toe dat een goed geschreven stuk broncode in de taal C soms net een kunstwerk is, maar dat is juist ook de enorme charme van deze taal. Wanneer ik de taal C vergelijk met muziek dan is het te vergelijken met Jazz, ook dit is een kunst op zich. Nog een goed vergelijk van de programmeertaal C is met een raceauto, het is compact gemaakt voor snelheid zonder toeters en bellen en niet voor comfort. Java is in dit vergelijk een degelijke gezinsauto met veiligheid voorop, ook niet slecht maar met een ander doel. Ik schrijf nog steeds in te taal C, mijn programma PragtFotoManager is in C en in Win32 geschreven wat resulteert in een zeer compact programma (230kb) dat supersnel is en erg veel functionaliteit kent. Het grappige is dat ik de programmeertaal C overal weer tegenkomt zoals in de programmeer omgeving voor de bekende Arduino minicomputer bordjes. Deze pagina gaat over mijn oude maar ook levenslange liefde voor de programmeertaal C, veel plezier met lezen en ik hoop ook u nog een beetje enthousiast te krijgen voor deze prachtige programmeertaal. Vriendelijke groet, Hein Pragt

Historie van de programmeertaal C

© 2011 Hein Pragt

In 1978 ontwikkelden Brian W. Kernighan en Dennis M. Ritchie de programmeertaal C waarvan de wortels liggen in de 'B Computer Programming Language' (bcpl), een taal die in 1969 ontwikkeld werd. De C taal evolueerde uit bcpl via een verbeterde versie, die B genoemd werd. Al deze talen hebben de eigenschappen van een hogere programmeertaal: meerdere statements kunnen in blokken gegroepeerd worden, onder andere zijn er constructies voor conditionele uitvoering (if) en constructies voor herhaalde uitvoering (while). Bovendien kennen al deze talen het begrip pointer, staan het rekenen met pointers toe ('pointer arithmetic') en kennen het samenstellen van grote eenheden uit kleinere datatypen zoals structs, unions en arrays. Bij het ontwikkelen van de programmeertaal C hadden Kernighan en Ritchie een aantal duidelijke doelstellingen, in de eerste plaats moest C een snelle taal worden, geschikt voor een breed scala van toepassingen en zeker voor het schrijven van een besturingssysteem. De taal C is een zeer 'low level taal' en het is maar één stap hoger dan assembler en leent zich dus uitstekend voor programma's die zeer dicht bij de architectuur ('hardware') van de computer liggen zoals besturingssystemen en drivers.

In het unix besturingssysteem heeft C assembler zelfs bijna geheel verdreven, alleen een stukje van de kernel (bij het laden van het besturingssysteem zelf, de 'bootstrapping') is in assembler geschreven. Een tweede belangrijke overweging bij de opzet van de programmeertaal C is de splitsing van de C compiler en de C functiebibliotheek. De C compiler kan niets anders dan het omzetten van een brontekst naar machine instructies alle functies van de taal zijn opgenomen in een standaard C functiebibliotheek. Zo bevatten de meeste functiebibliotheken een aantal low level input/output functies, die dichtbij het besturingssysteem van de computer staan. Deze low level functies worden in een tussenlaag gebruikt door een 'high level' functie als printf() om bijvoorbeeld uitvoer te formatteren. De eerste versie van C, door B.W. Kernighan en D.M. Ritchie uit 1978 staat bekend als de standaard-C. Sinds deze versie is C zeer populair geworden, en al snel verschenen er verschillende C dialecten. In 1983 besloot het 'American National Standards Institute' (ansi) een commissie in te stellen die de C taal eenduidig en machine-onafhankelijk zou bepalen en het resultaat hiervan was de ANSI-C standaard. Tegenwoordig gebruikt men de programmeertaal C nog steeds voor het schrijven van computerspellen en programma's waar snelheid erg belangrijk is.


boek boek bestellen C Programming Language - Dit is HET boek over de programmeertaal c. This book is meant to help the reader learn how to program in C. It is the definitive reference guide, now in a second edition. Although the first edition was written in 1978, it continues to be a worldwide best-seller. This second edition brings the classic original up to date to include the ANSI standard. From the Preface: We have tried to retain the brevity of the first edition. C is not a big language, and it is not well served by a big book. We have improved the exposition of critical features, such as pointers, that are central to C programming. We have refined the original examples, and have added new examples in several chapters. For instance, the treatment of complicated declarations is augmented by programs that convert declarations into words and vice versa. As before, all examples have been tested directly from the text, which is in machine-readable form. As we said in the first preface to the first edition, C wears well as one's experience with it grows. With a decade more experience, we still feel that way. We hope that this book will help you to learn C and use it well.


Online beginners cursus voor de programmeertaal C

© 2015 Hein Pragt

Gewoon beginnen!

Als kennismaking met de programmeertaaltaal C wil ik beginnen met enkele heel eenvoudige programma's die de basis van elk C laten zien.

Eerste voorbeeld:

/* Mijn eerste C programma */

#include 

void main() 
{
  printf("Hallo wereld!\n");  // Druk het af
}

Na het compileren en uitvoeren van dit programma staat, als alles goed is gegaan, de tekst Hallo wereld! op het scherm. Ik zal nu dit programma regel voor regel uitleggen, het programma begint met een commentaarregel en het is een goede gewoonte om elk stuk broncode met een of meerder commentaarregels te beginnen. Commentaar is tekst die door de compiler genegeerd zal worden en alleen een extra aanwijzing of geheugensteuntje voor de programmeur is. Commentaar begin met de tekencombinatie /* en eindigt met de tekencombinatie */ waarbij deze begin en einde markeringen op dezelfde regel mogen staan maar ook over meerdere regels mogen lopen.

De regel #include <stdio.h> geeft aan dat een ander bestand in dit programmabestand tussengevoegd moet worden op deze plaats. In C maakt met vaak gebruik van zogenaamde include bestanden met het achtervoegsel .h waarin alle constanten en declaraties van functies van een ander stuk C broncode staan of de declaraties van een standaard bibliotheek. In dit geval gaat het om de bibliotheek stdio.h die definities bevat voor de standaard invoer en uitvoer (toetsenbord en scherm). Hier staat ondermeer de definitie van de functie printf() in die we zo gaan gebruiken. Op de volgende regel staat de functie main() uitgeschreven, dit is altijd de eerste functie die het gecompileerde programma zal uitvoeren. Een functie is te herkennen aan de 2 ronde haken achter de naam waar tussen we de parameters voor de functie kunnen plaatsen. In dit geval zijn het dus lege ronde haken omdat onze functie geen parameters heeft. Daarna zien we een open accolade teken {, dit is in de programmeertaal C de start van een blok programmeerinstructies die bij elkaar horen (een samengestelde opdracht) en dit blok zal afgesloten worden door een accolade sluiten }.

Daarna staat de standaard bibliotheek functie printf() waarmee we bijna alles kunnen afdrukken. Ook hier zien we de ronde haken weer en nu staat hier de parameter voor de functie tussen. In dit geval is het een eenvoudige tekst reeks (string) waarbij het backslash \ teken een bijzondere betekenis heeft. De tekencombinatie \n zal een "newline" teken (volgende regel teken) in de tekenreeks opnemen. Er zijn vele variaties met het backslash teken die voor andere zogenaamde "control characters" staan zoals de \r "cariage return" en \t voor het "tab"teken. Ieder zogenaamd statement in C moet verplicht afgesloten worden met een puntkomma. Aan het einde van de regel ziet u de tweede vorm van commentaar in C door middel van de tekencombinatie // waarbij de compiler alles tot het einde van de regel zal negeren en daarna staat de sluit accolade van de functie main(). Wanneer u dit voorbeeld begrijpt kent u de elementaire basis van de programmeertaal C.

Het gebruik van blanco regels, spaties, tabs en inspringen is in de programmeertaal C totaal vrijgelaten, u mag uw code zo schrijven als u het zelf wilt, het is wel handig om u een beetje aan de stijl te houden die de meeste programmeurs gebruiken (dit leert u vanzelf door veel naar code van anderen te kijken) maar er zijn ook onder C programmeurs enkel hardnekkige verschillen, bijvoorbeeld in het plaatsen van de accolades en het inspringen. Als extreem voorbeeld kan het vorige stukje programma ook op de volgende wijze geschreven worden met precies hetzelfde resultaat.

/* Mijn eerste C programma */#include void main(){printf("Hallo wereld!\n");}

of

/* Mijn eerste C programma */

#include 

void main() {
  printf("Hallo 
  wereld!\n");  // Druk het af
}

of

// Mijn eerste C programma 

#include 

void main() 
{

printf("Hallo ");

     printf("wereld!");     printf("\n");  // Druk het af
}

Zoals u hier ziet kunt u in C heel eenvoudig bijna onleesbare programmacode schrijven, dit is in mijn ogen echt slecht gedrag, broncode is niet bedoeld voor een computer maar voor een mens. U komt uzelf vanzelf tegen wanneer u een hardnekkige fout moet zoeken in slordig geprogrameerd stuk broncode.

Variabelen

Voor het (tijdelijk) opslaan van gegevens in een computerprogramma hebben we in bijna elke programmeertaal de beschikking over zogenaamde variabelen. Een variabele is eigenlijk niets anders dan de naam van een hokje in het geheugen van de computer waar we iets in kunnen opslaan en weer terug kunnen lezen. Dit kan een getal zijn, maar ook een reeks tekens (string) en zelfs een aanwijzer (pointer) die weer naar een andere geheugenplaats kan wijzen. De programmeertaal C is een zogenaamde typed taal waarbij we dus bij het declareren (bekendmaken) van een variabel ook aan moeten geven wel soort data we er in willen stoppen en hoeveel, bijvoorbeeld hoeveel tekens in het geval van een string. In C kennen we een aantal basis datatype die aangeven wat we er in kunnen opslaan, dit zijn: char, int, float, double en void. Het type char wordt gebruikt voor het bewaren van ASCII tekens, het integer type int wordt gebruikt voor het opslaan van gehele getallen (met een beperkte waarde) en de typen float en double kan men gebruiken voor reële getallen. De variabele void geeft de waarde NIETS aan en kan dus ook geen andere waarde bevatten. Daarnaast ken de taal C zogenaamde type modifiers waarmee het basis datatype veranderd kan worden. De programmeertaal C beschikt over vier modifiers : signed, unsigned, long en short. Een int of char zijn standaard signed en long en short geven aan hoeveel bits (en dus de minimale en maximale waarde van de variabele) we willen gebruiken.

Voorbeeld van mogelijke combinaties van datatypen en modifiers:

Typeaantal bitsgetalswaarde
char 8 -128 t/m 127
unsigned char 8 0 t/m 255
int 16 -32768 t/m 32767
unsigned int 16 0 t/m 65535
long 32 -2147483648 t/m 2147483647
float 32 3.4E-38 t/m 3.4E+38
double 64 1.7E-308 t/m 1.7E+308

*) Deze waarden zijn wat er volgens de standaard minimaal in moet kunnen passen, op veel 32 bit systemen zal een int 32 bits zijn en dus gelijk zijn aan een long.

Om het nog meer verwarrend te maken kennen verschillende C compilers ook nog hun eigen datatypes, en zijn er in de laatste C standaard ook weer een aantal bijgekomen, mede omdat we nu ook 64 bits computers kennen. Deze basistypes kunt u echter bij elke compiler gebruiken. Elke variabel zo groot mogelijk definiëren is mogelijk maar wel een verspilling van snelheid en geheugengebruik. Wanneer ik in een reversiprogramma een miljoen speelvelden wil opslaan om te doorzoeken maakt het veel uit of ik 8 bits waardes of 32 waardes gebruik voor de speelvelden. Wanneer het type variabele dit toestaat kun u er ook mee rekenen. Het declareren (bekendmaken) van een variabele gebeurt door het noemen van een datatype en een unieke naam die u zelf mag kiezen. U kunt een variabel bij het declareren ook gelijk een initiële waarde geven, wanneer u dit niet doet zal er in de meeste gevallen een willekeurige waarde in staan die op dat moment in deze geheugenlocatie stond. Hier volgen een aantal voorbeeld programma's die gebruik maken van variabelen.

// Voorbeeld van int variabelen

#include <stdio.h>

void main() 
{
int getal1;
int getal2 = 4;
int getal3 = 0;

   getal1 = 2;
   getal3 = getal2 + getal1; 
   printf("Uitkomst is: %d\n",getal3);
}

De uitvoer zal zijn: Uitkomst is: 6

Hier declareren we drie variabelen, de eerste is een int waarbij we alleen de naam reserveren, de tweede en de derde variabele geven we ook een initiële waarde. Daarna kennen we de getal waarde 2 toe aan de variabele getal1, (we stoppen het getal 2 in de geheugenplaats die aangewezen word door de naam getal1). De variabel getal3 had de waarde 0 maar in de volgende regel overschrijven we deze waarde met de uitkomst van het optellen van de waarden van de variabelen getal1 en getal2. Getal3 zal nu de waarde 6 bevatten. We gaven al aan dat we met de functie printf bijna alles kunnen afdrukken en in dit geval drukken we een tekst met de waarde van een variabele af. In de tekst van de (formatting) string geven we door middel van de tekencombinatie %d aan waar we de waarde van een int variabel opgenomen willen zien, daarna volgt de naam van de variabelen die op deze plaats afgedrukt moet worden. In het volgende voorbeeld gebruiken we meerdere type variabelen:

// Voorbeeld van verschillende variabelen

#include <stdio.h> 

void main() 
{
int getal1,getal2;  // Twee variabelen in 1 keer
char teken;
float breuk;

   getal1 = 9;
   getal2 = 2; 
   getal1 = getal1 / getal2;
   teken = 'A';
   breuk = 9.0 /  2.0;
   printf("Getal1 = %d\n",getal1);
   printf("Teken = %c\n",teken);
   printf("Breuk = %f\n",breuk);
}

De uitvoer zal zijn:
Getal1 = 4
Teken = A
Breuk = 4.5

Als eerste laat ik zien dat na een type meerdere variabelen gedeclareerd kunnen worden die gescheiden moeten zijn met een komma. Zoals u ziet kunt u met de printf functie ook andere datatypes afdrukken zoals %c voor characters en %f voor floats. Aangezien de variabel getal1 van het type integer is kan hier dus alleen maar een geheel getal in opgeslagen worden. Na de berekening zullen dus de cijfers na de komma wegvallen. Bij de float breuk ziet u dat de cijfers na de komma wel opgeslagen worden. Ik moet wel in de berekening achter de getallen .0 opnemen om de compiler duidelijk te maken dat het om float waarden gaat.

Arrays

Voordat we verder gaan met string moeten we eerst het array behandelen. Tot nu toe declareerden we enkelvoudige variabelen zoals getal1, getal2 en getal3. We kunnen ook een lijst van getallen declareren en door middel van een index een van de waarden uit de lijst schrijven of lezen. Een array geven we aan door middel van rechte haken [ ] na een variabele naam. Het getal tussen de haken geeft aan voor hoeveel waarden we willen reserveren.

// Voorbeeld van int array

#include <stdio.h>

void main() 
{
int getal[3];

   getal[0] = 4;
   getal[1] = 7;
   getal[2] = getal[0] + getal[1]; 
   printf("Uitkomst is: %d\n",getal[3]);
}

We declareren hier een array van drie integers en daarna kennen we aan de eerste index waarde van het array de waarde 4 toe en aan de tweede index binnen het array de waarde 7. Let op dat in C de index van een array van 0 tot de lengte min 1 loopt, dit kan verwarrend zijn maar de echte doorgewinterde C programmeur heeft dit in zijn systeem zitten. In dit voorbeeld is het array niet erg handig maar wanneer we loops (programmalussen) behandelen zal het nut van arrays snel duidelijk worden. Net als elke andere variabel kunnen we ook een array bij de declaratie van initiele waarden voorzien. De waarden worden dan tussen accolades en gescheiden door een comma achter de declaratie gezet.


/* dagen per maand */
int dagen[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };

Een vorm van een array met toch een paar bijzonderheden is het character array. De C standaard kent geen datatype string (veel andere programmeertalen wel), voor C is een string een array van characters. Om het einde van een tekenreeks (string) aan te kunnen geven gebruikt C het zogenaamde NUL teken wat we in C weergeven met de \0 tekenreeks. Ondanks dat C geen datatype string kent, bestaat er wel een grote standaard bibliotheek met string functies waarmee u character arrays kunt doorzoeken, lengte kunt bepalen, zoek en vervang kunt uitvoeren enz.

// Voorbeeld van een character array

#include <stdio.h>

void main() 
{
char tekst[] = "test";

  printf("Index1 = %c\n",tekst[0]);
  printf("Tekst = %s\n",tekst);
}

De uitvoer zal zijn:
Index1 = t
Tekst = test

Zoals u ziet declareer ik hier een array zonder een lengte aan te geven, C zal hier genoeg plaatsen reserveren om de waarde waarmee ik initialiseer op te slaan. Aangezien het hier om een character array gaat zal er automatisch een NUL teken achter gezet worden waardoor er in het geheugen dus: t e s t NULL opgeslagen is en het array dus 5 lang is. Denk hier even rustig over na want dit is heel belangrijk.

Zoals ik al aangaf zijn er in de programmeertaal C een aantal tekencombinaties die een speciale betekenis hebben, binnen het type char kunnen daarbij de volgende tekens gebruikt worden:
'\n' = nieuwe regel
'\t' = tab
'\a' = belsignaal
'\b' = backspace
'\f' = formfeed
'\r' = carriage return
'\v' = vertikale tab
'\\' = backslash zelf
'\'' = enkel aanhalingsteken
'\"' = dubbel aanhalingsteken
'\0' = nulteken

Pointers

De meeste bekritiseerde mogelijkheid van de programmeertaal C is tevens de meest krachtige. Een pointer is een variabele die verwijst naar een andere variabel of geheugenlocatie. Iedere processor kent micro-instructies om rechtsreeks met het geheugen te werken en de pointer in de programmeertaal C zal één op één naar deze micro-instructie van de processor omgezet worden. Dit maakt de pointer super snel maar ook zeer gevaarlijk, want wanneer onze pointer wijst naar een stuk geheugen waar we niet mogen kopen (systeemgeheugen) of naar variabelen die we niet bedoeld hadden dan overschrijf deze instructie zonder enige vorm van waarschuwing of controle het geheugen op de locatie waar de pointer op dat moment naar wijst. U begrijpt dat wanneer u pointers gebruikt u dus heel goed moet weten wat u doet en zelf de beveiligingen moet inbouwen. Een pointer (aanwijzer) is niets meer dan een variabele waarin een geheugenadres is opgeslagen. Wanneer we dus een pointer naar het adres van een variabele laten verwijzen dan kunnen we ook de waarde op dit adres opvragen. Om het nog ingewikkelder te maken kunnen we zelfs pointers naar pointers definiëren, maar dit is wel zeer geavanceerd gebruik wat u bijvoorbeeld in de memory management functies van een besturingsysteem terug kunt vinden. Pointers kunnen we ook in een array zetten, waardoor er pointer arrays ontstaan. Een toepassing hiervoor is een alfabetische index op een grote hoeveelheid data waarbij een array van 26 pointers het begin van elke letter aanwijst zodat we snel naar een bepaalde positie kunnen springen. Twee tekens zijn belangrijk bij het gebruik van pointer, het * teken voor een pointer variabel geeft aan dat we de inhoud willen van het veld waar de pointer naar wijst en met het & teken krijgen we het geheugenadres van een gewone variabele om een pointer te vullen met dit adres. Het volgende voorbeeld geeft dit aan.

// Voorbeeld van pointers

#include <stdio.h>

void main()
{ 
int getal, *pointer;
  
  getal = 4;  
  pointer = &getal;   // adres van var
  printf("Getal heeft de waarde: %d\n",getal);
  printf("Getal via pointer gelezen: %d\n",*pointer);
  *pointer = 5;
  printf("Getal heeft de waarde: %d\n",getal);
  pointer = 5; // Dit kan maar is enorme fout
}

De uitvoer zal zijn:
Getal heeft de waarde: 4
Getal via pointer gelezen: 4
Getal heeft de waarde: 5

De laatste instructie (pointer = 5) is volkomen legaal in de taal C, de pointer wijst nu naar geheugenlocatie 5 in deze computer, waar dit ook mag zijn, het is waarschijnlijk niet legaal om hier naar toe te schrijven. Door hier nu een waarde aan toe te kennen overschijven we ergens in het geheugen iets met als waarschijnlijk gevolg dat nu of later ons programma of het besturingsteem zal crashen. Ook kan het besturingsysteem dit afvangen en een memory error genereren, de meest subtiele fout is dat we een van onze eigen variabelen overschrijven waardoor ineens een totaal andere waarde heeft dan we verwachten. Dit zijn de meest moeilijk op te vinden programmeerfouten. Voordat u pointers gaat gebruiken moet u pointers wel heel goed begrijpen.

Operatoren en expressies

Het is leuk om variabelen te hebben maar we zullen er ook iets mee moeten kunnen doen, bijvoorbeeld er meer rekenen. Hier komen zogenaamde operatoren om te hoek kijken. De programmeertaal C kent verschillende operatoren, een operator vertelt de compiler wat voor een rekenkundige of logische bewerking verricht moet worden. In C worden drie soorten operatoren onderscheiden: rekenkundige operatoren, relationele of logische operatoren en bitwise operatoren. Aangezien de taal C gemaakt is voor zeer luie programmeurs is er vaak een zeer korte en compacte notatie mogelijk. Dit maakt code echt niet sneller (de optimizer van de compiler zal toch een expressie helemaal optimaliseren) en we moeten er wel aan denken dat broncode voor de mens is. De programmeertaal C kent de volgende rekenkundige operatoren:

+ optellen
- aftrekken
* vermenigvuldigen
/ delen
% modulo
-- met 1 verlagen
++ met 1 verhogen

Er zijn een paar typische C constructies mogelijk met deze operatoren die ik in de volgende voorbeelden duidelijk zal maken. De operator gevolgd door een = geeft aan de bewerking op dezelfde variabel van toepassing is, dus a += 3; is eigenlijk a = a + 3;. Nog compacter en sneller is a++; om de variabele a één eenheid ter verhogen of a--; om de variabele met één eenheid te verlagen. Nog een belangrijk verschil is dat ++a; de waarde ook met één eenheid verhoogt, maar er is een verschil tussen a++; en ++a; en dat zit hem in de waarde van de variabel in een expressie. Bij a++ zal eerste de waarde van a teruggeven worden waarna de variabele a verhoogd zal worden en bij ++a; zal eerst de waarde verhoogd worden en dan de waarde teruggeven worden. Deze bewerkingen kunnen we ook op pointers toepassen waardoor we dus een soort van aanwijzer door het geheugen kunnen schuiven. Bewerkingen als opvragen en tegelijk verhogen zijn in C ook mogelijk en worden ook heel vaak gebruikt. Het is dus belangrijk om alle voorbeelden hieronder te begrijpen.

// Voorbeeld van rekenkundige operatoren

void main()
{
int x,y,z;
int ar[3] = ;
int *ptr;

  x = 12;
  y = 3;
  z = x / y;  // = 4 
  z *= 2;     // = 8
  z = x++;    // = 12
  z = x;      // = 13
  z = --x;    // = 12
  z += 10;    // = 22
  ptr = &ar;
  z = *ptr;   // = 1
  ptr++;      // verhoog pointer
  z = *ptr++; // = 5
  z = *ptr;   // = 8
}       

De tweede groep van operatoren zijn de relationele en logische operatoren. Relationeel geeft aan of een relatie tussen waarden, zoals kleiner of groter of gelijk waar of onwaar is. De set van relationele operatoren bestaat uit de volgende lijst:

> groter dan
>= groter of gelijk
< kleiner dan
<= kleiner of gelijk
== gelijk aan
!= ongelijk aan

Logische operatoren hebben betrekking op AND, OR en NOT en deze kunnen gebruikt worden om meerdere relationele operatoren te combineren in een complexe expressie. Dit zijn de logische operatoren:

&& en (AND)
|| of (OR)
! niet (NOT)

// Voorbeeld van relationele en logische operatoren

void main()
{
int x,y,z;

  x = 12;
  y = 12;
  z = 8;

  x == y;   // True
  x == z;   // False
  x != z;   // True
  x == 12;  // True
  x > z;    // True
  x <= z;   // False   
  x == 12 && y == 12; // True
  x == 12 || y == 8;' // True
}       

Compound statement

Naast enkele statements kent de taal C ook blokken met gebundeld statement die bij elkaar horen. In een taal als Pascal kennen we de Begin en End om een blok aan te geven, in de taal C doen we dit door middel van de accolade openen en de accolade sluiten. Op elke plek waar u een enkel statement kunt toepassen kunt u ook door middel van de accolades een compound statement gebruiken. Voor de duidelijkheid is het van belang de accoladen op een overzichtelijke manier te plaatsen. Hier komt een verschil tussen C programeurs aan het licht, sommigen zetten de begin acolade op een nieuwe regel, ik ben van het soort die de open accolade achter het conditionele statemente plaatst.

Het conditionele statement

De meeste programmeertalen kennen een conditioneel statement in de volgende vorm:

als (conditie is waar)   dan (compound) statement
anders (compound) statement

In C 

if (expressie)  statement
else statement 

In de expressie mogen we alle operatoren gebruiken waarbij de uitkomst 0 gelijk is aan true en de waarde ongelijk aan 0 voor false staat. If en else mogen ook genest (in elkaar verweven) gebruikt worden, dit kan echter soms moeilijk leesbare broncode opleveren waarbij men soms niet goed kan zien bij welke ik de else hoort. Dit is eenvoudig te ondervangen door goed inspringen en altijd accolades te gebruiken, ook bij enkelvoudige statements. Een meer cryptisch gebruik van het if en else statement is het gebruik van de ? operator. Deze probeer ik zoveel mogelijk te vermijden omdat ik deze vorm erg onleesbaar vindt en het voor de uiteindelijk gecompileerde code niet uitmaakt omdat de optimizer van de compiler er dezelfde code van zal maken als van de if else variant. De notatie is wel erg kort:

expressie 1 ? expressie 2 : expressie 3;

Wanneer expressie 1 waar is dan wordt expressie 2 uitgevoerd anders expressie 3.

// Voorbeeld van conditionele statements

#include <stdio.h>

void main()
{
int x,y,z;

// geef x,y en z willekeurige waarden

  if (x == y) 
    printf("x is gelijk aan y\n");
  else
    printf("x is ongelijk aan y\n");
 
  if (x == y && x == z) 
    printf("x is gelijk aan y en gelijk aan z\n");
  // else is optioneel!
 
  if (x == y) { 
    printf("x is gelijk aan y\n");
    if (x == z) {
      printf("en x is gelijk aan z\n");
    }
  }
  else {
    printf("x is ongelijk aan y\n");
  }
  
  x = 12;
  if (x - 12) { 
    printf("True\n");
  }
  x = 12;
  y = 12;
  if (x = y) { 
    printf("Dit niet\n");
  }
  else { 
    printf("Dit wel\n");
  } 
}       

De laatste variant is de meest gemaakte fout in de programeertaal C, het is een assignment, we maken de waarde x gelijk aan y en het resultaat is NIET 0 dus false. Hierdoor zal ALTIJD de else uitgevoerd worden tenzij y de waarde 0 heeft. Let op deze fout! Bij een hoog warning level zullen de meeste compilers hier wel een warning voor geven, ik compileer zelf altijd op het hoogste warning level en hanteer WARNING == ERROR.

Het meerkeuze statement (switch)

Met if en else kan een lange rij van condities worden opgesteld waardoor het programma snel onleesbaar kan worden. Soms willen we in één test meerdere waarden testen en bij elke waarde iets anders uitvoeren. Hier is een switch statement erg handig voor te gebruiken. Bij iedere case waarde hoort een (compound) statement en wanneer de compiler een break tegenkomt zal het doorvallen naar het einde van de switch. Wordt de break weggelaten dan zal het volgende statement ook worden uitgevoerd. Wanneer aan geen van de cases wordt voldaan zal het default statement worden uitgevoerd.

// Voorbeeld van conditionele statements

#include <stdio.h>

void main()
{
int x;

// geef x een willekeurige waarde

 switch(x) {
   case 1:  printf("De waarde 1\n");
            break;
   case 2:  printf("De waarde 2\n");
            break;
   case 3:
   case 4:  printf("De waarde 3 of 4\n");
            break;
   default: printf("Andere waarde!\n");
            break;
 } 
}       

Loops in C

De programmeertaal C kent drie soorten iteratieve statements (lussen): het while statement, het do while statement en het for statement. Alledrie zullen ze een statement of een code blok enige malen herhalen tot er aan een bepaalde conditie voldaan wordt. Het verschil tussen deze drie varianten zit in de test conditie en hoe vaak moet iets herhaald moet worden. Wanneer het een vooraf vast staand aantal keren betreft kan het beste gebruik worden gemaakt van een for statement, in andere gevallen is de while handiger. Een for loop in C ziet er nogal cryptisch uit. De formele syntax is:

for (initialisatie; conditie; increment) statement
De drie componenten zorgen voor een heel flexibel gebruik van het for statement, de initialisatie kent een begin waarde toe aan de zogenaamde loop control variabele (index), de conditie is een relationele expressie welke bepaald of de loop beëindigd moet worden, hier kan de loop control variabele maar ook elke andere variabel in gebruikt worden, en als laatste de stapwaarde bepaald hoe de loop control variabele wijzigt bij elke iteratie van de loop. Het krachtige van het for statement in C is dat de teller ook af kan lopen met elke zelfgekozen stap en dat de conditie van alles mag bevatten. Ook kunnen er meerdere loop index waarden tegelijk worden gebruikt met elk hun eigen stap. Het is niet noodzakelijk dat alle componenten van de for syntax aanwezig zijn. Elk onderdeel van de for loop is optioneel en zo kunnen er vreemde varianten ontstaan.

// Voorbeeld van for loops

#include <stdio.h>

void main()
{
int x,y;

  // druk 0..10 af
  for (x=0; x<10; x++) 
    printf("X = %d\n",x); 

  // druk 0 2 4 6 ..10 af  
  for (x=0; x<10; x += 2) 
    printf("X = %d\n",x); 
  
  // druk x 0 2 4 6 ..10 af
  // druk y 10..1 af
  for (x=0, y=10; x<10; x += 2, y--) {
    printf("X = %d\n",x); 
    printf("Y = %d\n",y); 
  }
}       

De tweede vorm van loop (lus) is de while loop en in C heeft deze de volgende syntax:

while (conditie) statement
Zolang de conditie waar is zal het statement of blok met statements worden uitgevoerd. Belangrijk is dat de test eerst uitgevoerd zal worden en wanneer deze gelijk onwaar is zal het statement dus nooit uitgevoerd worden. In het volgende voorbeeld gebruiken we ook even de functie getchar() uit de standaard library. Deze zal een ingedrukte toets teruggeven. Putchar is ook een functie uit de standaard library die een teken op het scherm afdrukt. Zie hier de meest eenvoudige tekstverwerker.

// Voorbeeld van while loop

#include <stdio.h>

void main() 
{ 
char ch = '\0'; 

  // stop als Q ingetikt is
  while (ch != 'Q') { 
    ch = getchar();
    putchar(ch);
  }  
}     

In tegenstelling tot de for en de while, test de do while loop de conditie aan het einde van de loop, de loop zal dus minimaal één keer uitgevoerd worden. Afgezien hiervan is de de do while constructie gelijk aan de while.

// Voorbeeld van while loop

#include <stdio.h>

void main() 
{ 
char ch; 

  // stop als Q ingetikt is
  do { 
    ch = getchar();
    putchar(ch);
  } while (ch != 'Q');
}     

Break, contnue en goto

Het break statement zijn we al eerder tegengekomen als de beëindiging van een case maar break kan ook als een beëindiging van een loop worden gebruikt. Indien meerdere loops genest zijn zal break alleen zorgen voor het stoppen van de loop waarin het voorkomt.

Door middel van het continue statement zal onmiddellijk naar de volgende stap van de loop gegaan worden en zo kan men binnen een loop een deel van de code overslaan. Dit kan efficiënt zijn omdat bijvoorbeeld na één test binnen de loop al duidelijk is dat de rest van de testen niet nodig is.

Dan komen we bij het meest verguisde statement in de taal C, het goto statement. Hiermee kan men vanuit een lus en zelfs vanuit geneste lussen naar buiten de lussen springen naar een label. Veel mensen denken dat ze netjes programmeren wanneer ze geen goto gebruiken, ik vind dit stom omdat het goto statement zeker nuttig kan zijn. Het is duidelijker om in een foutconditie snel uit geneste lussen te springen met een goto dan moeilijk te doen en te zorgen dat men uit alle lussen doorvalt. Maar hier verschillen de meningen van verschillende programmeurs, ik ben van mening dat duidelijke code voor strakke regeltjes gaat.

// Voorbeeld van break, continue en goto

#include <stdio.h>

void main() 
{ 
int i,y; 
  
  y = 20;
  for (i=0; i<10; i++) (
    y = x * 2;
    if (y > 10) 
      continue; 
    printf("Kleiner dan 10");
    // verlaat lus als y == 18
    if (y == 18)
      break;       
  }    

  for (i=0; i<10; i++) (
    for (y=0; y<10; y++) (
      printf("Waarde: %d\n",x * y);
      if (i ==5 && y == 8)
        goto marker;
    }
  }
marker:  
  
}     

Wordt vervolgt!


Gcc compiler onder Linux

© 2015 Hein Pragt

Op mijn Raspberry Pi programmeer ik in 'C' met gebruik van de gcc compiler. De gcc compiler is de "GNU" C Compiler en g++ is de "GNU C++ compiler". Hier staat een kleine uitleg met voorbeelden hoe deze compilers gebruikt kunnen worden. In voorbeeld 1 compileren we het bijna standaard programma "Hello world!", gebruik een editor onder linux vi is daar één optie, ik gebruik meestal de nano editor. Om de broncode te maken tikt u dan nano hello.c en voert u het volgende programma in:

#include "stdio.h"

int main() 
{
  printf("Hello world!\n");
} 

We kunnen dit programma vervolgens compileren met het volgende commando:

gcc hello.c -o hello 

Dit commando compileert en linkt hello.c naar een uitvoerbaar bestand met de naam "hello" dat uitgevoerd kan worden door hello of ./hello op de command line in te tikken. Het enige wat dit programma doet is de boodschap "Hello world!" op het scherm afdrukken, maar het is wel een teken dat de hele keten werkt. We kunnen ook de stappen van het compileren en linken uit elkaar trekken door middel van de volgende commando's, het resultaat zal hetzelfde zijn.

gcc -c hello.C
gcc hello.o -o hello 


NewbieIDE C en C++ IDE

© 2015 Hein Pragt

Ik was voor mijn dochtertje op zoek naar en eenvoudige maar wel krachtige IDE (compiler met editor in één) voor de programmeertaal c en ik vond het programma NewbieIDE. NewbieIDE is een gratis C ++ IDE waarmee je testprogramma's in C ++ kunt schrijven. Het is een eenvoudige en lichtgewicht applicatie ontworpen om beginners te helpen met een snelle start in C en C++. NewbieIDE is geschreven in VB.Net en gebouwd op de MinGW (Minimalist GNU for Windows) GCC compiler. Deze gratis C en C++ IDE is niet super krachtig maar het is echt effectief en snel in de uitvoering. Het wordt geleverd met een multi-interface met tabbladen die gebruikers in staat stelt om op een eenvoudige wijze een stuk sourcecode te schrijven en daarna met de F5 uit te voeren. NewbieIDE is open source software die gemakkelijk kan worden gedownload via de link aan het eind van dit artikel. De download zal als een ".7z" file komen, een gecomprimeerd bestandsformaat dat kan worden uitgepakt met behulp van gratis 7-Zip-compressie software. Daarna kunt u gewoon op de portable "NewbieIDE.exe" file uitvoeren om de IDE uit te voeren. NewbieIDE richt zich voornamelijk op C en C++ leerlingen en dus heeftr het een eenvoudige gebruikersinterface met alleen de noodzakelijke elementen. Dit omvat een menubalk, een werkbalk notering minimaal benodigde gereedschappen, een editor venster en een paneel voor het weergeven van het debuggen fouten. NewbieIDE ondersteunt de basisfuncties van een goede IDE inclusief regelnummering en syntax highlighting.
Download hier NewbieIDE


Visual Studio Express en community

© 2015 Hein Pragt

Zelf gebruik ik al meer dan 20 jaar de Microsoft C compilers, ik heb zeker 5 versie's op originele CD hier in mijn kast liggen en heb zelf nog een geldige licentie voor versie 4.2 en 5.0. Maar nu gebruik ik Visual Studio Community editie C++ wat een volledige versie is zonder beperkingen. Daarnaast kun u, wanneer u niet online wilt werken, de express edition 2010 en 2013 downloaden. Ik programmeer voor Windows zelf puur op win32, dat is dus standaard C met Win32 aanroepen om dingen op het scherm te zetten, systeemfuncties aan te roepen en de muis en het toetsenbord af te handelen. Het is een prima ontwikkel omgeving met ingebouwde debugger. In de nieuwste uitvoering kunt u er trouwens met bijna elke programmeertaal in werken.

Download Visual Studio Express C++

Visual Studio 2008 Express C++

Online boeken voor de programmeertaal C

© 2011 Hein Pragt

Hier staat twee pdf bestanden met een goede Nederlandstalige cursus voor de programmeertaal C. Alle aspecten van de taal komen in combinatie met goede voorbeelden aan de orde.

Een goede online cursus voor de programmeeraal C

Een goede online PDF cursus voor de programmeeraal C


Boeken over de programmeertaal C en C++

boek boek bestellen In zee met C - In zee met C is bestemd voor gebruik in het hoge onderwijs bij een inleidende cursus C voor technische informatica, elektrotechniek of industriële automatisering. Dit boek bestaat uit twee delen. Deel I is een algemene inleiding in de taal C, gebaseerd op kleine complete programma's aan de hand waarvan begrippen en elementen van de taal toegelicht worden. Deel 2 richt zich op C in een technische en/of embedded omgeving. Ook hier worden zoveel mogelijk compleet werkende programma's gepresenteerd die de lezer kunnen inspireren of waarmee de werking van een stuk software wordt verduidelijkt. In het eerste deel van het boek wordt een inleiding in de hogere taal C gepresenteerd. Het een en ander wordt aan de hand van C-programma's toegelicht. Hierbij wordt gebruikt gemaakt van een C-compiler in een Linux omgeving. Het is voor de beginner goed te volgen en alle belangrijke elementen van C komen aan de orde. Het tweede deel is gericht op C in een embedded en/of technische omgeving. Het laatste deel is doet een groot beroep op voorkennis van de gebruiker. Waar nodig wordt theoretische achtergrondinformatie gegeven. Onderwerpen zoals variabelen en constanten, samengestelde datatypen, pointers, functies, C in een embedded omgeving, crosscompilatie, het aansturen van hardware vanuit C, fixed point-berekeningen, assemblers en netwerktoepassingen worden behandeld. Goed geschreven studieboek voor het hoger onderwijs; een tweede doelgroep is de pc gebruiker die programmeren als hobby heeft. De uitgave is ook geschikt als naslagwerk.


boek boek bestellen Leerboek objectgeorienteerd programmeren in C++ / druk 1 - Dit boek is bestemd voor mensen die op een gestructureerde manier C++ willen leren. Ieder hoofdstuk behandelt een stuk theorie en wordt afgesloten door oefeningen die betrekking hebben op de behandelde stof. Als u alle hoofdstukken gelezen hebt, bent u In staat om een goede C++-structuur op te bouwen. De auteurs zijn werkzaam bij Datasim B.V Dit bedrijf is al een aantal laren koploper op het gebied van objectgeoriënteerde technologie en is gespecialiseerd in het geven van opleidingen in deze branche. Dit boek is dan ook geschreven aan de hand van praktijk- en leservaringen op het gebied van C++ en objectgeoriënteerde analyse. Dit boek behandelt achtereenvolgens de basisprincipes van (het programmeren met) objecten, de basismogelijkheden van de programmeertaal C++, de geavanceerde mogelijkheden van C++ en tot slot objectgeorienteerd programmeren in C++. Hoewel de uitgave in zijn opbouw dus zeer helder gestructureerd is en min of meer bij de basis van programmeren begint, is voor dit boek een zeer behoorlijke ervaring met het schrijven van computer programma's nodig, op het niveau HBO/WO. Beschikt men over deze voorkennis dan is het een helder en goed geschreven leerboek om objectgeorienteerd te leren programmeren in C++.



Last update: 07-05-2015




 

Disclaimer.

Hoewel de heer Hein Pragt de informatie beschikbaar op deze pagina met grote zorg samenstelt, sluit de heer Pragt alle aansprakelijkheid uit met betrekking tot de informatie die, in welke vorm dan ook, via zijn site wordt aangeboden. Het opnemen van een afbeelding of verwijzing is uitsluitend bedoeld als een mogelijke bron van informatie voor de bezoeker en mag op generlei wijze als instemming, goedkeuring of afkeuring worden uitgelegd, noch kunnen daaraan rechten worden ontleend. Op de artikelen van de heer Pragt op deze Internetsite rust auteursrecht. Overname van informatie (tekst en afbeeldingen) is uitsluitend toegestaan na voorafgaande schriftelijke toestemming van de rechthebbende. Voor vragen over copyright en het gebruik van de informatie op deze site kunt u contact opnemen met: (email: mail@heinpragt.com)