- Manglende bruk av korrekt 'namespace' (mest vanlig er å glemme: 'using namespace std;').
- Glemmer å include aktuell (.h-)fil.
- Programsetning med preprosessor-direktiv avsluttes med ';':
#include <iostream>; // Ingen preprosessor-direktiver
#define PI 3.1415926; // avsluttes med ';' :
#if !defined(XXX)
#define XXX;
#endif;
- Høyre- og venstresiden er byttet om i en tilordning:
a * b = svar; // Sidene er byttet om.
- Rett rekkefølge på operatorer/tegn ved aritmetisk tilordning:
int a = 94, b = 312;
a =- 4; // Tror at 'a' minskes med 4, slik at den får verdien 90.
// 'a' blir satt til -4(!). Må skrive: a -= 4;
b =+ 18; // Tror at 'b' økes med 18, slik at den får verdien 330.
// 'b' blir satt til 18(!). Må skrive: b += 18;
- Bruk av udefinert/feilskrevet variabel:
int ant1 = 26, ant2 = 7;
float antSum;
antsum = ant1 + ant2; // 'antsum' er skrevet uten stor 'S'.
- Divisjon med bare int'er slik at desimalene bare forsvinner (avrundes ikke):
int ant1 = 26, ant2 = 7;
float svar;
svar = ant1 / ant2; // svar = 3, Regner med to 'int'-er.
// Mister bare desimalene/avrundes ikke.
- Unødvendig Warning:
float tall = 12.8; // Mange kompilatorer vil her kunne gi en Warning,
// f.eks. 'initialzing': truncation from 'const double' to 'float'.
// Husk derfor å ha med 'F', dvs. float tall = 12.8F;
- Caster ikke automatisk til "lavere" type:
char ch = 'A';
cout << ch // Får skrevet 'A' (ASCII-verdi er 65).
<< ch+1; // Får skrevet 66, da regner totaluttrykket som int!
// Måtte ha skrevet: char(ch+1)
- Divisjon med '0'.
- "Sprenger" en variabels verdiområde ved utregning:
int a = 1000000, b = 100000, c = 1000, d;
d = a * b / c; // En int kan max. være 2.147.483.647. 'a*b' blir for stort for dette.
// Dermed blir noe "søppel" dividert med 'c', og gir dermed feil svar.
// Må derfor skrive: d = a * (b / c) eller d = a / c * b
- Ikke-matchende datatyper i uttrykk:
int a;
char b;
float c;
c = a / b; // Faktisk lovlig, men virker kanskje noe merkelig.
eller
char a[] = "TEKST";
char * p = a;
if (p == 'T') // 'p' er en peker og ikke en char-variabel. Må evt. bruke '*p'.
cout << ".......";
- Initialiserer ikke variable (inneholder istedet tilfeldig "søppel"):
int sum, tall;
do {
cout << "Skriv et tall: "; cin >> tall;
sum += tall; // 'sum' er ikke nullstilt, derfor adderes
} while (tall != 0); // 'tall' til tilfeldig "søppel".
- Manglende gåsøyne til slutt i tekststreng:
cout << "Denne teksten blir skrevet ut;
eller
char tekst[] = "Dette er en test-tekst; // Begge mangler avsluttende '"';
// Fort gjort å også glemme: , (komma) ' (apostrof) \ (backslash)
- Ikke-matchende antall parenteser:
if ((a = sqrt(b)) != ((6+ant)*(100-ant2)) // Mangler en ')' helt til slutt.
- Inkrement av samme variabel to ganger i samme uttrykk:
a = i++ * i++; // Uklart om ++ skjer mellom utregningen eller to ganger først til slutt.
- Misforstått operator-presedens:
svar = a - b * c + d; // Vil beregnes som: (a - (b * c)) + d
- Feil bruk av sammenligningsoperatorer:
- Tegnene '>' og '<' er snudd feil vei (logisk/semantisk).
- Byttet rekkefølgen til '<' og '=' i '<=' (syntaktisk).
- Byttet rekkefølgen til '>' og '=' i '>=' (syntaktisk).
- Byttet rekkefølgen til '!' og '=' i '!=' til '=!' (logisk/semantisk).
Dette medfører at det på venstre side settes til (får verdien av) NOT ('!') til det på høyre side!
eller
if ( -0.5 <= x <= 0.5 ) .... // Sammenligner -0.5 <= x (svaret er 0 eller 1)
// sammenligner så dette svaret med 0.5.
// Burde ha skrevet:
// if ( -0.5 <= x && x <= 0.5 ) ....
- Bruker '=' istedet for '==' når skal sammenligne uttrykk:
if (a = 5) // 'a' blir satt lik 5, som alltid er mulig/sant/true.
cout << "A er lik 5"; // Skulle i stedet ha brukt '==' (for å sammenligne).
else
cout << "A er ulik 5";
- '&&' betyr 'AND', '||' betyr 'OR', men bare en '&' eller '|' betyr noe helt annet ......
- Feil bruk av parenteser:
if (a = hentTall() != 0) // 'a' blir alltid 0 eller 1. Det 'hentTall()' returnerer
....... // sammenlignes med 0. Svaret (true (1) eller false (0))
// legges inn i 'a'. Må skrive: ((a = hentTall()) != 0).
// Dermed blir 'a' tilordnet det funksjonens returverdi,
// før 'a' sammenlignes med 0.
- Løkke har intet innhold/kropp, da har brukt ';' rett etter løkketesten:
for (int i = 0; i <= 5; i++); // Løkka er tom, da ';' er brukt til slutt på linja.
cout << a[i];
- Manglende '{' og '}' rundt (en-linjes) funksjonskropp eller sammensatt uttrykk/setninger:
char ch;
cin >> ch; // Om innlest 'ch' er ulik 'n' vil
while (ch != 'n') // løkka gå uendelig da innmaten
cout << ch << ' ' << ch << '\n'; // bare er EN utskriftslinje (har glemt
cin >> ch; // omsluttende krøllparenteser).
- Uendelige løkker (pga. logisk feil i testuttrykket eller at det ikke endrer seg):
char svar;
do {
.......
cout << "Fortsette (j/n)? "; cin >> svar;
} while (svar != 'n' || svar != 'N'); // 'svar' vil alltid være ulik
// ENTEN 'n' ELLER 'N'.
- Går en for langt/kort i løkke:
int tall;
cout << "Skriv inn 7 tall: ";
for (int i = 1; i < 7; i++) // Løkka går bare 6 ganger.
cin >> tall;
- Ikke-matchende antall '{' og '}'.
- Glemmer ";" etter en-linjes if-setning:
if (a == 5)
cout << "A er lik 5" // Glemt ";" til slutt på setningen.
else
cout << "A er ulik 5";
- 'else if' brukt aller først i et testuttrykk:
else if (a >= 10) // Ikke 'else' aller først i 'if'-uttrykk.
cout << "A er større enn eller lik 10";
else if (a <= 0)
cout << "A er mindre enn eller lik 0";
else
cout << "A er større enn 0 men mindre enn 10";
- Dinglende else (pga. manglende bruk av '{' og '}' blir ikke rett 'if' og 'else' matchende hverandre):
if (a >= 0)
if (a > 100)
cout << "A er større enn 100";
else // 'else' blir tilhørende den SISTE 'if'-setningen,
cout << "A er mindre enn 0"; // selv om det visuelt ser anderledes ut.
- Bytter om bruken av 'while' og 'if':
int tall;
cout << "Skriv tall: "; cin >> tall;
if (tall <= 0 || tall > 100) { // Må bruke 'while', da ønsker egentlig å være
cout << "Skriv tall (1-100): "; // garantert at 'tall' blir mellom 1 og 100.
cin >> tall; // Her testet det bare EN gang.
}
- Manglende 'break;' i 'switch/case'-setninger:
switch (tall) {
case 1: cout << "1"; // Om 'tall' har verdien 1, vil utskriften "1234" komme.
case 2: cout << "2"; // Dette skyldes at om en 'case' er sann/true, så vil
case 3: cout << "3"; // all etterfølgende kode utføres frem til den første 'break'.
case 4: cout << "4"; // Derfor må hver 'case'-setning avsluttes med en 'break;'.
}
- Initierer arrayer eller (nestede) struct'er feil:
int a[5] = { '1', '2', '3', '4', '5' }; // int-array, ikke char-array.
eller
int b[5] = { 1, 2, 3, 4, 5, 6 }; // Legger inn et tall for mye ift.lengden.
eller
char c[] = 'TEST-TEKST'; // Tekster omsluttes av " (gåsøyne).
eller
struct A {
int b; float c;
};
struct D {
A a1, a2;
}
int main() {
D dd = { { 1, 1.1F }, { 2, 2.2 F } }; // Korrekt initiering!
.......
}
- Håndtering av hele struct'er og deres datamedlemmer:
struct A {
int b; float c;
};
A a1, a2 = { 7, 4.8F };
// Kan ikke håndtere hele struct'en som en helhet ved utskrift
cout << a2; // og innlesing. Må behandle datamedlemmene/feltene enkeltvis.
cin >> a1; // Altså: cout << a2.b << ' ' << a2.c; og cin >> a1.b >> a1.c;
a1 = a2; // Men, dette er lovlig - kopiere hele struct'er!
- Manglende ';' etter enkle uttrykk, funksjons-, struct- eller klasse-deklarasjoner:
int a(int b, int c) // Deklarasjon av/heading for funksjon. Glemt ';'.
eller
struct D { class H {
int e; ........
float f; ........
char g; ........
} } // Glemt ';' etter avsluttende '}' begge steder.
- Kaller funksjon uten tom "()":
void a() {
.......
}
int main() {
.......
a; // Glemt tom "()". Funksjonen kalles/kjøres ikke !
.......
}
- 'void'-funksjon som returnerer verdi:
void a(int b, int c) {
int d = b * c;
return d; // Returnerer verdi, selv om headingen sier noe annet.
}
- Manglende 'return' i funksjon som skal returnere en verdi:
int regnUt(int a, int b) {
int c = a * b; // Retunerer ikke svaret ('c').
}
- Verdioverføring istedet for referanseoverføring når funksjonsparametre trenger å modifiseres:
void (int a, int b) {
cin >> a; // Kun de lokale (formelle) variablene 'a' og 'b' oppdateres,
cin >> b; // og ikke de medsendte (aktuelle). Dette skyldes at '&'
} // er utelatt/glemt etter begge 'int'-ene.
- Bruk av mange globale variable (ikke feil, men dårlig programmering).
- Ikke-synlig/-tilgjengelig variabel:
void funk() {
.......
cout << ant; // "ant" er ikke tilgjengelig (usynlig),
} // da er definert inni "main".
int main() {
int ant;
.......
}
- Forvirrende bruk av (like) variabelnavn (lokale vs. globale, formelle vs. aktuelle):
int a, b;
int regnUt(int a, int b) { // Lokale 'a' og 'b' er andre variable enn de globale,
return(++a * ++b); // selv om de verdioverføres og dermed initielt
} // får de samme verdiene som de globale 'a' og 'b'.
.......
regnut(a, b);
- Bruker noe (variabel, struct, funksjon, klasse) før den er deklarert/definert:
void funk() {
cout << nr; // Bruker "nr" før den er definert.
}
int nr;
int main() {
.......
}
eller
class A {
.......
B bobj; // Lager et B-objekt, før "B" er deklarert.
};
class B {
.......
};
- Default-/standard-argumenter angis både ved deklarasjon og definisjon:
void funk(int a = 7, char ch = 'X');
int main() {
........
}
void funk(int a = 7, char ch = 'X') { // Default-argument er angitt tidligere,
........ // og skal ikke spesifiseres også her.
} // Altså bare: void funk(int a, char ch)
- Prøver å aksessere noe som er private/protected:
class A {
private:
int a;
public:
void b() { ....... }
};
int main() {
A aa;
aa.b();
aa.a = 17; // Ulovlig, da "a" er private/skjult/hidden.
.......
}
- Glemmer å angi private data/funksjoner som 'private':
class A {
// Utelatt/glemt 'private'. Egentlig helt greit, da blir ellers automatisk også 'private'.
int a; // Men en god sedvane å også angi det som 'private' som skal være det.
public:
......
......
};
- Prøver å initiere datamedlemmer ved klasse-deklarasjon:
class A {
private:
int a = 0; // Dessverre ikke lovlig/mulig å initiere dataene under
char ch = 'X'; // selve deklarasjonen. Dette må constructoren(e) gjøre.
public:
........
};
- Tror at lager nytt objekt når opprettes vha. tomme parenteser:
class A {
.......
public:
A() { ....... }
};
int main() {
A a1; // OK - objektet 'a1' opprettes/lages.
A a2(); // Intet nytt objekt opprettes/lages.
....... // Dette er deklarasjonen/prototypen for den parameterløse
} // funksjonen 'a2' som returnerer et A-objekt!
- Ombytting av ":" og "::":
class A {
.......
};
class B : public A { // Ved arv brukes EN ":"
.......
void funk();
};
void B :: funk() { // Ved klasse-tilhørighet brukes TO "::"
.......
}
- Glemmer "::" ved definisjon av medlemsfunksjon utenfor klassen:
class A {
.......
public:
void funk(); // Deklarerer medlemsfunksjon (kun heading).
};
funk() { // Skal definere medlemsfunksjonens innmat/kode,
....... // men skriver ikke "A::funk()". Derfor blir dette
} // en annen, likenavnet og "global" funksjon.
- +/-1 feil ved array-indeksering:
int a[5] = { 1, 2, 4, 8, 16 }; // Arrayen har indeksene 0-4.
for (int i = 0; i <= 5; i++) // Løkka går EN for langt.
cout << a[i];
- Array som parameter håndtert feil:
int a[10];
void funk(int b[10]);
.......
funk(a[10]) ; // Skal bare sende med 'a' og ikke "skuff"
// nr.10 (a[10]) (som faktisk ikke finnes).
- Mister/glemmer '\0' ved (manuell) strenghåndtering:
char a[] = "TEST-TEKST";
char b[10];
strncpy(b, a, 4); // '\0' blir ikke tillagt på slutten,
b[4] = '\0'; // må gjøre dette manuelt.
- Mister tekst ved blandet innlesing vha. >> og getline(...):
int a;
char b[20], c[20];
cin >> a; // >> blar seg forbi/ignorerer blanke (space), tab og linjeskift ('\n').
cin >> b; // Derfor leses det første ikke-blanke inn i 'a' og 'b'.
// Her vil 'c' kun bli fylt med en totalt tom tekst, dvs. c[0] = '\0'!
cin.getline(c, 20); // Dette skyldes at det bare ligger igjen en '\n' i inn-bufferen fra
// den forrige innlesingen. Derfor må man, når man slik veksler mellom
// lesing vha. >> og getline, avslutte forrige >> innlesing med cin.ignore();
// Dermed forkastet den igjenliggende '\n', og neste getline starter med
// totalt tomt input-buffer.
// NB: getline leser t.o.m.'\n', men denne blir ikke en del av input-teksten.
- Kaller seg selv (rekursjon), istedet for likenavnet funksjon i base-klasse:
class A {
......
public:
void display() { ..... }
};
class B :: public A {
......
public: // Kaller her seg selv uendelig.
void display() { ..... display(); ..... } // Må skrive: A::display();
};
- Overskrivende funksjoner (ved arv) skjuler også overloadede funksjoner:
class A {
......
public:
void funk(float n) { ..... }
void funk(int n) { ..... }
};
class B : public A {
......
public:
void funk(float n) { ..... }
};
int main() {
B b1;
b1.funk(3); // 'funk' i B kjøres. Så lenge de overloadede er overskrevet, så tilkalles
...... // den nærmeste (i B) - for maskinen vet hvordan konvertere int til float.
}
- Peker og/eller vanlig variabel:
char * ch1, ch2; // 'ch1' er char-peker, 'ch2' er vanlig char. Må skrive: char * ch1, * ch2;
- Peker-aritmetikk kun aktuelt ifm. arrayer:
char ch = 'A';
char* chp = &ch;
chp++; chp--; // Peker-aritmetikk på en peker som ikke peker
// til en array er meningsløst/logisk feil.
- Meningsløs peker-sammenligning/-subtraksjon:
char t1[] = "Dette er en tekst", t2[] = "mens dette er en annen tekst";
char * tp1, *tp2;
tp1 = t1+4; tp2 = t2+7; // Begge peker noe ut i hver sin tekst.
if (tp1 < tp2) ...... // Meningsløst å sammenligne eller se på forskjellen mellom
if (tp2-tp1 > 2) ...... // to pekere som refererer til hver sine (ulike) arrayer.
- Pekere ikke satt korrekt eller overskriver noe ved en feil:
char t[] = "TESTING TESTING";
char * p;
strcpy (p, "TEKST"); // 'p' inneholder tilfeldig adresse og denne overskrives.
eller
p = t + 20; // 'p' peker utenfor/etter teksten.
cout << *p;
eller
p = new char[6]; strcpy(p, "TEKST");
delete [] p;
cout << p; // Memory er egentlig frigitt, så ikke aksesser den.
- Glemmer å sette av plass også til '\0':
char t[] = "Dette er en tekst";
char* t2 = new char[strlen(t)]; // Må huske 'strlen(t)+1', ellers blir det ikke
strcpy(t2, t); // avsatt plass også til '\0' ved kopiering.
eller
char* t3 = new char[strlen(t+1)]; // Det skal være 'strlen(t)+1' (og ikke 'strlen(t+1)'),
strcpy(t3, t); // da blir det avsatt plass til 2-to tegn for lite!
- Forsøker å ta verdien til nullptr/NULL:
char * ch = nullptr;
cout << *ch; // Å ta verdien til nullptr/NULL, medfører Fatal Error under run-time.
- Peker oppdaterer noe som også pekes til av andre:
char * p, * q = "xyz";
p = q;
*(p+1) = 'X';
cout << q; // Utskriften blir "xXz", da 'q' (fortsatt) peker til den
// samme adressen (de samme verdiene) som 'p' peker til.
// Kan altså få rare bieffekter når flere peker til det samme.
- Sammenblanding ved øking av pekers verdi og innhold:
char t[] = "Dette er en tekst";
char * ch = t; // Initieres til å peke på tekstens start (bokstaven 'D').
cout << (*ch)++; // verdien der 'ch' peker økes med en, altså t[0] blir 'E'.
cout << *(ch++); // 'E' skrives ut, og pekerens innhold økes med en (til t[1] / 'e').
cout << *ch++; // = *(ch++) rett ovenfor, dvs. 'e' skrives, pekeren økes til t[2].
- Glemmer "[]" nå sletter tilpekt array:
char* p = new char[10];
.......
delete p; // Glemt "[]" ifm. slettingen/frigivelsen.
- Sier "delete" om fast array/objekt o.l:
int a[5];
int* p = a;
delete [] p; // Peker på fast array, kan ikke slette den.
- Memory-lekkasje: Glemmer å si 'delete' (i destructor) om saker
objektet/funksjoner har sagt 'new' om mens det eksisterte/levde.
- new og delete kan ikke kombineres med (C sin) malloc og free.
- Rot med peker-verdi og kommentar:
int res, a = 3;
int* b;
*b = 7;
res = a /*b; // '/*' er starten på en lengre kommentar. Må skrive: res = a / *b;
- Bytter om bruken av "." og "->":
class A {
.......
void aa() { ........ }
};
int main() {
A ao;
A* ap;
ao->aa(); // "ao" er objekt, derfor skal "." brukes.
ap.aa(); // "ap" er peker, derfor skal "->" brukes.
.......
}
- Feil bruk av "*" og "&" ifm. pekere:
char c[6] = "TEKST"; // Bruken av "*" og "&" er her korrekt:
char* p = c; // Lager char-peker, som initieres til starten på "c".
cout << &p; // Skriver ut adressen til der "p" peker (innholdet).
cout << *p; // Skriver ut char'en der "p" peker (som er 'T') (verdien).
- Tekster sammenlignes på feil måte:
char* str = new char[10];
strcpy(str, "AAA");
// Dette er helt greit true om adressen til 'str' er lavere enn
if (str < "BBB") // adressen for den midlertidige teksten "BBB" i memory!
........ // Derfor må man huske å bruke strcmp(...) ved sammenligning av tekster.
- Tror at deler med en pekers verdi, men blir starten på en kommentar (/*..... */):
int a, b = 3, c = 5;
int* d = &c;
a = b/*d; // Tror at deler 'b' med verdien av der 'd' peker.
// Men '/*' er starten på en lengre kommentar som slutter ved første '*/'.
// Må istedet skrive: a = b / *d eller a = b /(*d)
- Returnerer peker til lokal variabel:
char* funk() {
char tekst[20]; // 'tekst' er en lokal variabel/array, og fylles med verdi/tekst.
cin.getline(tekst, 20); // Returnerer man en peker til dette, så returneres en peker til et
return tekst; // uklart definert og midlertidig minneområde (stacken). Derfor må
} // man i slike situasjoner allokere nytt og permanent minneområde (heapen)
// vha.'new', kopiere aktuell tekst dit, og så si 'return' om dette.
- Husker ikke å sette det siste elementet i listen sin neste-peker til nullptr/NULL.
- Traverserer forbi en listeslutt og/eller avleser nullptr->.....:
Person* p = head;
while (p->neste->id != 99) p = p->neste; // "id" er kanskje aldri "99"
// eller p->neste == nullptr
- Glemmer å angi hva slags måte det skal arves på:
class A {
......
};
class B : A { // Utelatt/glemt 'public', arver da automatisk på en 'private' måte.
......
};
- Peker til base-klasse kan ikke peke til array med avledede objekter:
class A {
......
};
class B : public A {
......
};
int main() {
A* a1; // Pekere til base-klasse.
B barr[5]; // Array med avledede objekter.
a1 = new B; // OK at peker til avledet objekt, men får kun tak i det i 'A' og det som er virtuelt.
a1 = barr;
a1++; // Blir feil, da 'B'-objekt er større (og tar mer plass) enn 'A'-objekt.
.......
}
- Destructor i avledet klasse kalles/kjøres ikke:
class A {
// Private-området er her uinteressant.
public:
// Constructor og andre funksjoner uinteressante.
~A() { ........ } // Destructor som gjør ett eller annet.
};
class B : public A {
public:
~B() { ........ }
};
int main() {
A* bpek = new B;
.........
delete bpek; // Kun A's destructor kjøres.
....... // For å få kjørt B sin også må destructoren være virtual.
}
- Virtuell funksjon kalles ikke fra constructor i base-klasse:
class A {
public:
A() { funkA(); }
virtual funkA() { cout << '1'; }
};
class B : public A {
public:
virtual funkA() { cout << '2'; }
};
int main() {
B bobj; // Utskriften blir '1'. Base-klassens constructor kjøres før den
} // avlededes constructor. Mao. når A's constructor kjøres finnes det
// ennå ikke noe B-objekt, og dens virtueller er umulig å kalle/kjøre.
- Må selv lage overloaded '='-funksjon eller copy-constructor:
class A {
private:
char* nvn;
....... // Innmat, men ingen konstruksjon av overloaded '='
}; // eller copy-constructor.
int main() {
A a1, a2;
....... // a1.nvn settes til å peke på noe (vha. new).
a2 = a1; // Innebygd '='-funksjon eller copy-constructor kalles, der
A a3 = a1; // a2.nvn og a3.nvn blir satt til å peke på det samme som a1.nvn-peker.
....... // Antagelig ikke det vi ønsket, derfor må egne funksjoner lages
} // som selv sier 'new' og kopierer innholdet reelt over.
- Copy-constructor innholder ikke referanse-overføring (&):
class A {
public:
A() { ........ }
A(A a) { ........ } // MÅ ha: "A(A & a)", ellers vil det i det uendelig forsøkes
......... // å lage nye objekter vha. copy-constructoren!
};
int main() {
A a1; // Parameterløs constructor kjøres.
A a2(a1); // Copy-constructor kalles/kjøres.
}
- Tror at man leser fra en fil, når man egentlig ikke har funnet/åpnet den:
ifstream innfil("FILEN-MIN.DTA");
if (innfil) { // Viktig sjekk på at filen lot seg finne/åpne.
........
........
} else
cout << "Finner ikke filen 'FILEN-MIN.DTA'.";
- Feil i filnavn-path:
ifstream innfil("c:\rot\temp\noter.dta"); // Tolkes som "c:<return>ot<tab>emp<newline>oter.dta".
// Må derfor alltid bruke '\\' i filpather.
- Feil ved filinnlesing, når dette skjer ved en kombinasjon av '>>', ignore(), get(...) og getline(...).