TDP004 Objektorienterad programmering
Förberedelsefrågor STL och kommandorad
Följande uppgifter behandlar standardbiblioteket i C++, Standarad Template Library (STL), strömmar och kommandoraden.
Uppgift 1
Du vet att användaren matat in en sträng eller ett heltal. Visa hur du utan andra hjälpmedel än medlemmar istd::cin
och vanliga if
-satser
kan läsa in inmatad data till en std::string
om inmatningen var en
sträng och till en heltalsvariabel om det var ett heltal.
Uppgift 2
Det är givet att 'statistics.txt' enbart innehåller flyttal. Förklara vad som är fel i följande kod:
int main()
{
ifstream ifs("statistics.txt");
if ( ! ifs )
{
cerr << "Kunde inte öppna 'statistics.txt'." << endl;
return 1; // terminate program with error code 1
}
double nr;
double sum{0.0};
int count{0};
while ( ! ifs.eof() )
{
ifs >> nr;
sum += nr;
++count;
}
double average = sum / count;
return 0;
}
Tips: Jämför antal behandlade tal med antal tal i filen.
Uppgift 3
Antag att programmet ser ut som:
cout << "Mata in ett flyttal: " << endl;
double d;
cin >> d;
Antag att användaren matade in "Ett-komma-fem".
Visa hur du gör för att upptäcka problemet och se till så att nästa
inmatning har en chans att fungera?
Uppgift 4
Visa hur du kan användastd::random_device
och
std::uniform_int_distribution
för att slå två 6-sidiga tärningar (en
tärning 1-6, två tärningar 2-12). Skriv ut resultatet med std::cout
.
Resultatet skall naturligtvis vara sannolikhetsmässigt korrekt. Det
vill säga att slag med en tärning ger samma sannolikhet att få varje
siffra 1-6, medan slag med 2 tärningar ger högst sannolikhet att slå 7
(6 av 36 kombinationer get summan 7), lägst att slå 2 och 12 (1 av 36
kombinationer för vardera).
Tänker du till inser du att du inte behöver någon matematik för att få
till detta korrekt, de nämnda std-typerna räcker.
Uppgift 5
Huvudprogrammet i C/C++ deklareras fullständigt som:
int main(int argc, char* argv[]);
Tolkning av "argv
" baklänges:
Vi har en array ([]) argv som på var position lagrar pekare (*) till
tecken (char).
Parametern argc anger antalet strängar i argv[] och argv[] innehåller
adressen till varje ord (som en sekvens med tecken) på kommandoraden
(inklusive programmets namn).
Kommandoraden "./a.out C-strings avslutas med noll-tecken" kommer
t.ex. se ut som följer i minnet:
+-----+ +-----+ argc | 5 | /--->| o------>[./a.out] +-----+ | +-----+ | | o------>[C-strings] +-----+ | +-----+ argv | o-----/ | o------>[avslutas] +-----+ +-----+ | o------>[med] +-----+ | o------>[noll-tecken] +-----+Tänk på att figuren är förenklad; en C-sträng "C-str" ritas [C-str] i figuren, men lagras i minnet som en sekvens med tecken enligt följande figur:
Enkelt I minnet +-----+-----+-----+-----+-----+-----+ [C-str] | 'C' | '-' | 's' | 't' | 'r' |'\0' | +-----+-----+-----+-----+-----+-----+Kuriosa: Ibland kan man även se deklarationen:
int main(int argc, char** argv);
Tittar du i figuren ser du att detta också stämmer. Tolkning baklänges:
Vi har en variabel argv som lagrar en adress (*) till något som är en
adress (*) till något som är ett tecken (char).
Är vi lite flexibla med singular och plural (pekare anger inte hur
många variabler som pekas ut) så blir denna variant samma sak. Dock
inte lika tydlig som den förra.
Visa hur du på enklaste sätt transformerar argc och argv till en
std::vector. Vektorn skall innehålla alla strängar från argv[] som
std::string. Titta framförallt på vilka konstruktorer det finns i
std::vector och std::string.
Uppgift 6
Antag att du har en variabel "my_map" av typenstd::map<string, int>
som du fyllt på med data. Nu skall du sätta in nyckeln "Kaffe" med
värdet 536. Om "Kaffe" redan finns i din map skall värdet som redan
finns ändras.
Visa hur du på enklaste sätt löser problemet.
Uppgift 7
Du har en variabel "my_map" av typenstd::map<string, vector<int>>
som
du fyllt på med data. Nu vill du med en iteratorloop gå igenom alla
nycklar och lägga till heltalet 3 i nyckelns vektor.
Visa hur du på enklaste och effektivaste sätt löser problemet.
Uppgift 8
Du har en variabel "v" av typenstd::vector<int>
som du fyllt på med
heltal. Visa hur du med en iteratorloop stegar igenom vektorn och tar
bort alla heltal med värdet 7.
Uppgift 9
Du har följande kod:
vector<int> v(istream_iterator(cin), istream_iterator());
vector<int> square;
Nu vill du gå igenom vektorn "v" och lagra kvadraten av varje värde i
vektorn "square".
Visa hur du gör detta med hjälp av std::transform, std::back_inserter
och ett lambdauttryck.
Uppgift 10
Du har en vektor som representerar (x,y) koordinater för objekt i ett spel:
using Point = pair<int,int>;
vector<Point> v;
Nu vill du ta reda på vilken av koordinaterna som ligger närmast en
punkt:
Point p;Antag att du redan har en funktion som beräknar avståndet mellan två punkter returnerat som ett positivt heltal:
int distance(Point const& a, Point const& b);
Visa hur du hittar elementet med minsta avstånd till punkten med hjälp
av std::min_element och ett lamdauttryck med capture.
Uppgift 11
Du har följande funktioner att tillgå:
tuple_sum(tuple<int,int> const& t) { return get<0>(t) + get<1>(t); }
tuple_min(tuple<int,int> const& t) { return std::min(get<0>(t), get<1>(t)); }
Du har även en vektor som representerar ett antal slag med två
tärningar:
vector<tuple<int,int>> v;
Nu vill du gå igenom vektorn "v" och ta bort alla dubbletter enligt
principen att (x,y) är samma som både (x,y) och (y,x).
För att göra detta måste vektorn först sorteras i lämplig ordning så
att dubbletterna hamnar i följd.
Visa hur du löser detta med std::sort och ett lambdauttryck.
Uppgift 12
Antag att du har en vektor så som den ser ut efter korrekt lösning i uppgift (11). Visa hur du tar bort dubbletterna med std::unique, std::vector::erase och ett lamdauttryck.
Sidansvarig: Eric Ekström
Senast uppdaterad: 2016-10-27