Nieuws:

Welkom, Gast. Alsjeblieft inloggen of registreren.
Heb je de activerings-mail niet ontvangen?

Auteur Topic: Beginnen met C  (gelezen 13986 keer)

Offline idefix

  • Lid
Beginnen met C
« Gepost op: 2009/04/12, 09:10:32 »
Omdat er hier van tijd tot tijd toch vragen over C gesteld worden, wil ik hier een topic maken als een soort beginnerscursus. Boeken over C gaan vaak aan een sneltreintempo vooruit, omdat C vaak niet beschouwd wordt als een beginnerstaal.
Met dit topic wil ik om de dag / x aantal dagen een "hoofdstukje" posten. De bedoeling is dat er een "lichte cursus" ontstaat, die de beginner in staat stelt om met C te beginnen. Tevens kunnen vragen gesteld worden, als iets niet goed begrepen is.

Deze paragraaf is niet voor de beginner, maar dient om discussies te vermijden:
Over het voor en tegen van C leren valt veel te zeggen. Er zijn andere, hogere,  talen (Java, Python of -godbetert- Visual Basic,,..) die veel geschikter zijn voor veel zaken dan C. Bijvoorbeeld het pointer-concept is nogal ingewikkeld en wordt in de bovengenoemde talen voor de programmeur weggestopt "achter de schermen" . Deze talen maken dus ook gebruik van pointers, maar onzichtbaar.
Deze talen maken echter vaak gebruik van optimalisatietechnieken. Om deze technieken tenvolle te kunnen benutten, komt een goed begrip van pointers van pas. Dus ook als je nooit in C gaat programmeren, kan een studie van het pointer-begrip nuttig zijn.
C is dertig jaar oud, en wordt nog steeds veel gebruikt. Voor systeemprogrammatie, voor games,... (C is een snelle taal). De ouderdom heeft nog een voordeel: er is veel broncode in C beschikbaar om te bestuderen en  er zijn veel mensen die C kennen.  C is door zijn ouderdom ook een beknopte taal, wat het leerproces vergemakkelijkt.
Tegelijk is de ouderdom een nadeel: veel concepten die nu als "modern" gelden, bestaan niet in C. Iets heel gewoons, als een type string bestaat niet in C. Er bestaat zelfs geen speciaal type voor karakters (= afdrukbare tekens). Voor het representeren van karakters worden integers (gehele getallen) gebruikt: int en char.
Wat ik wil zeggen: er kleven voor- en nadelen aan C. Daar gaat deze draad echter niet over. De bedoeling is om te leren beginnen met C, wat we in de volgende post meteen doen.
Support bacteria. They're the only culture some people have.

Offline idefix

  • Lid
Re: Beginnen met C
« Reactie #1 Gepost op: 2009/04/12, 10:46:13 »
Eerste programma

Typ het volgende programma in, en bewaar het onder de naam test.c
Vooral de extensie .c is belangrijk. Hierdoor weet de compiler straks dat het om een c-programma gaat.

#include <stdio.h>

main(){
  printf("Mijn eerste programma in C\n");
}


Voilà, je hebt je eerste C-programma ingetoetst. Hier valt al een en ander over te vertellen. Maar we gaan het eerst eens testen. In de directory waar je test.c opgeslagen hebt, typ je nu:

gcc test.c
Als je geen schrijffouten gemaakt hebt en nu op enter drukt, wordt het programma test.c gecompileerd door de gnu c compiler  (gcc). M.a.w. de code die je geschreven hebt, wordt nu omgezet naar een bestand dat voor de computer verstaanbaar is. Als je nu het commando ls geeft, zal je behalve test.c ook een bestand a.out zien. Dit is een uitvoerbaar bestand. De compiler heeft het gemaakt van jouw bronbestand test.c. Als je a.out wilt uitvoeren, moet je typen:
./a.out
Normaalgezien zie je nu het volgende:
Mijn eerste programma in C
Als je onderweg foutmeldingen krijgt, moet je kijken of je het bronbestand exact, zonder fouten, hebt overgeschreven. Een ; of \ vergeten, maakt dat het programma niet gecompileerd kan worden.

We gaan nu eens regel per regel bekijken van ons eerste programma:

#include <stdio.h>Deze regel zorgt ervoor dat de inhoud van het bestand stdio.h wordt ingevoegd. Dit bestand zit automatisch in het C-systeem, dus je moet het niet zelf schrijven. Het bevat informatie om uitvoer naar het scherm te kunnen laten gebeuren. De naam is de afkorting van standard input output. Voorlopig moet je hier niet te veel aandacht aan schenken. Onthoud alleen dat je dit bestand moet insluiten als je uitvoer naar het scherm wil schrijven (of invoer van het toetsenbord wilt gebruiken), zoals wij seffens met de functie printf().

