Oppgaver til kapittel 1¶
Det er to slags oppgaver på denne siden.
Oppvarmingene kommer først: korte programmer du skal lese, der du forutsier hva de skriver ut og velger et svar i nettleseren. Ikke noe prosjekt, ingen skriving, omtrent ett minutt hver. Hver eneste av dem er bygd rundt en feil kapittel 1 advarer spesifikt mot — langt billigere å møte her enn klokka ett om natta i din egen kode.
Så kommer programmene, fra oppgave 1 og utover: ting du skal skrive selv. Prøv hver enkelt selv før du avslører løsningen — du lærer langt mer av et ærlig forsøk, og feilene underveis, enn av å lese et ferdig program. Skriv koden inn i CLion og kjør den; ikke bare les den.
Når du åpner en løsning vises den uskarp — klikk én gang til for å avsløre den, slik at du ikke ser svaret ved et uhell.
Oppvarming: forutsi utskriften¶
Finn ut hva hvert program skriver ut før du velger et alternativ. Å svare låser spørsmålet og avslører forklaringen, så en gjetning koster deg oppgaven. Er du usikker, spor programmet for hånd, linje for linje, slik en debugger ville gjort det — den vanen er hele poenget.
W1. Del og skriv ut¶
#include <iostream>
int main() {
int a = 7;
int b = 8;
int c = 10;
double average = (a + b + c) / 3;
std::cout << average << "\n";
}
Hva skriver dette ut?
8. double-en på venstre side endrer ingenting ved divisjonen på høyre side.
a + b + c er 25, en int. 3 er også en int. Dermed er 25 / 3 heltallsdivisjon: den regner ut 8 og kaster resten, akkurat der, før noe som helst blir tilordnet. Først da blir denne 8-en konvertert til double og lagret i average.
Løsningen er å gjøre den ene siden til en double, slik at selve divisjonen beholder brøkdelen: (a + b + c) / 3.0. Se Operatorer og uttrykk.
W2. En funksjon som ikke endrer noe¶
#include <iostream>
void addTen(int value) {
value += 10;
}
int main() {
int count = 5;
addTen(count);
std::cout << count << "\n";
}
Hva skriver dette ut?
5. count ble aldri rørt.
En parameter er en kopi av argumentet. addTen fikk sin egen int med verdien 5, la 10 til den, og kastet den da funksjonen returnerte. count i main er en annen variabel og ble aldri endret.
Dette er den enkeltoverraskelsen nybegynnere oftest møter, og derfor bruker Funksjoner et helt avsnitt på den. For å la en funksjon endre kallerens variabel sender du en referanse — verktøyet for det kommer i Verdier, referanser og pekere. Inntil da: skal en funksjon gi noe tilbake, return-er du det.
W3. To ord inn, ett ord ut¶
Brukeren skriver Ada Lovelace og trykker Enter.
#include <iostream>
#include <string>
int main() {
std::string name;
std::cout << "Name: ";
std::cin >> name;
std::cout << "Hello, " << name << "!\n";
}
Hva skriver dette ut etter ledeteksten?
Hello, Ada! — Lovelace blir liggende igjen.
>> leser ett ord adskilt av blanktegn. Den stopper ved mellomrommet etter Ada, så name inneholder bare Ada; resten av linja blir liggende ulest i inndatabufferet.
For å lese en hel linje, mellomrom og alt, bruker du std::getline(std::cin, name) i stedet. Se Strenger og vektorer — og merk advarselen der om hva som skjer når du blander de to på samme strøm.
W4. En switch uten break¶
#include <iostream>
int main() {
int gear = 2;
switch (gear) {
case 1: std::cout << "First\n";
case 2: std::cout << "Second\n";
case 3: std::cout << "Third\n";
default: std::cout << "Unknown\n";
}
}
Hva skriver dette ut?
Alle tre: Second, Third, Unknown.
En case-etikett er et inngangspunkt, ikke en selvstendig blokk. Kjøringen hopper til case 2: og fortsetter så rett gjennom hver etikett under den helt til den treffer en break eller den avsluttende krøllparentesen. Her finnes ingen break noe sted, så den faller helt gjennom — også inn i default.
Det kompilerer uten en eneste innvending, fordi bevisst gjennomfall av og til er nyttig. Nettopp det gjør en glemt break til et så godt gjemmested for en feil. Se Kontrollstrukturer.
W5. Riktige grener i feil rekkefølge¶
#include <iostream>
int main() {
int celsius = -5;
if (celsius < 25) {
std::cout << "Comfortable\n";
} else if (celsius < 15) {
std::cout << "Cold\n";
} else if (celsius < 0) {
std::cout << "Freezing\n";
} else {
std::cout << "Hot\n";
}
}
Minus fem grader. Hva skriver dette ut?
Comfortable, ved −5 °C.
Bare den første grenen som passer kjører; resten hoppes over uansett hvor mye bedre de passer. -5 < 25 er sant, så kjeden stopper der og vurderer aldri Cold eller Freezing i det hele tatt. De to grenene er uoppnåelige for enhver verdi: alt som er under 15 eller 0 er også under 25.
Ingenting her er en syntaksfeil, så kompilatoren sier ikke et ord. En else if-kjede over et verdiområde må ordnes fra den ene enden til den andre — kaldest først, slik oppgave 9 nedenfor gjør det. Se Kontrollstrukturer.
W6. Dobling som ikke fester seg¶
#include <iostream>
#include <vector>
int main() {
std::vector<int> readings = {1, 2, 3};
for (int value : readings) {
value *= 2;
}
for (int value : readings) {
std::cout << value << " ";
}
std::cout << "\n";
}
Hva skriver dette ut?
1 2 3. Vektoren er urørt.
for (int value : readings) gir deg en fersk kopi av hvert element. value *= 2 dobler kopien, og kopien kastes ved slutten av den runden — samme regel om verdioverføring som i W2, i løkkeforkledning.
For å endre elementene på plass tar du en referanse, slik at value er elementet i stedet for en kopi av det:
Dette ene &-tegnet er hele forskjellen. Se Kontrollstrukturer.
Når du har svart på et spørsmål, lim programmet inn i Compiler Explorer og kjør det — å se utskriften bekrefte (eller motsi) resonnementet ditt er det som får det til å feste seg.
Hvor du skal legge koden din¶
Hver oppgave er sitt eget lille program med sin egen main(), og et CLion-prosjekt kjører én main() om gangen. Du har to muligheter:
Enklest — hold ett prosjekt åpent og bytt ut innholdet i main.cpp for hver oppgave. Kjør det, og lim så inn det neste. (Du mister det forrige forsøket, noe som er greit for rask øving.)
Beholder hver oppgave (anbefalt) — gi hver oppgave sin egen fil i ett enkelt prosjekt (ex1.cpp, ex2.cpp, …) og legg til én linje per fil i CMakeLists.txt:
Velg så hvilket program som skal kjøres fra rullegardinmenyen for kjørekonfigurasjon ved siden av den grønne ▶-knappen. Du trenger ikke forstå CMakeLists.txt ennå — CMake-introduksjon forklarer det i kapittel 2; for nå, bare kopier mønsteret.
1. Presenter deg selv¶
Øver på: Grunnstruktur, Variabler og grunntyper
Deklarer en std::string for navnet ditt og en int for alderen din (akkurat som kapittelets int age = 25). Skriv ut én linje:
Vis løsning
2. Gjennomsnittskarakter¶
Øver på: Operatorer og uttrykk
Du har tre prøvekarakterer: 7, 8 og 10. Skriv ut gjennomsnittet deres. Sørg for at det kommer ut som et desimaltall — 8.33…, ikke et avkortet 8.
Vis løsning
#include <iostream>
int main() {
int a = 7;
int b = 8;
int c = 10;
double average = (a + b + c) / 3.0; // 3.0 er en double, så desimalene beholdes
std::cout << "Average: " << average << "\n";
}
Del på 3 (en int) og C++ gjør heltallsdivisjon — den kaster bort brøkdelen og du får 8. Å skrive 3.0 gjør den ene siden til en double, så desimalene overlever. Det er kapittelets 10 / 3-regel i praksis.
3. Sensoravlesninger¶
Øver på: Strenger og vektorer, Kontrollstrukturer
Lagre fem sensoravlesninger — 42, 17, 99, 8, 56 — i en std::vector<int>. Skriv ut hvor mange det er, gjennomsnittet deres (som et desimaltall), og det største.
Hint: gå gjennom vektoren for å summere verdiene og holde styr på det største;
readings.size()er antallet.
Vis løsning
#include <iostream>
#include <vector>
int main() {
std::vector<int> readings = {42, 17, 99, 8, 56};
int sum = 0;
int largest = readings[0];
for (int r : readings) {
sum += r;
if (r > largest) {
largest = r;
}
}
double average = static_cast<double>(sum) / readings.size();
std::cout << "Count: " << readings.size() << "\n";
std::cout << "Average: " << average << "\n";
std::cout << "Largest: " << largest << "\n";
}
En områdebasert for besøker hvert element: vi legger hvert til sum og beholder det største som er sett så langt. static_cast<double> holder divisjonen desimal (heltallsdivisjon-regelen igjen), og readings.size() gir antallet elementer.
4. Partall eller oddetall¶
Øver på: Kontrollstrukturer
Bruk en for-løkke til å skrive ut tallene 1 til 10, og merk hvert enkelt som even eller odd.
Hint: et tall er partall når
n % 2 == 0.
Vis løsning
5. Kvadrater¶
Øver på: Funksjoner
Skriv en funksjon int square(int n) som returnerer n * n (du så akkurat denne funksjonen i kapittelet). Bruk så en for-løkke til å skrive ut kvadratene av 1 til og med 5.
Vis løsning
6. Trafikklys¶
Øver på: Enumerasjoner
Definer en enum class TrafficLight med Red, Amber og Green. Skriv en funksjon som skriver ut handlingen for hver enkelt — Stop, Get ready, Go — ved hjelp av en switch, og kall den for alle tre.
Vis løsning
#include <iostream>
enum class TrafficLight {
Red,
Amber,
Green
};
void act(TrafficLight light) {
switch (light) {
case TrafficLight::Red: std::cout << "Stop\n"; break;
case TrafficLight::Amber: std::cout << "Get ready\n"; break;
case TrafficLight::Green: std::cout << "Go\n"; break;
}
}
int main() {
act(TrafficLight::Red);
act(TrafficLight::Amber);
act(TrafficLight::Green);
}
Et fast sett med navngitte verdier håndtert av en switch. Uten default advarer kompilatoren deg hvis du legger til en farge senere og glemmer den her.
7. Fortsett å spørre¶
Øver på: Kontrollstrukturer
Spør brukeren om et positivt tall, om og om igjen, til de faktisk gir deg et. Skriv det så ut. Bruk en do-while-løkke, så du spør minst én gang.
Hint: dette er
do-while-mønsteret fra kapittelet — les inne i løkken, og gjenta så lenge verdien ennå ikke er positiv.
Kjør det — du skal se:
Enter a positive number: -4
Enter a positive number: 0
Enter a positive number: 12
Thanks — you entered 12
Vis løsning
#include <iostream>
int main() {
int number = 0;
do {
std::cout << "Enter a positive number: ";
std::cin >> number;
} while (number <= 0);
std::cout << "Thanks — you entered " << number << "\n";
}
En do-while kjører kroppen sin før den tester betingelsen, så ledeteksten vises alltid minst én gang. Løkken gjentar så lenge number <= 0, så den slipper deg først ut når verdien er ekte positiv — nettopp det "fortsett å spørre til det er gyldig" trenger.
8. Hils med fullt navn¶
Øver på: Strenger og vektorer
Spør om brukerens fulle navn (fornavn og etternavn, med mellomrommet), hils på dem, og fortell hvor mange tegn navnet har. Fordi navnet inneholder et mellomrom, trenger du std::getline, ikke std::cin >>.
Hint:
std::getline(std::cin, name)leser hele linjen;name.length()teller tegnene.
Kjør det — du skal se:
Vis løsning
#include <iostream>
#include <string>
int main() {
std::string name;
std::cout << "Enter your full name: ";
std::getline(std::cin, name);
std::cout << "Hello, " << name << "\n";
std::cout << "Your name has " << name.length() << " characters.\n";
}
std::getline leser hele linjen, mellomrom inkludert, så Ada Lovelace kommer inn helt — std::cin >> name ville stoppet ved mellomrommet og beholdt bare Ada. Tallet 12 inkluderer mellomrommet, fordi det er ett av tegnene i strengen.
9. Temperaturklassifisering¶
Øver på: Kontrollstrukturer
Les en temperatur (et helt antall grader Celsius) og skriv ut en beskrivelse ved hjelp av en if / else if / else-kjede: under 0 er Freezing, 0 til 14 er Cold, 15 til 24 er Comfortable, og 25 eller over er Hot.
Hint: test det kaldeste tilfellet først og arbeid oppover, så hver
else ifbare trenger å sjekke sin øvre grense.
Kjør det — du skal se:
Vis løsning
#include <iostream>
int main() {
int celsius = 0;
std::cout << "Enter the temperature in Celsius: ";
std::cin >> celsius;
if (celsius < 0) {
std::cout << "Freezing\n";
} else if (celsius < 15) {
std::cout << "Cold\n";
} else if (celsius < 25) {
std::cout << "Comfortable\n";
} else {
std::cout << "Hot\n";
}
}
Bare den første grenen som passer kjører, så det å ordne testene fra kaldest og oppover lar hver else if anta at alt under den allerede er utelukket: når celsius < 15 sjekkes, vet vi at den ikke er under 0, så den grenen betyr 0 til 14. Den siste else fanger alt som er igjen — 25 og over.