string en iostream.
© Harry Broeders.
Deze opdracht is bedoeld om je C kennis op te frissen en behandelt daarnaast
enkele kleine verbeteringen van C++ ten opzichte van C. In de propedeuse
heb je leren werken met character array's voor het opslaan van strings. In
de standaard C++ library is het type string gedefinieerd dat
veel eenvoudig te gebruiken is dan character array's. In C gebruik je de
stdio library voor input en output bewerkingen. In de C++ standaard
is de iostream library gedefinieerd die eenvoudiger te gebruiken
is dan de stdio library. Deze nieuwe library is bovendien
uitbreidbaar (zoals we in opdracht 2 zullen zien).
Lees voordat je met deze opgave gaat beginnen eerst hoofdstuk 1 van het dictaat door.
string type.
We zullen eerst de problemen met strings in C op een rijtje zetten en daarna
het nieuwe string type uit C++ bespreken.
De programmeertaal C heeft geen "echt" string type. Als je in C een string
(rij karakters) wilt opslaan dan doe je dat in een character array. In C
geldt de afspraak dat elke string wordt afgesloten door een zogenaamd
nul-karakter '\0'. Voorbeeld:
char naam[] = "Harry"; // deze array bevat 6 karakters!
Een string in C heeft de volgende problemen:
strxxx functies gebruikt worden).
#include <string.h>#include <iostream.h>int main() {char naam[10];naam = "Harry"; // Error! Zie opmerking 1.strcpy(naam, "Harry"); // OKcout<<naam<<endl;strcpy(naam, "Willem-Alexander"); // Error! Zie opmerking 2.strcpy(naam, "Alex"); // OKcout<<naam<<endl;if (naam == "Alex") { // Error! Zie opmerking 3.// ...}if (strcmp(naam, "Alex") == 0) { // OK// ...}}
Opmerkingen:
naam) kun je namelijk niets toekennen. Als je de
array wilt vullen dan moet je dat met de functie strcpy
(gedefinieerd in <string.h>) doen.
naam == "Alex" levert echter altijd false op! Als
je twee array variabelen met elkaar vergelijkt dan worden hun adressen
met elkaar vergeleken. Als je de inhoud van de array's met elkaar
wilt vergelijken moet je de functie strcmp (gedefinieerd in
<string.h>) gebruiken.
string.
De programmeertaal C++ heeft wel een "echt" string type. Dit type is gedefinieerd in de standaard library. Later zul je leren dat string geen "ingebouwd" type is maar een "zelfgemaakt type" een zogenaamde class. Voor het gebruik maakt dat echter niet uit. Voorbeeld:
#include <string>using namespace std;string naam("Harry"); // deze string bevat 5 karakters.
Een string in C++ heeft de volgende voordelen ten opzichte van
een string uit C:
string is dynamisch (de lengte kan tijdens het uitvoeren
van het programma, indien nodig, worden aangepast, er is dus ook geen maximale
lengte!).
string bevat veel extra functionaliteit.
#include <string> // Zie opmerking 1.#include <iostream>using namespace std;int main() {string naam;naam = "Harry"; // Zie opmerking 2.cout<<naam<<endl;naam = "Willem-Alexander"; // Zie opmerking 3.cout<<naam<<endl;if (naam == "Willem-Alexander") { // Zie opmerking 4.cout<<"Hoi Alex!"<<endl;}return 0;}
Opmerkingen:
<string> is dus heel wat anders dan
de C include file <string.h>. Als je in een C++ programma
toch de oude C strings wilt gebruiken (om oude C code te hergebruiken) dan
kun je de oude strxxx functies includen met de include file
<cstring>.
string met behulp van de operator =.
string is dynamisch en "groeit" als dat nodig is!
string gewoon vergelijken met
behulp van de operator ==.
Nu komt de verrassing: een variabele van het type (eigenlijk de class)
string is geen gewone variabele maar een object! Wat
dat precies betekent wordt in hoofdstuk 3 van het
dictaat uitgebreid behandeld. Op dit moment
zullen we alleen bekijken wat dit betekent voor het gebruik van objecten
(variabelen) van de class (het type) string.
Objecten zijn vergelijkbaar met gewone variabelen: ze hebben een naam en je kunt er "iets" in opslaan. Maar met objecten kun je iets wat met gewone variabelen niet kan. Je kunt objecten boodschappen (messages) sturen.
Je kunt een message naar een object sturen om het object een vraag
te stellen. Als je wilt weten hoeveel karakters een object van de class
string bevat dan kun je dat object de message size
sturen. Het antwoord op deze message is dan een integer die het aantal karakters
weergeeft.
#include <string>#include <iostream>using namespace std;int main() {string naam("Willem-Alexander");cout<<"De naam "<<naam<<" bevat "<<naam.size()<<" karakters."<<endl;cin.get();return 0;}
Uitvoer:
De naam Willem-Alexander bevat 16 karakters.
De syntax voor het versturen van een message is:
naam-van-object.naam-van-message(parameters)
Dus eerst de naam van het object waar naar toe de message verstuurd moet
worden (dat object wordt de receiver van de message genoemd) dan een
punt gevolgd door de naam van de message en tot slot een haakje openen en
een haakje sluiten met daartussen eventuele parameters. De message
size heeft geen parameters. Het versturen van een message lijkt
een beetje op het aanroepen van een functie. In C++ wordt het versturen van
een message meestal het aanroepen van een memberfunctie genoemd. Toch
is er een duidelijk verschil tussen een memberfunctie (message) en een functie:
een memberfunctie heeft een receiver en een gewone functie niet!
Je kunt ook een message naar een object sturen om het object iets te laten
doen. Na afloop van de memberfuntie is het object dan veranderd. Als
je bijvoorbeeld iets aan een object van de class string wilt
toevoegen dan kun je dat object de message append sturen. De
string die moet worden toegevoegd moet je als argument meesturen.
#include <string>#include <iostream>using namespace std;int main() {string naam("Willem-Alexander");naam.append(" en Maxima");cout<<naam<<endl;cin.get();return 0;}
Uitvoer:
Willem-Alexander en Maxima
string.
Voor het complete overzicht verwijs ik je naar de helpfile van de class
string. Als je in Borland C++ Builder het woordje
string intypt en op F1 drukt moet je kiezen voor
basic_string voor het complete overzicht. De typenaam
string blijkt een andere naam te zijn voor het template type
basic_string. Het begrip template wordt pas in hoofdstuk 4 van
het dictaat behandeld.
In deze paragraaf worden enkele voorbeelden gegeven.
> <
>= <= == != (spreekt
voor zich).
[].char
c(s[2]);s gelijk is aan Maxima dan wordt het karakter
c gelijk aan x.
[].s[3]='a';s gelijk is aan Maxima dan wordt het
s gelijk aan Maxama.
= of met assign.
Met assign kun je ook een deel van de ene string
aan de andere string toekennen.s1.assign(s2, 7,
4);
s1 wordt gelijk aan het deel van s2 dat begint op positie
7 en 4 karakters lang is. Als s2 gelijk is aan
Willem-Alexander dan zal s1 gelijk worden aan
Alex.
+ en += of met
append. Met append kun je ook een deel van de ene
string achter de andere string plakken.string
s1("Willem");
s1+="-Alexander";string
s2("Maxima");s2+=" en
";s2.append(s1, 7,
4);s2 wordt gelijk aan Maxima en Alex
insert.s1.insert(4,
s2);s2 op positie 4 in s1 in. Als s1
gelijk is aan Maxima en s2 gelijk is aan
Willem-Alexander dan wordt s1 gelijk aan
MaxiWillem-Alexanderma.s1.insert(4, s2,
7,
4);s1 gelijk is aan Maxima en s2
gelijk is aan Willem-Alexander dan wordt s1 gelijk
aan MaxiAlexma.
erase.s1.erase(3,
10);s1 gelijk is aan Willem-Alexander dan wordt
s1 gelijk aan Wilder.
replace.s1.replace(0,
4,
"Jongs");s1 gelijk is aan Maxima dan wordt
s1 gelijk aan Jongsma.
substr.s1=s2.substr(7);s1 wordt gelijk aan het deel van s2 dat begint
op positie 7. Als s2 gelijk is aan Willem-Alexander
dan zal s1 gelijk worden aan Alexander.s1=s2.substr(7,
4);s1 wordt gelijk aan het deel van s2 dat begint
op positie 7 en 4 karakters lang is. Als s2 gelijk is aan
Willem-Alexander dan zal s1 gelijk worden aan
Alex.
find.int
i(s1.find("Alex"));s1 gelijk is aan Willem-Alexander dan wordt
i gelijk aan 7. Als de string Alex niet in
s1 voorkomt krijgt i de waarde
string::npos (een in de class string gedefinieerde
constante). Eigenlijk moeten we deze regel als volgt programmeren:string::size_type
i(s1.find("Alex"));string wordt namelijk het type
size_type gedefinieerd dat gebruikt moet worden om indexwaarden
van een string in op te slaan.string::size_type
i(s1.find("le"));string::size_type
j(s1.find("le",
7));s1 gelijk is aan Willem-Alexander dan wordt
i gelijk aan 3 en j gelijk aan 8.find de string van voor naar
achter. Je kunt de memberfunctie rfind gebruiken om van achter
naar voor te zoeken.
find_first_of.string::size_type
i(s1.find_first_of("aeiou"));s1 die voorkomt in de als parameter
meegegeven string. Als s1 gelijk is aan
Maxima dan wordt i gelijk aan 1. Als de string
s1 geen van de karakters a, e,
i, o of u bevat krijgt i
de waarde string::npos.find_last_of,
find_first_not_of en find_last_not_of spreekt denk
ik voor zich.
const char* met
c_str().string.
Zoals je in paragraaf 1.7 van het dictaat
hebt gelezen gebruiken we in C++ de input/output library
iostream in plaats van de C library stdio. Het
zal je niet verbazen dat de variabelen cin en cout
die je in paragraaf 1.7 hebt leren kennen geen variabelen maar objecten zijn.
Je kunt deze objecten (net als objecten van de class string)
dus ook messages sturen. Elke class definieert echter zijn eigen messages.
Het object cout is een object van de class ostream
en het object cin is een object van de class
istream. Later zal blijken dat dit niet helemaal klopt
maar dat maakt voor dit verhaal niets uit. Naar een object van de
class string kun je bijvoorbeeld de message size
sturen om te vragen hoeveel karakters het object bevat. Naar
cout kun je deze message echter niet sturen (dit object begrijpt
deze message niet). De aanroep cout.size() geeft tijdens het
compileren de volgende foutmelding: 'size' is not a member of
'ostream'. Welke messages je naar cout en
cin kunt sturen kun je opzoeken in de helpfile van de class
ostream respectievelijk istream. Bijvoorbeeld:
cout.fill('#');cout.width(10);int i(189);cout<<i<<endl;
Uitvoer:
#######189
Tot slot van deze inleiding volgt nog een voorbeeld
waarin met objecten
van de class string wordt gewerkt.
Merk op dat in dit programma de vernieuwingen die in C++ zijn ingevoerd ten opzichte van C namelijk het gebruik van abstracte data typen en object georiënteerde technieken in dit programma nog niet toegepast zijn. In dit programma wordt C++ dus op een C manier gebruikt. Dit is voor kleine programma's geen probleem. Als een programma echter groter is of als het uitbreidbaar of onderhoudbaar moet zijn kunnen we beter gebruik maken van de object georiënteerde technieken die C++ biedt. Deze technieken zullen in de volgende practicumopdrachten aan de orde komen.
#include <iostream>#include <string>using namespace std;int main () {cout<<"Geef je email adres: ";string mailAdres;cin>>mailAdres;string::size_type indexAapje(mailAdres.find("@"));if (indexAapje!=string::npos) {cout<<"Gebruiker: "<<mailAdres.substr(0, indexAapje)<<endl;cout<<"Machine: "<<mailAdres.substr(indexAapje+1)<<endl;}else {cout<<mailAdres<<" is geen geldig email adres!"<<endl;}cout<<"Druk op de return-toets."<<endl;cin.get();cin.get();return 0;}
Deze opdracht bestaat uit de deelopdrachten 1a tot en met 1c. Opdrachten 1b en 1c moet je laten aftekenen door de docent.
Opdracht 1a.
Compileer en test het bovenstaande programma
|
Opdracht 1c.
Soms is alleen 1 van de 4 onderdelen (protocol, machine, directory of file)
nodig. Het ontleden van de hele URL is dan overbodig. Schrijf één
of meer functies zodanig dat het volgende
testprogramma
De uitvoer moet dan zijn: |