Göm menyn

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 i std::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. statistics.txt skulle exempelvis kunna se ut så här:
1.0
2.0

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ända std::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:
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:
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 typen std::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 typen std::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 typen std::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: Christoffer Holm, Simon Ahrenstedt
Senast uppdaterad: 2023-10-26