De volgende regel
main(){
Deze regel duidt aan dat hier de main-functie (hoofdfunctie) van het programma begint. Elk programma heeft zo een main-functie. De uitvoering van een programma begint steeds in main().
De twee haakjes () tonen aan dat het om een functie main gaat. We komen nog terug op functies. De accolade { duidt aan dat alles wat nu volgt, tot aan de sluitende accolade }, behoort tot de main()-functie.
In ons geval staat er maar één regel tussen de accolades, maar er kunnen er veel staan. Het stuk tussen de accolades heet een blok, in dit geval het main-blok.

De regel tussen de accolades is de enige die werkelijk iets doet:
printf("Mijn eerste programma in C\n");
Je ziet dat er na printf ook een haakje ( staat, en op het einde staat weer een haakje ). Je raadt het al, printf() is een functie, meer bepaald een functie om iets op het scherm te zetten, in geformatteerde toestand, d.w.z. in een bepaalde vorm. Hetgeen op het scherm moet komen, komt tussen de haakjes () te staan. Dit heet het argument van de functie. Onze main-functie had lege haakjes (), dus die heeft geen argument gekregen.
Het argument van printf is hier "Mijn eerste programma in C\n". Dit is de tekst die op het scherm moet afgedrukt worden, behalve de twee laatste tekens \n. De \n zorgt ervoor dat na het afdrukken, de cursor naar de volgende regel springt, een zogeheten newline. Je kan test.c eens veranderen door de \n weg te laten.
Je moet nu wel weer compileren, omdat je de broncode veranderd hebt. En dan weer ./a.out aanroepen. Zie je het verschil? De cursor plakt nu tegen je zinnetje aan.
Het laatste punt voor deze "les" is de puntkomma op het einde van printf(). Deze ; duidt erop dat we klaar zijn met het printf()-statement. De puntkomma moet achter ieder statement (opdracht) staan in C. Het is een fout die je nog veel zal maken: de ; vergeten. Maar stilaan wordt het een gewoonte.
Probeer eens de ; weg te laten en dan te compileren. Je zal het volgende zien:
$ gcc test.c
test.c: In function 'main':
test.c:5: error: expected ';' before '}' token
 
Je ziet, de compiler wijst je op je fout.

De } op de laatste regel is de afsluiter van de { die het main-blok opende.
Ziezo, je eerste programma zit er op. Je hebt er wat mee gespeeld (de \n weglaten, of de ; vergeten). In het volgende stuk gaan we kijken wat variabelen zijn.
« Laatst bewerkt op: 2009/04/12, 10:49:23 door idefix »
Support bacteria. They're the only culture some people have.

Offline track

  • Lid
Re: Beginnen met C
« Reactie #2 Gepost op: 2009/04/12, 15:30:15 »
Er is ook een vrij mooi "Wikiboek" dat ook de achtergronden een beetje verlicht.
(en volgens mij niet te erg "sneltrein", of ben ik al te gevorderd ?)
->  http://nl.wikibooks.org/wiki/Programmeren_in_C

Vriendelijke groet,

track

Offline profoX

  • Lid
    • wesley
    • Lionslink
Re: Beginnen met C
« Reactie #3 Gepost op: 2009/04/12, 23:15:58 »
Leuk initiatief, maar de code in die eerste les voldoet niet aan de ANSI C standaard.

De programmacode

Citaat
#include <stdio.h>

main(){
  printf("Mijn eerste programma in C\n");
}

zal achter de schermen omgezet worden in het volgende stuk code:

Citaat
#include <stdio.h>

int main(){
  printf("Mijn eerste programma in C\n");
}

omdat int als standaardtype wordt gebruikt volgens de C standaard wanneer er geen type gespecifieerd wordt.. en dus ontbreekt er nog een return-statement.. "technisch 'correct'" zou dus zijn:

Citaat
#include <stdio.h>

main(){
  printf("Mijn eerste programma in C\n");
  return 0;
}

maar je zou nog steeds een compilerwarning krijgen indien je compileert met de -Wall optie omdat het een slechte programmeerstijl is om returntypes niet expliciet te vermelden.

Als je het volledig netjes en volgens de standaard wil doen, dan moet je het dus als volgt doen:

Citaat
#include <stdio.h>

int main(){
  printf("Mijn eerste programma in C\n");
  return 0;
}

Tip: compileer steeds d.m.v. "gcc -Wall -ansi -pedantic" (hoewel -ansi in sommige gevallen misschien een beetje te strikt is) want dan meldt de compiler je vaak wanneer je iets "op een minder goede manier" doet
« Laatst bewerkt op: 2009/04/12, 23:19:07 door profoX »
Human Knowledge Belongs To The World -- Antitrust (2001)
Nederlandstalige Ubuntu documentatie van Ubuntu-NL (wiki)

Offline idefix

  • Lid
Re: Beginnen met C
« Reactie #4 Gepost op: 2009/04/13, 08:08:32 »
Dank je wel Profox, maar ik wou deze tutor stappeke voor stappeke maken. Ik wou dit concept introduceren na het bespreken van fucties en return, omdat de "oude" manier ook nog werkt. De meeste compilers laten dit toe omdat het zo ingeburgerd was. Maar je hebt gelijk dat het niet meer de ANSI-standaard is.

Maar als ik iets fouts zeg, alsjeblieft, verbeter mij.
« Laatst bewerkt op: 2009/04/13, 10:22:03 door idefix »
Support bacteria. They're the only culture some people have.

Offline idefix

  • Lid
Re: Beginnen met C
« Reactie #5 Gepost op: 2009/04/13, 10:20:54 »
Variabelen

In deze les gaan we eens kijken naar variabelen. Variabelen zijn als doosjes met een naam, waar je iets in kan stoppen en weer uithalen. Net zoals er verschillende soorten dozen zijn, heb je verschillende soorten variabelen. En net zoals je een luciferdoosje niet kan gebruiken om een boterham in te stoppen, kun je niet elk type variabele gebruiken voor eender wat. Concreet betekent dit dat je in een variabele voor een geheel getal (integer) geen kommagetal kunt stoppen.

We gaan meteen een voorbeeld geven. Stel dat je een variabele wilt maken om het aantal mensen in een club weer te geven. Daarvoor gebruik je best een geheel getal (halve mensen bestaan alleen in horrorfilms met kettingzagen). Een geheel getal is in C een int.
Op deze manier maak je een variable (anders gezegd: zo declareer je een variabele):
int a;

Hiermee declareer je een variabele van het type int (geheel getal), met de naam a. Het is beter een naam te kiezen die weerspiegelt waar de variable voor staat. bijvoorbeeld aantal_leden of ledenaantal. Als je alleen maar letters of andere cryptische omschrijvingen gebruikt, zal je programma onleesbaar worden. Dus zo is het beter:

int ledenaantal;


Hiermee heb je nu de variabele ledenaantal gemaakt. De variabele heeft echter nog geen waarde. We kunnen hem een waarde toekennen met de toekenningsoperator =

ledenaantal = 1;

Dit stukje code doet niets anders dan de waarde 1 toekennen aan ledenaantal.

Je kan ook een variabele declareren en meteen een waarde toekennen:
int ledenaantal = 1;

Dit is hetzelfde als:
int ledenaantal;
ledenaantal = 1;

Stel nu dat het lidgeld 19.90 EURO bedraagt, dan kunnen we dit bedrag niet in een int stoppen, want het is geen geheel getal. Hiervoor gebruik je het type float. Met hetgeen we weten declareren we nu de variabele lidgeld:
float lidgeld = 19.90;

Om nu verder te gaan met de verschillende types, moeten we eerst een beetje theorie bekijken over bits en bytes.

Het geheugen van een computer bestaat uit miljoenen schakelaartjes (of als je wil: lampjes) die ofwel aan ofwel uit staan. Eén zo een schakelaartje heet een bit. Deze bit kan twee waarden aannemen: 0 (uit) of 1 (aan). Infeite kan je zeggen dat je met zo een schakelaartje tot 1 kan tellen.
Als je twee schakelaars naast elkaar zet, dan krijg je meer mogelijkheden:

00: beide schakelaars staan uit
01: de eerste staat uit, de tweede staat aan.
10: de eerste staat aan, de tweede staat uit.
11: beide staan aan.

Met 2 schakelaars / bits kun je dus vier toestanden aangeven, of anders gezegd: met 2 bits kun je 4 getallen voorstellen:

00: in ons decimaal stelsel 0
01: in ons decimaal stelsel 1
10: in ons decimaal stelsel 2
11: in ons decimaal stelsel 3

Meer kunnen we niet doen met 2 bits. Kijk eens naar 3 bits:

000: 0
001: 1
010: 2
011: 3, tot hier waren we al gekomen met 2 bits.
100: 4
101: 5
110: 6
111: 7

We kunnen dus 8 getallen aanduiden met 3 bits (0-7). Om het getal 8 aan te duiden heb je 4 bits nodig: 1000.

Wat we nu eigenlijk doen, is het binaire stelsel bespreken.
Wij, gewone stervelingen, werken meestal met het decimale of tiendelige stelsel (behalve voor bijvoorbeeld de tijd, waar we het twaalfdelig en 60-delig stelsel gebruiken). Het decimale stelsel bevat 10 cijfers: 0,1,2,3,4,5,6,7,8,9. Om de waarde tien aan te duiden, zijn er niet genoeg cijfers voorhanden. Dit doen we door twee cijfers te nemen: de 1 en de 0: 10. En dan aan we weer verder: 11, 12, 13, ... 19. Nu zijn onze mogelijkheden weer op. De eerste positie moet dus vervangen worden: 20. En dan weer verder 21, 22, ... 29, 30, 31, ... 39, 40, 41, ... enz ... 97, 98, 99.
Nu hebben we alle 100 mogelijke combinaties met 2 cijfers gehad. Het volgende getal, honderd, heeft 3 cijfers noddig: 100. En zo kunnen we weer verdertellen: 101, 102, 103,...

Precies zo gaat het bij binair rekenen (met maar twee getallen: 0 en 1). Alleen raken onze mogelijkheden veel sneller uitgeput en moeten we sneller langere getallen schrijven.
Het begin is zoals in het tiendelig stelsel:

0
1  : hier zijn we al uitgeput, omdat we geen cijfer 2 hebben. Het getal 2 moet dus voorgesteld worden door een 10
10
11 : we zijn weer uitgeput, we doen er weer een positie bij:
100
101
110
111: we zijn weer uitgeput, we doen er weer een positie bij:
1000
enz.

Hoe meer bits, hoe grotere getallen kunnen voorgesteld worden.
Met 1 bit kunnen 2 waarden weergegeven worden.
Met 2 bits kunnen 4 waarden weergegeven worden. (4 = 2²)
Met 3 bits kunnen 8 waarden weergegeven worden. (8 = 2³)
Met 4 bits kunnen 16 waarden weergegeven worden. (16 = 24)
Met 5 bits kunnen 32 waarden weergegeven worden. (25)
Met 6 bits kunnen 64 waarden weergegeven worden. (26)
Met 7 bits kunnen 128 waarden weergegeven worden. (27)

Met 8 bits kunnen 256 waarden weergegeven worden (0-255). Zo een reeks van 8 bits heet een byte. Dat is eigenlijk de basiseenheid waarmee de meeste computers werken. Als je twee bytes na elkaar zet, heb je 16 bits en kun je 65536 waarden voorstellen.

Een int wordt meestal opgeslagen in 4 bytes. In een int kun je dus 4.294.967.296 verschillende waarden opbergen. Een groter getal kun je niet in een int stoppen (bijvoorbeeld de wereldbevolking): er is gewoonweg niet genoeg plaats voor.

Er bestaat in C ook een type short (voluit short integer of "korte integer") die meestal in 2 bytes opgeslagen wordt en 65.536 getallen kan voorstellen.

Er bestaat in C nog een type char, dat  opgeslagen wordt in 1 byte: daarmee kunnen dus gehele getallen van 0 tot 255 opgeslagen worden.

De situatie is eigenlijk nog ingewikkelder, omdat je wel of niet met negatieve getallen kunt werken. Bijvoorbeeld een short, die in twee bytes opgeslagen wordt, kan zoals gezegd 65.536 waarden opslaan. Als dit alleen positieve getallen zijn, gaan de waarden van 0 tot en met 65.535.
We kunnen echter ook een short declareren als signed short (d.w.z met een teken, + of -). Dan kan je ook negatieve waarden voorstellen, van -32.768 tot en met +32.767. In totaal zijn dit ook 65.536 waarden.
Als we echter zeker zijn, dat we geen negatieve waarden hebben (bijvoorbeeld om het aantal leden van een club weer te geven), kunnen we een type als unsigned declareren. Een unsigned short kan de waarden 0 t.e.m. 65.535 weergeven.

In C geldt dat als een type zonder prefix (signed / unsigned) gedeclareerd wordt, dat het een signed type is.

In het volgende stuk zullen we de basis-types eens systematisch opsommen, met hun bereik.
« Laatst bewerkt op: 2009/04/13, 11:26:00 door idefix »
Support bacteria. They're the only culture some people have.

Offline idefix

  • Lid
Re: Beginnen met C
« Reactie #6 Gepost op: 2009/04/13, 11:57:35 »
De basis-datatypes

In dit stuk bekijken we eens de basis-datatypes:

1. Gehele getallen

Hier hebben we de types char, short, int, long.
De lengte in bytes van een bepaald type kan verschillen van computer tot computer, maar hier geven we de meest gangbare lengtes weer.

Een char wordt opgeslagen in 1 byte en heeft het bereik -128 t.e.m. +127
Een unsigned char heeft het bereik 0 t.e.m. 255

Een short wordt meestal opgeslagen in 2 bytes en heeft het bereik -32.768 t.e.m. + 32.767
Een unsigned short heeft het bereik 0 t.e.m. 65.535.

Een int wordt meestal opgeslagen in 4 bytes en heeft het bereik -2.147.483.648 t.e.m. +2.147.483.647
Een unsigned int heeft het bereik van 0 t.e.m. 4.294.967.295.

Een long heeft meestal hetzelfde bereik als een int (hij wordt meestal ook opgeslagen in 4 bytes). Er bestaat ook een unsigned long.


2. Kommagetallen

Hier hebben we de types float, double, long double.

Bij veel compilers wordt een float opgeslagen in 4 bytes, een double in 8 bytes en een long double in 12 bytes.

Een float heeft een bereik van 10-38 tot 10+38, met een precisie van 6 significante cijfers.
Een double heeft vaak een bereik van 10-308 tot 10+308, met een precisie van 15 significante cijfers.

Het is heel belangrijk te beseffen dat de precisie beperkt is bij floating-point (komma-)getallen. Dit komt omdat deze getallen intern in het tweedelig stelsel (1 en 0) worden weergegeven.

Dit was het laatste stukje zonder voorbeeld. De volgende stukken zullen "levendiger" zijn omdat er meer voorbeelden zullen gegeven worden. In het volgende stuk gaan we de uitvoer m.b.v. de functie printf() eens nader bekijken.
« Laatst bewerkt op: 2009/04/13, 11:59:06 door idefix »
Support bacteria. They're the only culture some people have.

Offline idefix

  • Lid
Re: Beginnen met C
« Reactie #7 Gepost op: 2009/04/13, 20:11:47 »
Uitvoer met printf()

We hebben al de functie printf() gezien. De f in printf staat voor format, wat wil zeggen dat de uitvoer geformatteerd wordt, of anders gezegd: de uitvoer wordt in bepaalde vorm op het scherm gezet.
We hebben al gezien dat printf() een argument nodig heeft: een tekenreeks tussen aanhalingstekens (een string in het jargon).

Eigenlijk kan printf meerdere argumenten krijgen:

#include <stdio.h>

main(){
  char voorbeeld = 97;
  printf("%d\n", voorbeeld);
}

Als je dit programma laat draaien, krijg je als uitvoer: 97. De functie printf() heeft hier twee argumenten meegekregen, gescheiden door een komma:

"%d\n" en voorbeeld

Het eerste argument "%d\n" bestaat uit %d en \n. Dit laatste kennen we al. Dit newline-karakter zorgt dat de cursor na de uitvoer naar de volgende regel springt. De %d is nieuw: dit is een conversiespecificatie. Deze zegt aan de compiler in welke vorm het tweede argument (hier dus de variabele voorbeeld) moet weergegeven worden, namelijk als een decimaal.

We kunnen de variabele voorbeeld ook laten afdrukken als een karakter, als een teken (Engels: character). Als je hetzelfde programma laat draaien maar de conversiespecificatie vervangt door een %c:

#include <stdio.h>

main(){
  char voorbeeld = 97;
  printf("%c\n", voorbeeld);
}

dan krijg je als uitvoer de letter 'a'. Dit is vreemd, want we hadden aan de variabele voorbeeld de waarde 97 toegekend.
Nu is het zo dat letters en andere afdrukbare tekens intern in de computer ook weergegeven worden als getallen. Elke letter heeft zijn eigen code. Deze code noemt men de ASCII-code (American Standard Code for Information Interchange). Zo heeft de letter 'a' de waarde 97, de letter 'b' de waarde 98, 'c' heeft de waarde 99, enz.
De hoofdletter 'A' is 65, 'B' is 66, enz.
Omdat een char in 1 byte wordt opgeslagen, kan hij 256 verschillende tekens vertegenwoordigen. Meer dan genoeg voor alle letters, hoofdletters, cijfers en leestekens. De cijfers die hier genoemd worden, zijn dan wel te verstaan als de tekens, bijvoorbeeld het teken '5' en niet de waarde 5.

We hebben dus al 2 conversiespecificaties gezien: %d en %c. Tussen het % en de letter d en c kan nog een cijfer voorkomen, dat de veldbreedte bepaalt. Probeer eens het programma te draaien met volgende regel:

  printf("%8c\n", voorbeeld);


De letter 'a' zal nu afgedrukt worden, maar 8 posities opgeschoven naar rechts:

       a

Ook voor floating-point getallen (kommagetallen) bestaan conversiespecificaties:

%f zal een getal als floating-point getal afdrukken.
%e zal een getal in de wetenschappelijke notatie afdrukken. (ook %E doet dit)

Tussen de % en de f of de e kan je ook de veldbreedte opgeven als geheel getal. Bovendien kan je bij %f ook de precisie aangeven:

#include <stdio.h>

main(){
  float pi = 3.14159;
  printf("%10.3f\n", pi);
}
Dit drukt 3.142 af op een veldbreedte van 10. Dus de .3 specifieert de gewenste precisie. Indien niets gespecifieerd wordt, wordt een precisie van 6 genomen.

Er zijn veel mogelijkheden, met printf(). De lijst van argumenten hoeft niet beperkt te zijn tot 2: je kan in één aanroep van printf() verschillende variabelen laten afdrukken op het scherm:

#include <stdio.h>

main(){
char voorbeeld = 99;
int getal = 1009;
  float pi = 3.14159;
  printf("%c%d%10.3f\n", voorbeeld, getal, pi);
}

zal de volgende uitvoer geven:
c1009        3.142

Het char voorbeeld wordt als een char ('c') gedrukt, het int getal als een integer en de float pi op een veldbreedte 10 en met precisie 3.

Je kan ook spaties opnemen in de conversiespecificatie:
 
  printf("%c %d%10.3f\n", voorbeeld, getal, pi);

geeft volgende uitvoer (met een spatie tussen c en 1009):
c 1009        3.142

Je kan ook newlines opnemen in de conversiespecificatie:
 
  printf("%c\n%d%\n10.3f\n", voorbeeld, getal, pi);

geeft volgende uitvoer:
c
1009
        3.142
       
Er zijn nog andere conversiespecificaties, maar met de kennis uit dit stuk kan je al heel wat. Tekst zullen we later behandelen, omdat we daarvoor nog enkele andere zaken moeten zien.

In het volgende stuk gaan we een interactief programma schrijven: we gaan invoer van de gebruiker vragen en daar iets mee doen.
« Laatst bewerkt op: 2009/04/13, 20:13:29 door idefix »
Support bacteria. They're the only culture some people have.

Offline profoX

  • Lid
    • wesley
    • Lionslink
Re: Beginnen met C
« Reactie #8 Gepost op: 2009/04/13, 20:27:46 »
Leuk. Ik zou ook wel even %g vermelden als format specifier. Veel personen schijnen het bestaan hiervan niet te weten, terwijl het een zeer handige format specifier is om kommagetallen weer te geven
Human Knowledge Belongs To The World -- Antitrust (2001)
Nederlandstalige Ubuntu documentatie van Ubuntu-NL (wiki)

Offline idefix

  • Lid
Re: Beginnen met C
« Reactie #9 Gepost op: 2009/04/13, 20:47:03 »
Dank je wel, profoX  :D

%g neemt de kortste van het e-formaat en het f-formaat (de computer kiest zogezegd)

Er is ook nog een

%G:  neemt de kortste van het E-formaat en het f-formaat.

Nog een tip: experimenteer!  Schrijf zelf een programma om dit uit te proberen. Doen en fouten maken is de beste manier om iets te leren!

Support bacteria. They're the only culture some people have.

Offline idefix

  • Lid
Re: Beginnen met C
« Reactie #10 Gepost op: 2009/04/14, 20:50:06 »
Invoer van de gebruiker.

Tot dusver hebben onze programma's nog niet veel nuttigs gedaan, behalve iets afdrukken op het scherm. In C bestaat er ook een functie om invoer van de gebruiker op te slaan in een variabele. Deze functie heet scanf().

Voor we deze functie bekijken, moet ik eerst iets zeggen over adressen. Het geheugen van een computer bestaat uit miljoenen, soms zelfs miljarden bytes. Als we een variabele declareren (bijvoorbeeld een int getal, dan zit deze variabele ergens in het geheugen. Hoe weet nu de computer waar hij precies getal opgeborgen heeft?
Elke byte van het geheugen heeft een uniek nummer, ofwel adres. De computer houdt bij waar hij elke variabele opgeborgen heeft, m.a.w. hij houdt het adres van elke variabele bij. Je kan het adres van een variabele gemakkelijk oproepen door de adres-operator &:

#include <stdio.h>

main()
{
int getal = 1000;
printf("Het getal is %d\nHet adres van getal is %d\n", getal, &getal);
}

In de printf() zie je eerst en vooral dat er in de conversiespecificatie tekst is opgenomen. Dit is geen enkel probleem.
Het gaat hier echter om het laatste argument: &getal. Dit is het adres van de variabele getal. Aan de conversiespecificatie zie je dat dit adres als een integer wordt weergegeven. Bij mij geeft dit programma de volgende uitvoer:

1000
Het adres van getal is -1077941152

Wellicht is het adres bij jou iets anders, maar je zal ook een geheel getal zien, het actuele adres van de variabele.

Nu we weten wat een adres is, kunnen we de functie scanf() bekijken.

Scanf() lijkt qua opzet op printf(). De functie kan ook meerdere argumenten meekrijgen. Het eerste argument is ook een conversiespecificatie, dat aangeeft of de gebruiker een geheel getal of een kommagetal of een teken of iets anders invoert.
De andere argumenten zijn adressen van variabelen.
Laten we eens een voorbeeld bekijken met twee argumenten.

#include <stdio.h>

main(){
int getal_1;
printf("Geef een geheel getal:");
scanf("%d", &getal_1);
printf("Het ingegeven getal was: %d\n", getal_1);
}

In dit voorbeeld wordt een int gedeclareerd met de naam getal_1.
Nadien wordt een zin op het scherm gezet met de vraag een geheel getal in te voeren.
Dan komt scanf(): de conversiespecificatie "%d"zorgt ervoor dat het ingevoerde geïnterpeteerd wordt als een geheel getal.
De analogie met de conversiespecificatie van printf() zal wel duidelijk zijn. Het tweede argument is het adres van onze variabele getal_1. Op dat adres wordt de waarde 3 opgeborgen. De laatste printf() bevestigt dat op het adres van de variabele getal_1 daadwerkelijk de waarde 3 staat, m.a.w. dat getal_1 inderdaad de waarde 3 heeft.

Nu een ander voorbeeld, waarbij niet om een getal, maar om een karakter gevraagd wordt.

#include <stdio.h>

main(){
char teken;
printf("Typ een karakter in: ");
scanf("%c", &teken);
printf("Het ingetypte karakter was: %c\n", teken);
}

Dus de conversiespecificatie "%c" dwingt de functie scanf() de invoer als karakter te nemen.

De andere conversiespecificaties zijn:

%f : float
%lf : double
%Lf : long double

In één aanroep van scanf() kunnen meerder variabelen ingevoerd worden:

char teken1, teken2;
int getal;
printf("Typ twee karakters en een integer in: ");
scanf("%c%c%d", &teken1, &teken2, &getal);

In dit voorbeeld zie je dat je ook 2 variabelen van hetzelfde type na elkaar kunt declareren, gescheiden door een komma.

Veel kunnen onze programma's nog niet. Ze kunnen variabelen declareren, er een waarde aan toekennen, invoer accepteren en iets afdrukken op het scherm. In het volgende stukje gaan we leren hoe we een programma beslissingen kunnen laten nemen.

Support bacteria. They're the only culture some people have.

Offline idefix

  • Lid
Re: Beginnen met C
« Reactie #11 Gepost op: 2009/04/15, 19:37:44 »
Beslissingen

We kunnen programma's beslissingen laten nemen op basis van vergelijkingen. De basisvorm van een beslissing is altijd:
ALS aan een voorwaarde voldaan is, doe iets
en ANDERS doe iets anders.
als in het Engels is if. anders in het Engels is else.
Dit zijn sleutelwoorden in C. Ze worden gebruikt om beslissingen te nemen:

#include <stdio.h>

main(){
int getal;
printf("Typ een getal in (0-10):");
scanf("%d", &getal);
if (getal > 10){
printf("Het ingetypte getal was te hoog\n");
printf("Het programma wordt beeïndigd.");
}
else {
printf("Het ingetypte getal was: %d\n", getal);
}
}

De eerste 3 regels van main() moeten bekend voorkomen. Er wordt een waarde gevraagd tussen 0 en 10 en die wordt in een int getal gestopt.
De regel
if (getal > 11){
kijkt of de waarde van getal kleiner is dan 11. Er was namelijk gevraagd om een getal tussen 0 en 10. De vergelijking zelf staat tussen haakjes. Dan wordt er een nieuw blok gevormd door de accolade { te openen. Alles wat tussen deze accolade en zijn sluit-accolade staat, wordt uitgevoerd als aan de voorwaarde uit de vergelijking voldaan is (in dit geval de twee printf()'s). Na de sluitaccolade volgt een else, weer met een blok (tussen accolades). Dit blok wordt uitgevoerd als niet aan de vergelijking voldaan is.
Een else is niet noodzakelijk. if kan ook alleen voorkomen.

Je ziet dat bepaalde regels naar rechts inspringen en dat bepaalde regels meer inspringen dan andere. Dit heet indentatie en wordt gedaan om de leesbaarheid van een programma te verhogen: alles wat tot eenzelfde blok behoort, staat op dezelfde "hoogte". Alles wat in de main() staat, staat naar rechts ingesprongen. Binnen het main-blok, zijn er nog twee blokken: een if- en een else-blok: binnen deze blokken wordt nogmaals ingesprongen. Zo zie je in een oogopslag tot welk blok een regel behoort.
Ik gebruik graag indentatie van 2 spaties, maar je kan ook meer spaties gebruiken,zoals hier op het forum worden 8 spaties genomen. De meeste editors laten de indentatie bepalen in hun instellingen.
 
De vergelijking van een if-statement is ook niet beperkt tot "als iets groter is dan". De volgende vergelijkingsoperatoren zijn geldig:

>  : groter dan
>= : groter dan of gelijk aan
<  : kleiner dan
<= : kleiner dan of gelijk aan
== : is gelijk aan
!= : is niet gelijk aan

Let op: een veel voorkomende fout is het gebruik van een enkel = in een if-statement:

int a = 10;
if (a = 10){
...
};

Dit is fout, omdat de = niet mag gebruikt worden om te vergelijken. Juist is dus:
int a = 10;
if (a == 1){
...
}

Je moet hier echt mee opletten, want
int a = 10;
if (a = 10){
...
};
zal geen foutmelding opleveren. Wat er gebeurt is het volgende: de uitdrukking tussen haakjes is een toekenning van een waarde aan een variabele. Dus hier krijgt a de waarde 10. Nadien wordt deze uitdrukking geëvalueerd op waar of onwaar. Nu is het in C zo dat een toewijzingsexpressie altijd waar is. Dus het programmafragmentje hierboven is niet in strijd met de syntax-regels van C (de compiler zal niet klagen over een fout), maar het zal niet het resultaat leveren dat verwacht werd.
 

In plaats van:

if (getal > 10){
hadden we ook kunnen schrijven:

if (getal >= 11){
Nog een voorbeeld met volgende structuur:

if ...
else if ...
else ...

Je kan na een if verschillende else if plaatsen. Dit voorbeeld eindigt bovendien met een gewone else. Maar in die laatste else zit nog eens een if-statement. Dit heet een genest if-statement. Men kan if's nesten tot op vele niveaus, maar let wel dat de bijhorende else's bij de juiste if's passen. Hierbij komt indentatie heel goed van pas:

#include <stdio.h>

main(){
int getal;
printf("Typ een getal in (0-10):");
scanf("%d", &getal);
if (getal > 10){
printf("Het ingetypte getal was te hoog\n");
}
else if (getal < 5) {
printf("U hebt een buis: %d op 10\n", getal);
}
else {
printf("U bent geslaagd met %d op 10!\n", getal);
if (getal == 10){
printf("U heeft zelfs het maximum. Bravo!\n");
}
}
}

Als een blok uit een enkel statement bestaat, zijn accolades niet noodzakelijk:

if (a == 1)
printf("a is gelijk aan 1");

Als men zo werkt, kunnen bij geneste en /of opeenvolgende if-else statements verwarrende situaties ontstaan: is de volgende code juist?

if (a == 1)
if (b == 2)
printf("a is gelijk aan 1 en b is gelijk aan 2");
else
printf("a is gelijk aan 1 en b is ongelijk aan 2");

Of is dit juist?

if (a == 1)
if (b == 2)
printf("a is gelijk aan 1 en b is gelijk aan 2");
else
printf("a is ongelijk aan 1");

Dit laatste voorbeeld is niet juist. Een else hoort steeds bij de dichtstbijstaande if. Dus ook als a gelijk is aan 1 en b niet gelijk aan 2, zal dit afdrukken dat a ongelijk is aan 1.

Met accolades kan het laatste voorbeeld toch afgedwongen worden:
if (a == 1){
if (b == 2)
printf("a is gelijk aan 1 en b is gelijk aan 2");
}
else
printf("a is ongelijk aan 1");

Ik wil nog vermelden dat er naast gelijkheidsoperatoren ook logische operatoren kunnen voorkomen in een if():

!   : logische niet
&&: logische en
||: logische of

Dus:

if (!(a==1))is het zelfde als
if (a!=1)
if ((a==1)&&(b==2))gaat na of a gelijk is 1 EN b gelijk is aan 2. Aan beide voorwaarden moet voldaan zijn.

if ((a==1)||(b==2))gaat na of a gelijk is 1 OF b gelijk is aan 2. Aan één van beide voorwaarden moet voldaan zijn.


Er zijn naast if ... else nog andere manieren in C om beslissingen te nemen. Daar gaan we in het volgende stukje verder op in.
« Laatst bewerkt op: 2009/04/15, 19:43:48 door idefix »
Support bacteria. They're the only culture some people have.

Offline Joshua822

  • Lid
Re: Beginnen met C
« Reactie #12 Gepost op: 2009/04/16, 10:42:08 »
Is dit topic ook voor ( domme ) beginnersvragen ?

Trouwens, je kunt beter direct een taal leren volgens de standaard. Dus inplaats van main() int main(void) en ook aan het besturingssysteem terugschuiven of de operatie succesvol was met return 0;

Offline idefix

  • Lid
Re: Beginnen met C
« Reactie #13 Gepost op: 2009/04/16, 13:49:22 »
Is dit topic ook voor ( domme ) beginnersvragen ?

Trouwens, je kunt beter direct een taal leren volgens de standaard. Dus inplaats van main() int main(void) en ook aan het besturingssysteem terugschuiven of de operatie succesvol was met return 0;

Joshua, er zijn geen domme vragen. En beginnersvragen kun je gerust stellen.

Wat betreft uw opmerking over de standaard:
Dank je wel Profox, maar ik wou deze tutor stappeke voor stappeke maken. Ik wou dit concept introduceren na het bespreken van fucties en return, omdat de "oude" manier ook nog werkt. De meeste compilers laten dit toe omdat het zo ingeburgerd was. Maar je hebt gelijk dat het niet meer de ANSI-standaard is.

Maar als ik iets fouts zeg, alsjeblieft, verbeter mij.

Ik wil nu nog een stuk over switch, dan één over operatoren, dan over loops. En dan over functies. Dan ga ik ook uitleggen waarom int main() gebruikt moet worden. Maar mijn hoofdbekommernis is dat het stap-voor-stap gaat.
Support bacteria. They're the only culture some people have.

Offline Joshua822

  • Lid
Re: Beginnen met C
« Reactie #14 Gepost op: 2009/04/16, 17:19:33 »
Oké dan, dan zal ik maar eens één van mijn beginner vragen ophoesten :P

Citaat
#include <stdio.h>

int main(void){

float *pointer = malloc( sizeof(*pointer) );
float x = 3.14;
pointer = &x;
printf("%f1.2", pointer);
getchar();
free( pointer );
return 0;

}

Bij deze lijn gaat het mis :

float *pointer = malloc( sizeof(*pointer) );

Ik krijg de volgende error als ik het wil compileren :

point.c:5: warning: incompatible implicit declaration of built-in function ‘malloc’

Wat is hier mis ? Ik ben nog redelijk nieuw met dit pointer gedoe in low level talen.


Offline track

  • Lid
Re: Beginnen met C
« Reactie #15 Gepost op: 2009/04/16, 18:17:15 »
Volgens mij moet je  "malloc( sizeof(*pointer) );"  zetten.
(-> http://en.wikipedia.org/wiki/Sizeof )
Jouw commando zou de grootte van de pointer zelf (hoe veel bytes een geheugen-adres vraagt dus) opleveren.

track

Offline idefix

  • Lid
Re: Beginnen met C
« Reactie #16 Gepost op: 2009/04/16, 18:29:54 »
Meer over beslissingen

Als er veel else if's voorkomen, na een if-statement, kan het handiger zijn een switch-statement te gebruiken.
Deze switch evalueert een variabele en gaat dan geval per geval (case per case) kijken wat moet gebeuren:

#include <stdio.h>

main(){
int getal;
printf("Typ een getal in (0-10):");
scanf("%d", &getal);
switch (getal){
case 0:
printf("U haalde helaas nul punten. Slechter kan niet.\n");
break;
case 1: case 2: case 3: case 4:
printf("Onvoldoende! Gebuisd!\n");
break;
case 5: case 6:
printf("U bent geslaagd met de hakken over de sloot.\n");
break;
default:
printf("U bent goed geslaagd. Proficiat.\n");
}
}

het statement switch(getal) bekijkt de waarde van getal. Dan wordt door de accolade een blok geopend, meer bepaald een switch-blok, waarin de verschillende cases worden behandeld.
Na het printf() volgt een break-statement. Door deze break wordt het switch-blok verlaten. Als we namelijk de waarde 0 hadden, hoeven we niet meer verder te zoeken naar andere cases.

In de regel
case 1: case 2: case 3: case 4:
zie je dat verschillende cases kunnen gecombineerd worden, gescheiden door een :
Ook hier wordt het case afgesloten door een break-statement.

Dan volgen nog een gelijkaardige case 5: en case 6: en dan komen we bij default:. Dit duidt op alle andere gevallen. In dit voorbeeld had hier dus ook kunnen staan:
case 7: case 8: case 9: case 10:
Na een default staat geen break-statement. De default is hoe dan ook het laatste van een switch-blok. Nadien wordt het switch-blok sowieso verlaten. Er mag ook maar één default staan in een switch-blok.

Een switch kan leesbaarder zijn dan een if... else if ... else if.... maar je kan je steeds met if ... behelpen.

Een belangrijke beperking van switch is dat de te evalueren expressie een geheel getal moet zijn. Dit kan echter, behalve een int, short of long ook een char zijn:

#include <stdio.h>

main(){
char letter;
printf("Typ een letter in:");
scanf("%c", &letter);
switch (letter){
case 'a':
printf("U gaf a op\n");
break;
case 'b': case 'c':
printf("U gaf b of c op\n");
break;
case 'd': case 'e':
printf("U gaf d of e op.\n");
break;
default:
printf("U gaf een letter groter dan de e.\n");
}
}

Uit deze twee voorbeelden blijkt nogmaals duidelijk het verschil tussen de conversiespecificaties "%d" en "%c".

Er bestaat ook nog een conditionele operator ?:. Zijn gebruik kan best verduidelijkt worden met een voorbeeld:

int a,b, x;
a = 10;
b = 20;
x = 0;
x = (a < b)? a:b;

De laatste regel kent aan x een waarde toe:

x =

Welke waarde precies hangt af van de test:

(a < b)?

Als aan de voorwaarde tussen haakjes voldaan wordt, krijgt x de waarde van de variabele voor het dubbelpunt (hier dus a). Anders krijgt x de waarde van de variabele achter het dubbelpunt (hier dus b). Infeite kan deze ene regel herschreven worden als een gewoon if...else:

if (a < b)
x = a;
else
x = b;

Deze code is leesbaarder dan de vorige, die echter minder typwerk vraagt.
Je kan natuurlijk vrij kiezen om de conditionele operator wel of niet te gebruiken, omdat je steeds de mogelijkheid hebt een if...else te gebruiken.

De conditionele operator is de enige die 3 expressies als operanden heeft:

x = uitdrukking1 ? uitdrukking2 : uitdrukking3

Daarom heet de conditionele operator een ternaire operator, tegenover een unaire operator (met 1 operand) en een binaire (met twee operanden) operator.

Van die laatste twee gaan we in het volgende stukje wat meer voorbeelden zien.
 
« Laatst bewerkt op: 2009/04/16, 18:34:55 door idefix »
Support bacteria. They're the only culture some people have.

Offline idefix

  • Lid
Re: Beginnen met C
« Reactie #17 Gepost op: 2009/04/16, 18:59:21 »
Oké dan, dan zal ik maar eens één van mijn beginner vragen ophoesten :P

Citaat
#include <stdio.h>

int main(void){

float *pointer = malloc( sizeof(*pointer) );
float x = 3.14;
pointer = &x;
printf("%f1.2", pointer);
getchar();
free( pointer );
return 0;

}

Bij deze lijn gaat het mis :

float *pointer = malloc( sizeof(*pointer) );

Ik krijg de volgende error als ik het wil compileren :

point.c:5: warning: incompatible implicit declaration of built-in function ‘malloc’

Wat is hier mis ? Ik ben nog redelijk nieuw met dit pointer gedoe in low level talen.


Je maakt een paar fouten:
1. om malloc() te kunnen gebruiken, heb je stdlib.h nodig:
#include <stdlib.h>
Maar eigenlijk heb je malloc() hier zelfs helemaal niet nodig. Je maakt gewoon een pointer naar float, geeft een waarde aan die pointer. Malloc() is voor dynamische geheugenallocatie, en dat is geen beginners-gedoe (met alle respect): dit wordt hoofdzakelijk gebruikt in geschakelde lijsten e.d.

2. In je printf() zet je als conversiespecificatie "%f1.2". Dit is fout. Het moet zijn: "%1.2f": dus de veldbreedte en aantal decimalen moeten tussen % en f

3. Bovendien laat je de printf()  pointer afdrukken en niet de waarde van de variabele x, waar pointer naar wijst. Als je dit wilt doen, moet je de pointer dereferencen door er een * voor te zetten: *pointer
Als je printf("%d", pointer); doet, zal het adres geprint worden.

free() hebben we niet nodig als we malloc niet gebruiken.

Probeer dit eens:
#include <stdio.h>

int main(void){
float *pointer;
float x = 3.14;
pointer = &x;
printf("%1.2f", *pointer);
return 0;
}

PS: Misschien is het beter een apart topic te openen als je een vraag hebt. Dan kan dit topic een soort mini-cursus worden.
« Laatst bewerkt op: 2009/04/16, 19:02:20 door idefix »
Support bacteria. They're the only culture some people have.

Offline idefix

  • Lid
Re: Beginnen met C
« Reactie #18 Gepost op: 2009/04/17, 09:43:41 »
Operatoren

We hebben nu al verschillende soorten operatoren gezien:

vergelijkingsoperatoren: <, <=, >, >=, ==, !=
logische operatoren: &&, ||, !
de toewijzingsoperator: =

Er bestaan nog andere types operatoren:

de rekenkundige: +, -, *, /, %  (optellen, aftrekken, vermenigvuldigen, delen, modulo of rest-operator)

Een voorbeeld:

#include <stdio.h>

main(){
int a = 0;
int b = 10;
int c = 6;

a= b - 6;               /* a is nu 4 */
printf ("%d\n", a);
b = a * c;              /* b is nu 24 */
printf ("%d\n", b);
b = b - 2;              /* b is nu 22 */
printf ("%d\n", b);
a = b / 6;          /* b is nu 3, het geheel getal dat men krijgt door gehele deling van 22 door 6 */
printf ("%d\n", a);
a = b  % 6;             /* a is nu 4, de rest die men krijgt bij gehele deling van 22 door 6 */
printf ("%d\n", a);
}

Een opmerking over de stukjes tekst tussen /* en */: dit heet commentaar. Alles wat tussen /* en */ wordt door de compiler genegeerd. Commentaar dient om dingen te verklaren, voor jezelf en ook voor derden die je code willen lezen.

De regel

b = b -2;

kan eigenaardig overkomen. Je moet hem lezen als: "Ken aan b de waarde toe die b nu heeft minus twee". Deze regel kan ook in verkorte vorm geschreven worden:

b -= 2;

Hierin is -= dus infeite ook een toekenningsoperator, want hij kent een waarde toe aan een variabele.
Analoog hebben we ook: +=, *=, /=, %=. Bijvoorbeeld:

int b = 12;
b += 2;     /* b zal nu 14 zijn */
b *= 2;     /* b zal nu 28 zijn */
b /= 4;     /* b zal nu 7 zijn */
b %= 3;     /* b zal nu 1 zijn, de rest die je krijgt als 7 door 3 deelt */

Er bestaan nog een unaire operator -: die doet hetzelfde als - in de wiskunde:

int a = 12;
int b = 0;
b = -a;  /* b zal nu -12 zijn */

Handelingen als 1 ergens bij optellen of ergens van aftrekken, komen zoveel voor dat men er aparte operatoren voor gemaakt heeft (unair): ++ en --:

int a = 12;
a++;  /* a zal nu 13 zijn */
++a;  /* a zal nu 14 zijn */

De verhogingsoperatoren kunnen dus zowel voor als na de variable staan (prefix: voor en postfix: na). Hier moet men rekening houden met een belangrijke nuance:

int a, b, c = 0;
a = ++c;  /* prefix: eerst wordt c verhoogd met 1, daarna wordt die waarde toegekend aan a */
b = c++;  /* postfix: b krijgt eerst de waarde van c toegekend, nadien wordt de waarde van c met 1 verhoogd */

Na dit stuk code hebben zowel a als b de waarde 1 en heeft c de waarde 2.

Het volgende stukje zal gaan over lussen, waar we echt mee kunnen automatiseren.

« Laatst bewerkt op: 2009/04/17, 11:51:36 door idefix »
Support bacteria. They're the only culture some people have.

Offline idefix

  • Lid
Re: Beginnen met C
« Reactie #19 Gepost op: 2009/04/17, 15:26:51 »
Lussen (loops)

De kracht van programmeren zit hem ten dele in het feit dat je een variabele verschillende waarden kunt laten aannemen.
Een ander aspect is dat je bepaalde taken die herhaald moeten worden, niet steeds opnieuw hoeft te schrijven. Je kan ze opnemen in een herhalingslus. Om maar meteen een voorbeeld te geven: stel dat je voor straf 10 x moet schrijven "Ik zal braaf zijn". In C kun je dat zo doen:

#include <stdio.h>
main(){
int i = 0;
for(i = 0; i < 10; i++){
printf("Ik zal braaf zijn\n");
}
}

We makken een int i, die we dan als een teller (counter) in een for-lus (for-loop) stoppen. De for-loop bestaat uit 3 delen, gescheiden door een puntkomma:

de initialisatie van de teller: i = 0
de controle-vergelijking: zolang hieraan voldaan is, wordt het for-blok (tussen de accolades) uitgevoerd: i < 10.
de opteller: deze verhoogt de teller met 1: i++

Bij een eerste keer dat we door de lus lopen ziet de situatie er zo uit:
1. De teller wordt op 0 gezet (enkel bij de eerste doorgang door de lus)
2. Is 0 < 10 ? Ja, dus het blok wordt uitgevoerd (het printen van "Ik zal braaf zijn")
3. De teller wordt met 1 verhoogd.

De tweede doorgang gaat als volgt (i is nu gelijk aan 1):
1.  Is 1 < 10 ? Ja, dus het blok wordt nogmaals uitgevoerd.
2. De teller wordt met 1 verhoogd en komt op 2 te staan.

De derde doorgang verloopt gelijkaardig (i is nu echter gelijk aan 2)
1.  Is 2 < 10 ? Ja, dus het blok wordt nogmaals uitgevoerd.
2. De teller wordt weer met 1 verhoogd en komt op 3 te staan.

Dit gaat zo door tot de laatste keer als i = 10. Dan voldoet i niet meer aan de controle-vergelijking en wordt de lus onmiddellijk gestopt:
10 < 10 ? Neen, dus STOP.

Je kan een lus grotere stappen laten nemen dan +1:

#include <stdio.h>
main(){
int i = 0;
for(i = 0; i < 10; i += 2){
printf("%d\n", i);
}
}

In dit stukje zie je dat de teller-variabele ook in het blok mag gebruikt worden. De teller is trouwens niet beperkt tot integers:

#include <stdio.h>
main(){
float f = 0;
for(f = 10; f > 0; f -= 0.5){
printf("%f\n", f);
}
}

In dit stukje zie je ook dat de teller een andere waarde dan 0 mag hebben. De voorwaarde is ook anders en als je naar omlaag telt, moet je de teller verminderen.

Met lussen kun je dus dingen automatiseren. Stel dat je de som moet nemen van de eerste 43 gehele getallen:

#include <stdio.h>
main(){
int i;
int som = 0;
for(i = 1; i <= 43; i++){
som += i;
}
printf("De som is %d\n", som);
}

Een andere herhalingslus is de while-lus. Deze ziet er zo uit:

while (voorwaarde)
   doe iets
   
Zolang aan de voorwaarde voldaan wordt, wordt het while-blok uitgevoerd:

#include <stdio.h>
main(){
int i = 0;
int som = 0;
while (i <= 43){
som += i;
i++;
}
printf("De som is %d\n", som);
}

Dit programma doet exact hetzelfde als het vorige, maar met een while-lus. We moeten er dan wel op letten dat we de teller vooraf een waarde geven (i = 0), en dat we hem in het while-blok ook verhogen.

Een variant van de while-lus is de do...while-lus:

#include <stdio.h>
main(){
int i = 1;
int som = 0;
do {
som += i;
i++;
} while (i <= 43);
printf("De som is %d\n", som);
}

Hier staat de voorwaarde na het uit te voeren blok.
Support bacteria. They're the only culture some people have.

Offline idefix

  • Lid
Re: Beginnen met C
« Reactie #20 Gepost op: 2009/04/17, 18:10:04 »
Functies

Een van de grootste voordelen van programmeren is dat je code kunt herbruiken. Stel dat je een rechthoek op het scherm wil tekenen. We kunnen dit doen met de functie printf(). Bijvoorbeeld een rechthoek van 12 op 5 sterretjes kunnen we opvatten als 5 rijen van 12 sterretje onder elkaar. 5 keer hetzelfde herhalen vraagt om een for-lus:

#include <stdio.h>
main(){
int i = 0;
for (i = 0; i < 5; i++){
printf("%c%c%c%c%c%c%c%c%c%c%c%c\n",'*','*','*','*','*','*','*','*','*','*','*','*');
}
}

Deze code zal een mooie rechthoek op het scherm zetten. Ik vind de printf() zelf voor verbetering vatbaar. Uiteindelijk doen we hier ook 12 keer hetzelfde. Dit moet in een for-lus kunnen:

#include <stdio.h>
main(){
int i, j = 0;
for (i = 0; i < 5; i++){
for(j = 0; j < 12; j++){
printf("%c",'*');
}
printf("%c", '\n');   /*telkens we 12 * gedrukt hebben, springen we naar de volgende regel */
}
}

Dit is dus een for-lus binnen een for-lus. Men spreekt ook van een geneste for-lus. De buitenste lus zorgt ervoor dat de binnenste lus 5 keer herhaald wordt.

Stel nu dat we binnen dit programma meer dan eens een rechthoek willen tekenen. Dan moeten we elke keer die twee for-lussen typen. Het zou handig zijn moesten we dat kunnen omzeilen.
Hier komen functies op het toneel. Een functie is een stukje code dat je kan aanroepen zo veel als je wil. In ons voorbeeld zou het zinvol zijn als we onze functie rechthoek() zouden noemen. De twee haakjes duiden aan dat het om een functie gaat. Een programma met een functie rechthoek(), die tweemaal aangeroepen wordt, ziet er dan zo uit:

#include <stdio.h>

void rechthoek();

main(){
rechthoek();
rechthoek();
}

void rechthoek(){
int i, j = 0;
for (i = 0; i < 5; i++){
for(j = 0; j < 12; j++){
printf("%c",'*');
}
printf("%c", '\n'); 
}
}

Op de derde lijn wordt een functie gedeclareerd met de naam rechthoek(). Tevens wordt door het woord void ervoor te zetten aangegeven dat deze functie geen waarde aflevert. Sommige functies kunnen een waarde afgeven als resultaat van een bewerking (straks daarover meer). Onze functie rechthoek() levert echter geen waarde af, maar tekent een rechthoek.
Deze lijn declareert enkel een functie, ze zegt nog niets over wat deze functie moet doen. De functiedefinitie volgt na het main()-blok.

Je ziet dat de functiedefinitie ook bestaat uit het aflevertype (void), de naam (rechthoek), twee haakjes en een accolade.
Alles wat tussen deze accolade en de laatste accolade staat, behoort tot deze functie. In de "body" van de functie (dus tussen de accolades) zit de functionaliteit om de rechthoek te tekenen.

Je ziet dat er variabelen gedeclareerd worden binnen de functie. Het is belangrijk te beseffen dat deze variabelen enkel bestaan binnen deze functie. Je kan bijvoorbeeld de waarde van i of j niet laten afdrukken vanuit main(), simpelweg omdat die i en j daar niet bestaan. Je kan trouwens een int i declareren binnen main(), maar dat zal dan een andere variabele zijn dan de i uit de functie rechthoek().

In het main()-blok wordt de functie rechthoek() tweemaal aangeroepen.

Onze functie doet wel wat ze moet doen (rechthoeken tekenen), maar echt flexibel is ze niet. Het zou mooi zijn, mochten we de lengte en breedte bij iedere aanroep kunnen opgeven. Het zou leuk zijn, moesten we kunnen zeggen:

main(){
rechthoek(12, 5);
rechthoek(4, 9);
}

Dit is mogelijk door de functie zo te declareren dat ze parameters aanvaardt. Dit gebeurt als volgt:

void rechthoek(int lengte, int breedte);

Hiermee geven we aan dat we binnen de functie twee variabelen gaan gebruiken, lengte en breedte, die hun waarde krijgen bij de aanroep van de functie. De functiedefinitie zelf ziet er zo uit:

void rechthoek(int lengte, int breedte){
int i, j = 0;
for (i = 0; i < breedte; i++){
for(j = 0; j < lengte; j++){
printf("%c",'*');
}
printf("%c", '\n'); 
}
}


We  kunnen de functie nog flexibeler maken door ook het af te drukken teken op te nemen in de parameterlijst. Het volledige programma ziet er dan zo uit:

#include <stdio.h>

void rechthoek(int lengte, int breedte, char teken);

main(){
rechthoek(12,5, '#');
rechthoek(5,3, 'O');
}
void rechthoek(int lengte, int breedte, char teken){
int i, j = 0;
for (i = 0; i < breedte; i++){
for(j = 0; j < lengte; j++){
printf("%c", teken);
}
printf("%c", '\n'); 
}
}

De volgorde van de parameters is belangrijk. Je moet een functie steeds aanroepen met de parameters in de volgorde waarin de functie ze verwacht. Dus in dit geval zou de volgende aanroep fout geweest zijn:

rechthoek('#',12, 5);


Als een functie geen parameters krijgt, schrijft men void ook tussen de haken. Dus onze eerste functie rechthoek() had er zo moeten uitzien:

void rechthoek(void);
Deze code zegt dat de parameterlijst leeg is (void). Ook is de afleverwaarde leeg, m.a.w. de functie levert niets af.
Stel dat wij een functie willen schrijven die het gemiddelde aflevert van 2 getallen. Deze functie kunnen we best de naam gemiddelde geven. Het is duidelijk dat de functie twee parameters neemt, nl. de getallen waarvan het gemiddelde moet worden genomen. Het resultaat van die functie is het gemiddelde. Dit is de waarde die dus afgeleverd wordt. Stel dat we twee floats als parameter nemen, dan zal de functie ook een float als gemiddelde afleveren:

float gemiddelde (float getal1, float getal2);
In de declaratie van de functie (men spreekt ook wel van het prototype) zien we reeds dat de functie een float zal afleveren.

De functiedefinitie (ook wel implementatie geheten) ziet er zo uit:

float gemiddelde (float getal1, float getal2){
float resultaat;
resultaat = (getal1 + getal2)/2;
return resultaat;
}

We maken een float resultaat die zal afgeleverd worden door de functie. Dit afleveren gebeurt door het return statement.
Omdat deze functie een float aflevert, mag hij aangeroepen worden waar je een float zou mogen schrijven. Het volledige programma:

#include <stdio.h>

float gemiddelde (float getal1, float getal2);

main(){
float a= 3, b= 4, c = 0;
c = gemiddelde (a, b);
printf( "%f\n", c);
}

float gemiddelde (float getal1, float getal2){
float resultaat;
resultaat = (getal1 + getal2)/2;
return resultaat;
}


Op de tweede regel van main() zie je dat c de waarde krijgt die de functie aflevert. Nu zijn we op het punt gekomen waar we de main() op een juiste manier kunnen declareren: main() is namelijk een functie die een integer aflevert. De juiste declaratie is dus:

int main(){
   ...
   return 0;
}
Omdat main() een int aflevert, MOET je een return opnemen in het main()-blok. Als main() een 0 aflevert aan het besturingssysteem, wil dat zeggen dat het programma foutloos beeïndigd is. Elke andere waarde duidt op een fout.

Het feit dat je een main() ook mag declareren zonder return-waarde, komt doordat dat vroeger niet moest. Men ziet het door de vingers omdat anders alle code die vroeger geschreven is, herschreven zou moeten worden.

Zelfs een functie als printf() levert een int, namelijk het aantal afgedrukte karakters.

Bekijk eens goed het volgende programma:

#include <stdio.h>

void test (int n);
int main(){
int i = 0;
printf("i is gelijk aan %d\n", i);
test (i);
printf("i is nog steeds gelijk aan %d\n", i);
return 0;
}

void test (int n){
n += 1;
printf("Binnen de functie is n nu gelijk aan %d\n", n);
}

Als je dit programma draait, krijg je als output:

i is gelijk aan 0
Binnen de functie is n nu gelijk aan 1
i is nog steeds gelijk aan 0

Dat komt omdat de functie test() niet de variabele i meekrijgt maar de waarde van i. Je zou kunnen zeggen dat er een kopie genomen wordt van i, maar dat i zelf onaantastbaar is voor een functie. De functie test mag vanalles doen met de waarde die ze krijgt via haar parameter, ze kan gewoonweg niet raken aan i zelf. In het Engels heet dit systeem call by value.

In het volgende stukje zullen we zien hoe we een variabele toch kunnen veranderen door een functie-aanroep.
« Laatst bewerkt op: 2009/04/17, 18:14:53 door idefix »
Support bacteria. They're the only culture some people have.

Offline idefix

  • Lid
Re: Beginnen met C
« Reactie #21 Gepost op: 2009/04/18, 11:47:41 »
pointers

Dan komen we nu bij één van de zaken, waardoor c zijn populariteit behoudt: pointers.

Zoals je weet, geven wij namen aan variabelen:

float gemiddelde;
int som;

Nu worden deze variabelen ergens op een bepaalde plaats in het geheugen opgeslagen. Het geheugen moet je zien als een enorme kast met een enorm aantal unieke nummers (zoals huisnummers in een straat). Elke byte (weet je nog? 8 bits) in het geheugen heeft zo een uniek adres. Het geheugen moet je je voorstellen als een lange rij bestaande uit bits (1 en 0):

11001011 00001011 11001101 11101100 11010101 ....

Het adres van een variabele kunnen we heel gemakkelijk oproepen door de &-operator (adres-operator):

&gemiddelde
&som

Bijvoorbeeld:

#include <stdio.h>

main(){
int i = 0;
printf("Adres van i: %u\n", &i);
}

Hier wordt het adres van i afgedrukt als unsigned geheel getal.

Een pointer is nu niets anders dan een variabele die het adres van een andere variabele bevat. Een pointer heeft dus ook een type: bijvoorbeeld pointer naar int, pointer naar char,...
Dit is nodig, want het systeem moet niet alleen het adres hebben van de eerste byte, maar ook het aantal bytes waarin de variabele opgeslagen wordt.

Een voorbeeld:

Stel dat een char c gedeclareerd wordt, de waarde 'a' meekrijgt en in het geheugen opgeslagen wordt op adres 8500. Dan kan (een stukje van) het geheugen er zo uit zien:

...    |  8498   |     8499    |     8500    |      8501   |     8502   | ...
     10011010  11001101  01100001  10101011  00011001     
     
Onder het geheugenadres 8500 staat de binaire waarde 0110001: dat is 97 in het decimaal stelsel en dat is precies de ASCII-waarde van het karakter 'a'. De waarden in de voorgaande en volgende blokken spelen geen rol voor onze char, want een char wordt opgeslagen in 1 byte (8 bits).

Als we nu zouden doen:

c = 'b'

dan verandert het adres van onze variabele c niet, maar wel de waarde op dat adres:

... |    8498    |      8499   |      8500   |      8501   |     8502   | ...
     10011010  11001101  01100010  10101011  00011001     
     
Op adres 8500 staat nu 01100010 en dat is 98 of de ASCII-waarde van de letter 'b'.

Als we het volgende intypen:

int i = 5;

Dan kan het geheugen er zo uit zien als het adres 8500 is:
 
...  |    8498   |     8499    |    8500      |   8501     |    8502     |    8503     |     8504      |...
     10011010  11001101  00000000  00000000  00000000  00000100   11001110
     
Een int wordt op de meeste computers opgeslagen in 4 bytes. In het geval van een klein getal zijn 3 bytes dus onbenut;

00000000 00000000 00000000 00000100  is 4 in het binair. Dus je ziet dat het adres 8500 is, maar dat ook 8501, 8502 en 8503 gebruikt worden voor deze variabele.

Voor de volledigheid moet ik ook zeggen dat de meeste computers variabelen andersom opslaan: ik bedoel hiermee in omgekeerde volgorde (dit heet "little endian" om het te onderscheiden van "big endian" uit het vorige voorbeeld):

... |     8498    |    8499     |    8500    |    8501     |    8502     |      8503    |     8504    |...
     10011010  11001101  00000100  00000000  00000000  00000000   11001110
     
Dit maakt wel dat programma's niet zomaar overdraagbaar zijn tussen little endian- en big endian-computers.

We gaan nu een programma met twee pointers declareren:

#include <stdio.h>

int main(){
int i = 10;
int j = 20;
int * p = &i;
int * q = &j;
printf("Waarde van i: %d\n", *p);
printf("Adres van i: %u\n", p);
printf("Waarde van j: %d\n", *q);
printf("Adres van j: %u\n", q);
return 0;

}

Bij mij levert dit de volgende uitvoer (bij jou zijn de adressen wellicht anders):

Waarde van i: 10
Adres van i: 3217026136
Waarde van j: 20
Adres van j: 3217026132

Met de declaratie

int * p = &i;

maak je dus een pointer naar int en stop je er meteen het adres van i in. Je kan dit ook in twee stappen doen:

int * p;
p = &i;

Je kan ook *p schrijven (zonder spatie) om een pointer te declareren.

Het sterretje * in *p in de regel

printf("Waarde van i: %d\n", *p);

is de dereference-operator. Hiermee wordt de waarde verkregen van hetgeen zich op het adres bevindt waar p naar wijst. Dit is dus een heel andere * dan in de declaratie:

int * p = &i;

Het is belangrijk te weten dat deze declaratie  GEEn waarde toekent aan * p, maar aan p. het type van p is namelijk int *, een pointer naar int.

Aan de output kun je zien dat een int in 4 bytes opgeslagen wordt:
Het adres van i is 3217026136. De volgende 3 bytes zijn bezet door i, dus de eerste vrije byte is 3217026132 (we tellen achteruit want we hebben een little endian-machine).

In het stuk over functies had ik gezegd dat je de waarde van een variabele niet kunt veranderen d.m.v. een functie. Dat was dan buiten pointers gerekend, want als je als parameters adressen (pointers) gebruikt, kun je wel de waarden die zich op die adressen bevinden, veranderen:

#include <stdio.h>

void verwissel(int * p, int * q);

int main(){
int i = 10, j = 20;
verwissel (&i, &j);
printf("%d %d\n",i, j);
return 0;
}

void verwissel(int * p, int * q){
int hulpvariabele;
hulpvariabele = *p; /* we stoppen de waarde van *p in hulp, anders gaat ze verloren in de volgende regel  */
*p = *q;            /* *p krijgt nu de waarde van *q        */
*q = hulpvariabele; /* *q krijgt nu de oude wwarde van *p   */
}

In de main()-functie zie je dat de waarden van de variabelen daadwerkelijk veranderd zijn (ze zijn omgewisseld). Dit komt omdat de functie die dit doet, de adressen van de variabelen meegekregen heeft.

De ware kracht van pointers gaan we zien in het volgende stukje, over arrays.
« Laatst bewerkt op: 2009/04/24, 22:12:07 door idefix »
Support bacteria. They're the only culture some people have.

Offline idefix

  • Lid
Re: Beginnen met C
« Reactie #22 Gepost op: 2009/04/24, 22:25:43 »
arrays

Stel dat we als leraar informatica de punten willen bijhouden van de 4e klas. Er zitten 22 leerlingen in die klas.
Dan zouden we 22 variabelen kunnen maken als volgt (punten worden op 10 gegeven en zijn steeds gehele getallen):

int punt1;
int punt2;
int punt3;
...
int punt22;

Of verkort:

int punt1, punt2, punt3, ... punt22;

Dit zijn allemaal variabelen van hetzelfde type. Hier zit dus een zekere vorm van herhaling in. Dat is gesneden brood voor een computer: die gaat met het grootste gemak om met herhalingen (zie wat we gezegd hebben over lussen).
Het is dan ook niet verwonderlijk dat C voorziet in een middel om de punten uit het voorbeeld gemakkelijker te declareren:
we maken een lijst van variabelen met één naam, maar waar we aan elke variabele een volgnummer geven. In het geval van onze punten, zou dat zijn:

int punten[22];
Hiermee declareer je een variabele punten, die een lijst is van 22 int's. De individuele punten zijn nu te bereiken via deze code:

punten[0] = 9;
punten[1] = 6;
punten[2] = 10;
punten[21] = 7;

Je ziet dat we aan het eerste element uit de lijst, de waarde 9 toekennen. Het eerste element heeft altijd volgnummer 0. Een array (zoals zo een lijst in het Engels heet) begint steeds te tellen vanaf 0. Dit heeft ook tot gevolg dat het array loopt tot en met element punten[21]. Tot hier en niet verder. Als we namelijk van 0 beginnen te tellen, dan hebben we bij 21 reeds 22 elementen geteld.

Je zou dus bijvoorbeeld het volgende kunnen schrijven:

int a = punten[0];  /*a zou de waarde 9 krijgen omdat punten[0] = 9 */
int b = punten[21];  /*b zou de waarde 7 krijgen omdat punten[0] = 7 */

Je kan een array ook initialiseren met waarden:

int punten[5] = {8, 9, 6, 8, 7};

Met deze code krijgt het array punten dat bestaat uit 5 elementen meteen beginwaarden:
punten[0] = 8
punten[1] = 9
punten[2] = 6
enzovoort

We hadden ook het aantal elementen kunnen weglaten in bovenstaande declaratie:

int punten[] = {8, 9, 6, 8, 7};

In dergelijke gevallen, wordt het array automatisch zo groot gemaakt dat het alle waarden kan bevatten die het bij zijn declaratie heeft gekregen (in dit geval: 5 elementen)

Je hoeft bij een array-declaratie trouwens niet alle elementen een waarde te geven: in het onderstaande voorbeeld krijgt enkel het eerste element een waarde (9). De andere elementen krijgen automatisch de waarde 0.

int punten[10] = {9};

De kracht van arrays komt zeer goed tot uiting in combinatie met lussen:

#include <stdio.h>

int main(){
int a[10] = {9}, c;
for (c = 0; c < 10; c++)
printf("%d\n", a[c]);
}

In deze lus worden met de uitdrukking a[c] alle elementen uit het array a doorlopen.

Uit het vorige stuk weten we dat * een dereferentie-operator kan zijn (naast de pointer-operator en de vermenigvuldigingsoperator). Als we nu een array a[] hebben dan is a het adres van het eerste element.

p = a; is dus hetzelfde als p = &a[0];

Dit heeft tot gevolg dat a[c] ook kan uitgedrukt worden als *(a+c). Het vorige voorbeeld kunnen we dus als volgt herschrijven:

#include <stdio.h>

int main(){
int a[10] = {9}, c;
for (c = 0; c < 10; c++)
printf("%d\n", *(a+c));
}

De uitdrukking a is dus duidelijk een pointer, want dereferentiëren hem. We hebben op het eerste gezicht nergens expliciet een pointer gedeclareerd. Maar zoals gezegd: a is hier een pointer, namelijk naar het eerste element van het array: a[0]

De uitdrukking a+c is een voorbeeld van pointer-aritmetica (rekenen met pointers). We hoeven hier zelf niet het aantal bytes te kennen dat moet opgeschoven worden: a+1 zal 4 bytes opschuiven als a[] als int gedeclareerd is, of één byte als a[] als char gedeclareerd is, of 8 bytes als a[] een array van doubles is.

Arrays kunnen als argumenten van een functie voorkomen. Als wij de som willen nemen van de elementen van een array kunnen wij volgende functie schrijven:

#include <stdio.h>

int som(int a[], int grootte);
int main(){
int a[10] = {1, 2, 3,4, 5, 6, 7, 8, 9, 10}, totaal;
totaal = som(a, 10);
printf("%d\n", totaal);
}
int som(int a[], int grootte)
{
int  i, som = 0;
for (i = 0; i < grootte; i++)
som += a[i];
return som;
}

Het argument a[] in de functie geeft alleen het adres door van het eerste element van het array. Dit is veel efficiënter dan alle waarden van het array te kopiëren. In feite is dit argument dus een pointer. We kunnen deze functie dan ook zo schrijven:

int som(int * a, int grootte)
{
int  i, som = 0;
for (i = 0; i < grootte; i++)
som += a[i];
return som;
}

Of zo:

int som(int * a, int grootte)
{
int  i, som = 0;
for (i = 0; i < grootte; i++)
som += *(a+i);
return som;
}

Deze functie kan (in al haar versies) op verschillende manieren aangeroepen worden. Ze hoeft zelfs niet de som van alle waarden te nemen. Bijvoorbeeld van de eerste drie elementen. Of van element 7 t.e.m. 9:

totaal = som(a, 10); /* totaal is de som van alle 10 elementen */
totaal = som(a, 3);  /* totaal is de som van de eerste 3 elementen */
totaal = som(&a[6], 3); /* totaal is de som van a[6], a[7] en a[8] = 24 */

In het volgende stuk gaan we verder in op een speciaal soort arrays, namelijk arrays van chars. Dat zijn namelijk zogenaamde strings die tekst kunnen bevatten.
« Laatst bewerkt op: 2009/04/24, 22:29:19 door idefix »
Support bacteria. They're the only culture some people have.

Offline idefix

  • Lid
Re: Beginnen met C
« Reactie #23 Gepost op: 2009/04/27, 19:35:24 »
Strings

Om tekst weer te geven, gebruiken we in C arrays van characters, strings of tekenreeksen genaamd. Deze strings hebben de eigenaardigheid dat ze afgesloten worden door het "nulkarakter": '\0'

Omdat tekst zoveel gebruikt wordt, kunnen strings ook op een speciale manier gedeclareerd worden:

char s[] = {'a', 'b', 'c', '\0'};

is hetzelfde als dit:

char s[] = "abc";

De tweede notatie is veel gemakkelijker te lezen. Let wel op dat "abc" 4 elementen heeft: 'a', 'b', 'c' en '\0'. Het laatste karakter, het nul-karakter sluit de string af. Het wordt echter niet afgedrukt als een string op het scherm gezet wordt.
Omdat strings arrays zijn, kunnen we ook de pointer-notatie gebruiken:

char * p = "abc";
printf(%s %s\n", p, p +1);

De pointer p wijst naar het adres van de 'a' uit de string "abc". In de printf()-aanroep zien we een nieuwe conversiespecificatie: %s. Deze bewerkstelligt dat het argument als een string moet afgedrukt worden. In ons voorbeeld worden dus twee strings afgedrukt: deze die begint bij de 'a' en deze die op het volgende adres begint (bij de 'b'): de uitvoer zal dus zijn: abc bc.

In de header-file string.h staan nog veel functies die met strings werken. Bijvoorbeeld strlen(const char *s) retourneert een unsigned int, de lengte van de string (zonder '\0'):

#include <stdio.h>
#include <string.h>

int main(){
char * s = "azerty";
int i = strlen(s);
printf("%s bevat %d tekens.\n", s, i);
}

De const in het functie-prototype is de constant-modifier: deze zorgt ervoor dat het argument niet kan veranderd worden. Dit is dus een veiligheid voor onbedoelde verandering en tegelijk een verduidelijking naar lezers van het programma.

In een string kunnen escape-sequences voorkomen. Stel dat je in een tekst een dubbele aanhalingsteken wilt opnemen (bvb "Een " heet een aanhalingsteken"). Je kan dat niet zomaar doen, want de compiler zal denken dat het " na een het afsluitaanhalingsteken van de string is. Als je een aanhalingsteken wilt opnemen in een string moet je er een backslach voor zetten: "Een \" heet een aanhalingsteken". Het newline-karakter (\n) is ook zo een escape-teken. De backslash zelf moet je ook escapen, anders denkt de compiler dat er een speciaal teken gaat volgen:

printf("%s", "Dit is een backslash:\\");

In string.h zijn nog tal van nuttige functies m.b.t. strings:

strcomp(): vergelijkt 2 strings op hun alfabetische volgorde
strcat(): voegt twee strings bij elkaar
strcpy(): kopieert een string naar een andere.

Het zou hier te ver voeren om alle functies te beschrijven. Er bestaan goede web-tutorials en boeken. De bedoeling van deze stukjes was mensen op weg te helpen met C, die totaal geen programmeer-ervaring hebben, of voor wie de meeste boeken te snel gaan.
Als je alle stukjes doorgenomen hebt (en een beetje zelf gespeeld met de code eruit), sta je sterk genoeg in je schoenen om aan een boek te beginnen. Ik vind "De programmeertaal C" van Al Kelley en Ira Pohl zeer goed.

Je hebt nu nog niet veel geleerd, maar de kennis die je nu hebt zou het beginnen aan een boek moeten vergemakkelijken. Er zijn nog heel veel dingen waarover ik niets gezegd heb: meerdimensionale arrays, structs, dynamisch geheugen, ...
De bedoeling was niet een gans boek over C te schrijven, maar een hulp te bieden bij het "beginnen met C".
   
Support bacteria. They're the only culture some people have.

Offline Laus_2

  • Lid
Re: Beginnen met C
« Reactie #24 Gepost op: 2009/04/28, 22:31:12 »
bedankt voor bovenstaande. Ik kende al c-gebaseerde talen maar ff de basis is wel handig.

stel ik wil zelf een project starten, een bestaand project aanpassen...neem als voorbeeld een willekeurig sourceforge project.
Hoe kom je aan de gui-designtools, hoe kom je aan kennis over alle bibliotheken enz?

Ik bedoel, Geany, eclipse...prima...maar hoe kan ik mn appje tekenen, compileren? Hoe maak ik er een .deb van?
Mss wat hoog gegrepen voor deze topic hoor..mss het vervolg?