Du må være registrert og logget inn for å kunne legge ut innlegg på freak.no
X
LOGG INN
... eller du kan registrere deg nå
Dette nettstedet er avhengig av annonseinntekter for å holde driften og videre utvikling igang. Vi liker ikke reklame heller, men alternativene er ikke mange. Vær snill å vurder å slå av annonseblokkering, eller å abonnere på en reklamefri utgave av nettstedet.
  20 4311
Hei, Jeg har fått en innlevering (går forøvrig første året på NTNU i gjøvik) som jeg sliter med. Oppgaven er som følger:

Lag funksjonene void skrivTopper() og void Topp::skriv()
Den første funksjonen går gjennom alle toppene som er i bruk. Først skrives toppens nummer.
Deretter skrives alle toppens data (vha. den andre funksjonen). Utskriften stanser for hver tiende
Topp, og brukeren blir bedt om og må skrive ett tegn for at utskriften skal fortsette.
Vis hele sitatet...
det er en global array med objekter:

Kode

Topp   toppene[MAXTOPPER + 1];    //  Array med Topp-objekter.
og jeg prøver å loope gjennom på følgende måte

Kode

void skrivTopper() {       //  Skriver ALLE toppene:
	for (int top = 1; top < (MAXTOPPER + 1); top++) {
		cout << Topp::toppene[top];
	}
}
error koden jeg får er:

Kode

Error (active)	E0135	class "Topp" has no member "toppene"
Hadde vært flott om noen kunne forklart meg eller henvist til kilder som forklarer hvordan globale arrays fungerer mtp klasser osv.
Nå er ikke jeg så kjent med C, men det ser ut som du henter ut maks størrelse på arrayet på feil måte. Maxtopper som du deklarerer arrayet med, er kanskje ikke tilgjengelig når det kjøres. (Skal det være cout eller count i linje 3?) Anbefaler å deklarere Maxtopper som en egen variabel og bruk den direkte, eller finn funksjonen som returnerer arrayets størrelse. Sånn ville jeg gjort det i Delphi iallefall. Som sagt, jeg kan være helt på vidda. (Finnmarksvidda. Hehe!)

Du får sikkert bedre svar senere i dag.
MAXTOPPER er bare en konstant jeg har deklarert tidligere i programmet, glemte helt å legge til det hehe. Er nok ingen av de tingene som er problemet dessverre, får bare google meg litt rundt til jeg finner ut av det selv eller noen her kommer med noen innspill.
Kanskje du kan legge ut hele koden din? Det er litt lettere å finne en feil i en kode hvis man har konteksten.

Kode

#include <fstream>               //  ifstream, ofstream
#include <iostream>              //  cin, cout
#include <iomanip>               //  setw
#include <cstring>               //  strcpy, strcmp, strlen
#include <cctype>                //  toupper
using namespace std;

//  CONST:
const int STRLEN = 40;   //  Max. tekstlengde.
const int MAXETAPPER = 10;   //  Max. antall etapper.
const int MAXTOPPER = 50;   //  Max. antall topper.
const int MAXOPPOM = 10;   //  Max. topper p† EN etappe.


class Topp {            //  KLASSE:
private:
	char  navn[STRLEN];      //  Toppens navn.
	int   moh,               //  Toppens meter over havet.
		hoyde;             //  Toppens meter fra dalbunnen/stigningsstart.
	float lengde;            //  Veilengde (i km) fra dalbunnen/stigningsstart.

public:                    //  Deklarasjon av medlemsfunksjoner:
	void skriv();                         //  Oppgave 2A
	void skrivNavn();                     //  Oppgave 2B
	void lesData(char nvn[]);             //  Oppgave 2C
	bool heter(char nvn[]);               //  (Ferdigkodet)
	void lesFraFil(ifstream & inn);       //  Oppgave 2G
	void skrivTilFil(ofstream & ut);      //  Extra
};


class Etappe {
private:
	char  startsted[STRLEN];  //  Etappens startsted/-by.
	char  sluttsted[STRLEN];  //  Etappens sluttsted/-by.
	float lengde;             //  Etappens fulle lengde (i km).
	int   antTopper;          //  Totalt antall topper oppom p† etappen.
	int   topper[MAXOPPOM + 1]; //  Toppenes numre i 'toppene'-arrayen.

public:                     //  Deklarasjon av medlemsfunksjoner:
	void skriv();                         //  Oppgave 2B
	void lesData();                       //  Oppgave 2D
	bool gaarOppom(int n);                //  Oppgave 2E
	bool startSlutt(char nvn[]);          //  Oppgave 2F
	void lesFraFil(ifstream & inn);       //  Oppgave 2G
	void skrivTilFil(ofstream & ut);      //  Extra
};

//  DEKLARASJON AV FUNKSJONER:
void  skrivMeny();
char  les(char t[]);
float les(const char t[], const int min, const int max);
void  les(const char t[], char s[], const int LEN);
int   finnTopp(char nvn[]);
void  skrivTopper();           //  Oppgave 2A
void  skrivEtappe();           //  Oppgave 2B
void  nyTopp();                //  Oppgave 2C
void  nyEtappe();              //  (Ferdigkodet - men kallende skal kodes)
void  oppom();                 //  Oppgave 2E
void  starterSlutter();        //  Oppgave 2F
void  lesFraFil();             //  Oppgave 2G
void  skrivTilFil();           //  Extra


							   //  GLOBALE VARIABLE:
Topp   toppene[MAXTOPPER + 1];    //  Array med Topp-objekter.
Etappe etappene[MAXETAPPER + 1];  //  Array med Etappe-objekter.
int    sisteTopp;               //  Indeks for siste Topp hittil brukt.
int    sisteEtappe;             //  Indeks for siste Etappe hittil brukt.


int main() {           //  HOVEDPROGRAM:
	char kommando;

	lesFraFil();                               //  Oppgave 2G
	skrivMeny();

	kommando = les("nske");
	while (kommando != 'Q') {
		switch (kommando) {
		case 'P':  skrivTopper();      break;   //  Oppgave 2A
		case 'A':  skrivEtappe();      break;   //  Oppgave 2B
		case 'T':  nyTopp();           break;   //  Oppgave 2C
		case 'E':  nyEtappe();         break;   //  
		case 'O':  oppom();            break;   //  Oppgave 2E
		case 'S':  starterSlutter();   break;   //  Oppgave 2F
		case 'F':  skrivTilFil();      break;   //  Extra  
		default:   skrivMeny();        break;
		}
		kommando = les("nske");
	}
	skrivTilFil();
	cout << "\n\n";
	return 0;
}

//  *****************   DEFINISJON AV KLASSE-FUNKSJONER:  *****************

void Topp::skriv() {                    //  Skriver ALLE data:
										//  Oppgave 2A:  Lag innmaten
}

void Topp::skrivNavn() {               //  Skriver KUN navnet:
									   //  Oppgave 2B:  Lag innmaten
}

void Topp::lesData(char nvn[]) {       //  Leser alle egne data:
									   //  Oppgave 2C:  Lag innmaten
}

bool Topp::heter(char nvn[]) {          //  Returnerer 'true/false' til om
	return (!strcmp(navn, nvn));           //    toppen heter 'nvn' eller ei.
}

void Topp::lesFraFil(ifstream & inn) {  //  Leser ALT fra fil:
										//  Oppgave 2G:  Lag innmaten
}

void Topp::skrivTilFil(ofstream & ut) {  // Skriver ALT til fil:
										 //  Extra:  Lag frivillig innmaten
}

void Etappe::skriv() {                  //  Skriver ALLE data:
										//  Oppgave 2B:  Lag innmaten
}

void Etappe::lesData() {               //  Leser ALLE data:
									   //  Oppgave 2D:  Lag innmaten
}
//  Etappe g†r oppom (true)
bool Etappe::gaarOppom(int n) {        //    topp nr.'n' eller ei (false):
									   //  Oppgave 2E:  Lag innmaten
}
//  Etappe starter eller slutter
bool Etappe::startSlutt(char nvn[]) {   //    i gitt by ('nvn') eller ei.
										//  Oppgave 2F:  Lag innmaten
}

void Etappe::lesFraFil(ifstream & inn) {   //  Leser ALT fra fil:
										   //  Oppgave 2G:  Lag innmaten
}

void Etappe::skrivTilFil(ofstream & ut) {  // Skriver ALT til fil:
										   //  Extra:  Lag frivillig innmaten
}


// **********************   DEFINISJON AV FUNKSJONER:    *********************

void skrivMeny() {         //  Presenterer lovlige menyvalg:
	cout << "\n\nFLGENDE KOMMANDOER ER LOVLIG:\n";
	cout << "\tP   = skriv alle toPper\n";
	cout << "\tA   = skriv en etAppe\n";
	cout << "\tT   = ny Topp\n";
	cout << "\tE   = ny Etappe\n";
	cout << "\tO   = etapper som g†r Oppom en gitt topp\n";
	cout << "\tS   = etappe som Starter eller Slutter et gitt sted/by\n";
	cout << "\tF   = skriv til Fil\n";
	cout << "\tQ   = Quit/avslutt\n";
}


char les(char t[]) {        //  Henter ett ikke-blankt upcaset tegn:
	char ch;
	cout << '\n' << t << ":  ";   //  Skriver medsendt ledetekst.
	cin >> ch;   cin.ignore();    //  Leser ETT tegn. Forkaster '\n'.
	return (toupper(ch));         //  Upcaser og returnerer.
}

//  Leser et tall i et visst intervall:
float les(const char t[], const int min, const int max) {
	float n;
	do {                               // Skriver ledetekst:
		cout << '\t' << t << " (" << min << '-' << max << "): ";
		cin >> n;   cin.ignore();         // Leser inn ett tall.
	} while (n < min || n > max);      // Sjekker at i lovlig intervall.
	return n;                           // Returnerer innlest tall.
}

//  Leser en ikke-blank tekst:
void les(const char t[], char s[], const int LEN) {
	do {
		cout << '\t' << t << ": ";	cin.getline(s, LEN); //  Ledetekst og leser.
	} while (strlen(s) == 0);           //  Sjekker at tekstlengden er ulik 0.
}


int finnTopp(char nvn[]) {          //  Returnerer (om mulig) indeksen for
	for (int i = 1; i <= sisteTopp; i++)    //  toppen med navn lik 'nvn'.
		if (toppene[i].heter(nvn))  return i;
	return 0;                           //  Ingen match - returnerer '0'.
}


void skrivTopper() {       //  Skriver ALLE toppene:
	for (int top = 1; top < (MAXTOPPER + 1); top++) {
		cout << Topp::toppene[top];
	}
}


void skrivEtappe() {       //  Skriver EN gitt etappe:
						   //  Oppgave 2B:  Lag innmaten
}


void nyTopp() {            //  Legger inn en ny topp:
						   //  Oppgave 2C:  Lag innmaten
}


void nyEtappe() {          //  Legger inn en ny etappe:
	if (sisteEtappe < MAXETAPPER) {         //  Plass til flere:
		etappene[++sisteEtappe].lesData();    //  Ny etappe leser ALLE data selv.
	}
	else                                   //  Fullt med etapper:
		cout << "\n\n\tFullt med etapper i datastrukturen!\n\n";
}


void oppom() {              //  Etapper som g†r oppom EN gitt topp:
							//  Oppgave 2E:  Lag innmaten
}


void starterSlutter() {    //  Etappe som starter/slutter et gitt sted/by:
						   //  Oppgave 2F:  Lag innmaten
}


void lesFraFil() {        //  Leser inn HELE datastrukturen:
						  //  Oppgave 2G:  Lag innmaten
}


void skrivTilFil() {        //  Skriver ut HELE datastrukturen:
							//  Extra:  Lag frivillig innmaten
}
det er hele koden, det er en template fra læreren som vi skal fylle ut funksjonene på. Må bare nevne at jeg er ganske forvirret over alt dette klasser og objekter og destruktor, konstruktor osv. Så det kan hende jeg bare gjør noe jævlig dumt hehe
Sist endret av ClockWorx; 14. november 2017 kl. 10:52. Grunn: ekstra informasjon
Så bare veldig kjapt på dette, så mulig det er feil, men du skal vel skrive ut med "cout << toppene[top]" og ikke "cout << Topp::toppene[top]. toppene er jo en global variabel og ikke en medlem av klassen Topp som feilmeldingen sier.
Ja har prøvd dette også, men da får jeg en annen error kode, kan forsåvidt legge ved denne også.

Error (active) E0349 no operator "<<" matches these operands

Jeg googlet litt og prøvde å inkludere <string> i tillegg til <cstring> men det gjorde ingen forskjell
Sist endret av ClockWorx; 14. november 2017 kl. 11:10. Grunn: Automatisk sammenslåing med etterfølgende innlegg.
Regner med at det er fordi du prøver å skrive ut et topp objekt direkte, uten at cout vet hva som skal skrives ut. Antar du skal skrive ut navnet på toppene, da blir det i såfall "cout << toppene[top].skrivNavn()", så må du fylle ut koden i skrivNavn() også.
Her var det mye dårlig praksis. Siden dette er et eksempel fra læreren din, så antar jeg at han har bakgrunn fra C og har lært seg C++ uten å sette seg ordentlig inn i det.

Det du prøver å skrive ut i 'void skrivTopper()' funksjonen er klassen selv. Dette hadde fungert om du har en statisk konstant variabel med navn 'toppene' på innsiden av klassen topp, som er en array. Men utfra oppgaven å tolke, så ønsker du å skrive ut navnet på toppene fra 'Topp' instansene 'toppene'. Men siden 'navn' er deklarert som en 'private' klasse attribute på innsiden av klassen 'Topp', så må du implementere 'Topp::skrivNavn()' metoden først.

Kode

void Topp::skrivNavn()
{
    cout << this -> navn << endl;
}
For så å etter på implementere funksjonen 'void skrivTopper()'

Kode

void skrivTopper() {       //  Skriver ALLE toppene:
	for (int top = 1; top < (MAXTOPPER + 1); top++) {
		toppene[top].skrivNavn();
	}
}
C++ har mange og bedre måter både å håntere stringer på, som 'std::string' og kontainere til å håndtere arrays, som 'std::array', 'std::list', 'std::vector' o.l. Noe som gjør håndteringen av disse objektene mye mer trivielt. Hvorfor læreren din har valgt å bruke 'char []' (char arrays) til strings og rå arrays til å lagre instansene av 'Topp' må du nesten spørre han om.

I tillegg så virker det litt som han har missforstått prinsippen med OOP (Objekt Orientert Programmering) og ansvar området til de enkelte metodene. Blant annet så har han deklarert «les» og «skriv» metoder fra std(in/out) og filer inn i både klasssen Topp og Etappe. Det hadde vært en mye bedre praksis å implementere «getters» og «setter» i disse klassene og heller laget eksterne funksjoner eller eksterne klasser til å ta seg av jobben med å fylle opp og skrive ut data fra disse.
Sist endret av 0xFF; 14. november 2017 kl. 12:08.
Har fått med meg at læreren ikke er helt med, han er dårlig til å formulere oppgaver og forelesningene hans er generelt sett dårlige. Må jo bare ta det som en lærerik opplevelse og heller lære meg de litt "bedre" praksisene på egen hånd, takk for svar skal prøve ut dette nå! Et kvikt spørsmål bare, "this ->" har jeg sett tidligere, men forstår ikke helt hva den gjør. Fungerer den slik at den alltid vil bruke det klasseobjektet som blir benyttet for øyeblikket slik at man slipper å bytte om dette?

ville for eksempel noe slikt være mulig?

Kode

void Topp::skriv() {                    //  Skriver ALLE data:
	cout << this->navn;
	cout << this->moh;
	cout << this->hoyde;
	cout << this->lengde;			
}
Ville dette skrevet ut hvert enkelt objekts informasjon hvis jeg looper gjennom alle objektene?
Sist endret av ClockWorx; 14. november 2017 kl. 12:39. Grunn: Automatisk sammenslåing med etterfølgende innlegg.
Sitat av ClockWorx Vis innlegg
Har fått med meg at læreren ikke er helt med, han er dårlig til å formulere oppgaver og forelesningene hans er generelt sett dårlige. Må jo bare ta det som en lærerik opplevelse og heller lære meg de litt "bedre" praksisene på egen hånd, takk for svar skal prøve ut dette nå! Et kvikt spørsmål bare, "this ->" har jeg sett tidligere, men forstår ikke helt hva den gjør. Fungerer den slik at den alltid vil bruke det klasseobjektet som blir benyttet for øyeblikket slik at man slipper å bytte om dette?

ville for eksempel noe slikt være mulig?

Kode

void Topp::skriv() {                    //  Skriver ALLE data:
	cout << this->navn;
	cout << this->moh;
	cout << this->hoyde;
	cout << this->lengde;			
}
Ville dette skrevet ut hvert enkelt objekts informasjon hvis jeg looper gjennom alle objektene?
Vis hele sitatet...
Ja, 'this' er en pointer som alltid peker til bunnen av sin egen klasse. Så hvis du jobber på innsiden av en metode som tilhører klassen 'Topp', så vil 'this' peke til bunnen av klassen 'Topp'. Og legg merke til at når jeg sier bunnen, så mener jeg ikke bunnen av klassen bokstavelig, men heller toppen.

Grunnen til at jeg sier bunnen er fordi når koden din blir kompilert, så vil det som oftest (jeg kan ikke si alltid, siden det finnes rimelig mange minne/CPU arkitekturer og systemer i verden) føre til at «starten» av klassen din ligger på et lavere minne adresse en egenskapene og metodene i klassen gjør. Hvis du ser på eksemplet under:

Kode

#include <cstdlib>
#include <iostream>

class Foo
{
        private:
                int a;
                int b;
                int c;

        public:
                std::ptrdiff_t diff_a(); // Henter differancen mellom this -> a og this oppgitt i byte
                std::ptrdiff_t diff_b(); // Henter differancen mellom this -> b og this oppgitt i byte
                std::ptrdiff_t diff_c(); // Henter differancen mellom this -> c og this oppgitt i byte
};

std::ptrdiff_t Foo::diff_a()
{
        std::ptrdiff_t address_this = reinterpret_cast<std::ptrdiff_t>(this);
        std::ptrdiff_t address_a = reinterpret_cast<std::ptrdiff_t>(&(this -> a));

        return(address_a - address_this);
}

std::ptrdiff_t Foo::diff_b()
{
        std::ptrdiff_t address_this = reinterpret_cast<std::ptrdiff_t>(this);
        std::ptrdiff_t address_b = reinterpret_cast<std::ptrdiff_t>(&(this -> b));

        return(address_b - address_this);
}

std::ptrdiff_t Foo::diff_c()
{
        std::ptrdiff_t address_this = reinterpret_cast<std::ptrdiff_t>(this);
        std::ptrdiff_t address_c = reinterpret_cast<std::ptrdiff_t>(&(this -> c));

        return(address_c - address_this);
}

int main(int argc, char **argv)
{
        Foo foo;

        std::cout << "&(this -> a) - this = " << foo.diff_a() << std::endl;
        std::cout << "&(this -> b) - this = " << foo.diff_b() << std::endl;
        std::cout << "&(this -> c) - this = " << foo.diff_c() << std::endl;

        return(EXIT_SUCCESS);
}
Output:

Kode

&(this -> a) - this = 0
&(this -> b) - this = 4
&(this -> c) - this = 8
Så vil du se at 'this' peker til samme adresse som 'this -> a' (0 i differanse mellom disse to). Mens 'this -> b' ligger 4 byte over minne adressen til 'this' eller 'this -> a' (int er normalt 4 byte, altså &(this -> a) + 4) og samme med c. Så når man sier at den peker til bunnen av en klasse, så mener man med andre ord toppen.
Sist endret av 0xFF; 14. november 2017 kl. 13:29.
Sitat av ClockWorx Vis innlegg
Har fått med meg at læreren ikke er helt med, han er dårlig til å formulere oppgaver og forelesningene hans er generelt sett dårlige. Må jo bare ta det som en lærerik opplevelse og heller lære meg de litt "bedre" praksisene på egen hånd, takk for svar skal prøve ut dette nå! Et kvikt spørsmål bare, "this ->" har jeg sett tidligere, men forstår ikke helt hva den gjør. Fungerer den slik at den alltid vil bruke det klasseobjektet som blir benyttet for øyeblikket slik at man slipper å bytte om dette?

ville for eksempel noe slikt være mulig?

Kode

void Topp::skriv() {                    //  Skriver ALLE data:
	cout << this->navn;
	cout << this->moh;
	cout << this->hoyde;
	cout << this->lengde;			
}
Ville dette skrevet ut hvert enkelt objekts informasjon hvis jeg looper gjennom alle objektene?
Vis hele sitatet...
Jepp, du har forstått korrekt: 'this' henviser til runtime objektinstansen av klassen som blir beskrevet, og er en peker. For å aksessere (verdien til) minneområdet som pekeren peker til (pekerens verdi er en minneadresse (se: Stack/Heap)) gjør man en såkalt 'dereferencing', og C++ definerer piloperatøren (->) synonymt med dereferencing av en peker.

Generelt vil

Kode

MittObjekt->ObjektMetode();
være det samme som

Kode

(*MittObjekt).ObjektMetode();
Takk, det var en nyttig ting å vite! Skal prøve å jobbe meg videre i oppgavene nå, så kommer jeg tilbake hvis det er noe mer jeg lurer på !

Er nå på en ny oppgave:
Den første funksjonen skriver en melding om det ikke er plass til flere topper i datastrukturen.
I motsatt fall leses en potensielt ny topps navn. Om denne allerede finnes (bruk ferdiglaget
funksjon) kommer det en melding. I motsatt fall tas en ny Topp i bruk, og den leser alle sine data
selv (vha. den andre funksjonen). Husk å bruke ferdiglagde funksjoner, der du sender med noen
rimelige tallverdier som parametre.
Vis hele sitatet...
Jeg forstår ikke hvordan jeg skal kunne vite om etappe arrayen er full eller om den har plass til flere elementer? Tenkte først at kanskje jeg kunne sjekke siste indeks for 0, men i c++ blir vel arrays som ikke er definert bare tildelt tilfeldige minneverdier. Noen hint?

EDIT: Da fant jeg ut at jeg bare kan bruke samme "oppsett" som på nyEtappe som er ferdiglagd av læreren, så det var vel ikke så vanskelig hehe.
Sist endret av nso; 14. november 2017 kl. 16:18. Grunn: endret html til quote
Sitat av ClockWorx Vis innlegg
Takk, det var en nyttig ting å vite! Skal prøve å jobbe meg videre i oppgavene nå, så kommer jeg tilbake hvis det er noe mer jeg lurer på !

Er nå på en ny oppgave:
Den første funksjonen skriver en melding om det ikke er plass til flere topper i datastrukturen.
I motsatt fall leses en potensielt ny topps navn. Om denne allerede finnes (bruk ferdiglaget
funksjon) kommer det en melding. I motsatt fall tas en ny Topp i bruk, og den leser alle sine data
selv (vha. den andre funksjonen). Husk å bruke ferdiglagde funksjoner, der du sender med noen
rimelige tallverdier som parametre.
Vis hele sitatet...
Jeg forstår ikke hvordan jeg skal kunne vite om etappe arrayen er full eller om den har plass til flere elementer? Tenkte først at kanskje jeg kunne sjekke siste indeks for 0, men i c++ blir vel arrays som ikke er definert bare tildelt tilfeldige minneverdier. Noen hint?
Vis hele sitatet...
Jeg forsto ikke helt hva oppgaven gikk ut på, den var dårlig formulert. Men jeg kan prøve å svare på spørsmålet ditt. Du har to variabler som forteller deg dette, 'MAXETAPPER' beskriver antall elementer i arrayen 'etappene'. Og 'sisteEtappe' holder siste index som er lagt til, så du må huske å øke 'sisteEtappe' med 1 hver gang du legger til et nytt element i arrayen. Så du må sjekke at 'sisteEtappe' ikke overskrider 'MAXETAPPER'.

Men som tidligere sagt, så er dette en idiotisk måte å gjøre det på. Rå arrayer tilhører en tid der C var «the shit». I C++ så behandles disse mye bedre og enklere ved å bruke template kontainere som std::array, std::list, std::vector o.l. I ditt tilfelle så hadde det vært perfekt å bruke en dynamisk allokert template kontainer som std::vector.

Kode

#include <cstdlib>
#include <iostream>
#include <vector>

class Topp
{
        public:
                int x;
};

int main(int argc, char **argv)
{
        std::vector<Topp> foo;  // Deklarerer 'foo' som en 'std::vector' som består av 'Topp' elementer
        Topp a;
        Topp b;
        Topp c;                 // Deklarerer 3 instanser av 'Topp' klassen.

        a.x = 1;
        b.x = 3;
        c.x = 12;               // Gir 'x' i de 3 instansene av 'Topp' klassen verdier.

        foo.push_back(a);
        foo.push_back(b);
        foo.push_back(c);       // Pusher de 3 instansene av 'Topp' klassen inn i std::vector kontaineren.

        std::cout << "Størrelsen av foo: " << foo.size() << std::endl;

        // Man kan få tilgang til 'foo' elementene på flere måter:
        // 1: Bruk av foo.at() metoden

        for (size_t i = 0; i < foo.size(); i++)
        {
                std::cout << "foo.at(" << i << ").x: " << foo.at(i).x << std::endl;
        }

        // 2: Bruk av klammeparenteser

        for (size_t i = 0; i < foo.size(); i++)
        {
                std::cout << "foo[" << i << "].x: " << foo[i].x << std::endl;
        }

        // 3: Bruk av iteratorer
        // Vanligvis skrives for looper på en linje.
        // Men jeg har splittet den over tre linjer for å kunne kommentere hver del.

        for(    auto foo_it = foo.begin();      // Deklarere og assigne std::vector<Topp>::iterator fra foo.begin()
                foo_it != foo.end();            // Sjekke at iteratoren ikke er på ended av foo
                ++foo_it)                       // Increase iteratoren
        {
                std::cout << "std::vector<Topp>::iterator: " << foo_it -> x << std::endl;
        }

        return(EXIT_SUCCESS);
}
Output:

Kode

Størrelsen av foo: 3
foo.at(0).x: 1
foo.at(1).x: 3
foo.at(2).x: 12
foo[0].x: 1
foo[1].x: 3
foo[2].x: 12
std::vector<Topp>::iterator: 1
std::vector<Topp>::iterator: 3
std::vector<Topp>::iterator: 12
std::vector er dynamisk allokert, det vil si at du trenger ikke å tenke på størrelsen til den. Når du pusher et nytt element inn, så tar std::vector kontaineren seg av allokering av minne, samme når du sletter elementer i fra den. Så den vil alltid ha riktig størrelse.

Men det kan godt tenkes at læreren deres ønsker at dere skal lære å håndtere rå arrays, jeg gjør deg bare oppmerksom på at det finnes mer sofistikerte og effektive måter å gjøre det på.
Sist endret av nso; 14. november 2017 kl. 16:18.
EDIT2: Jeg sitter litt fast, har følgende kode:

Kode

void nyTopp() {            //  Legger inn en ny topp:
	char toppNavn[STRLEN];
	if (sisteTopp < MAXTOPPER) {         //  Plass til flere:

		cout << "skriv ny toppnavn: ";
		cin >> toppNavn;

		if (finnTopp(toppNavn) == 0) {
			
			toppene[++sisteTopp].lesData(toppNavn);
		}
		else 
		{
			cout << "Den toppen eksisterer allerede.";
		}
	}
	else {
		cout << "\n\n\tFullt med topper i datastrukturen! \n\n";
	}	
}
Problemet er nå når jeg skal bruke lesData() funksjonen, jeg forstår ikke helt hvordan jeg kan instantiate et nytt objekt med navnet som er lest inn, tenkte noe alla dette:

Kode

void Topp::lesData(char nvn[]) {       //  Leser alle egne data:
	nvn.navn = les();
	nvn.moh = les();
	nvn.hoyde = les();
	nvn.lengde = les();
}
men dette er det jo åpenbart mange problemer med, så hvis noen kunne hintet meg i riktig retning ville det vært flott
nso
popålol
nso's Avatar
Administrator
Sitat av 0xFF Vis innlegg
Men som tidligere sagt, så er dette en idiotisk måte å gjøre det på. Rå arrayer tilhører en tid der C var «the shit». I C++ så behandles disse mye bedre og enklere ved å bruke template kontainere som std::array, std::list, std::vector o.l. I ditt tilfelle så hadde det vært perfekt å bruke en dynamisk allokert template kontainer som std::vector.
Vis hele sitatet...
Spørsmålet er vel hva som er mest hensiktsmessig og logisk lettforståelig for en som parallelt med å skrive oppgaven også driver å lærer seg hva et array er (og basert på oppgaveteksten kan de ikke ha bevege seg så alt for langt forbi det punktet). Jeg kan se for meg tilfeller hvor det er hensiktsmessig å lære dem the old way (tm) fordi det er lettere å forstå hva som foregår.
Sist endret av nso; 14. november 2017 kl. 16:25.
Har fått med meg at læreren ikke er helt med, han er dårlig til å formulere oppgaver og forelesningene hans er generelt sett dårlige. Må jo bare ta det som en lærerik opplevelse og heller lære meg de litt "bedre" praksisene på egen hånd, takk for svar skal prøve ut dette nå! Et kvikt spørsmål bare, "this ->" har jeg sett tidligere, men forstår ikke helt hva den gjør. Fungerer den slik at den alltid vil bruke det klasseobjektet som blir benyttet for øyeblikket slik at man slipper å bytte om dette?
Vis hele sitatet...
Har du spørsmål, så er både læreren og fagassistenter ofte tilgjengelig, anbefaler å bruke dem. Anbefaler også å gjøre ukeoppgaver da de dekker veldig mye av innholdet og gjør oppgaven mer forståelig.
Jeg forstår ikke hvordan jeg skal kunne vite om etappe arrayen er full eller om den har plass til flere elementer? Tenkte først at kanskje jeg kunne sjekke siste indeks for 0, men i c++ blir vel arrays som ikke er definert bare tildelt tilfeldige minneverdier. Noen hint?
Vis hele sitatet...
Hvordan å sjekke det? Er jo veldig logisk. Den er full når den har nådd MAX. if\else setning forteller deg fort om den er full eller ikke. Dette er noe vi lærte ganske tidlig i år.
C++ har mange og bedre måter både å håntere stringer på, som 'std::string' og kontainere til å håndtere arrays, som 'std::array', 'std::list', 'std::vector' o.l. Noe som gjør håndteringen av disse objektene mye mer trivielt. Hvorfor læreren din har valgt å bruke 'char []' (char arrays) til strings og rå arrays til å lagre instansene av 'Topp' må du nesten spørre han om.
Vis hele sitatet...
Det er HELT riktig. Hadde ClockWorx fulgt med i timen, hadde han fått med seg at læreren sa at vi kommer til å lære om pekere over jul. Poenget til læreren at vi lærer oss "den vanskelige måten" først, slik at vi forstår hvordan ting fungerer, for så lære enklere løsninger. Nå tror jeg ikke at 0xFF er en lærer, og tror heller ikke at han er med i timene våre. Derfor er det vanskelig fra hans ståsted å avgjøre læringsprosessen og opplegget til læreren vår.
Om du bruker THIS (altså pekere) i oppgaven din, vil den sannsynligvis ikke bli godkjent.

Ser at du sliter med veldig mye her ellers. Du bør følge bedre med i timene samt bruke tid på "hands-on". Det vil nok bidra til utviklingen mer enn å si at læreren er dårlig fordi du ikke forstår. Det er forøvrig universitet; det meste skal du lære på egenhånd.

Sitat av nso Vis innlegg
Spørsmålet er vel hva som er mest hensiktsmessig og logisk lettforståelig for en som parallelt med å skrive oppgaven også driver å lærer seg hva et array er (og basert på oppgaveteksten kan de ikke ha bevege seg så alt for langt forbi det punktet). Jeg kan se for meg tilfeller hvor det er hensiktsmessig å lære dem the old way (tm) fordi det er lettere å forstå hva som foregår.
Vis hele sitatet...
Godt svart (y)
Sist endret av Morsken; 15. november 2017 kl. 12:48. Grunn: Automatisk sammenslåing med etterfølgende innlegg.
Ok, klarte å få det til slikleis:

Kode

void Topp::lesData(char nvn[]) {      
	Topp nvnn;
	char moh1[] = "Meter over havet?";
	char hoyde1[] = "Hoyde fra start?";
	char lengde1[] = "lengde fra start?";

	strcpy(nvnn.navn, nvn);
	nvnn.moh = les(moh1, 0, 8848);
	nvnn.hoyde = les(hoyde1, 0, 8848);
	nvnn.lengde = les(lengde1, 0, 50);
}
Og med denne

Kode

void nyTopp() {            //  Legger inn en ny topp:
	char toppNavn[STRLEN];
	if (sisteTopp < MAXTOPPER) {         //  Plass til flere:

		cout << "skriv ny toppnavn: ";
		cin >> toppNavn;

		if (finnTopp(toppNavn) == 0) {
			
			toppene[++sisteTopp].lesData(toppNavn);
		}
		else 
		{
			cout << "Den toppen eksisterer allerede.";
		}
	}
	else {
		cout << "\n\n\tFullt med topper i datastrukturen! \n\n";
	}	
}
Nå lurer jeg på følgende oppgave:

Lag funksjonen void Etappe::lesData()
Funksjonen, som kalles av den ferdiglagde nyEtappe(), leser inn alle etappens data, inkludert
alle toppene den går innom. Husk at en topp angis kun vha. dets indeks i toppene. Bruk aktivt
ulike les(). Vi forutsetter at enhver etappes antTopper er mindre eller lik sisteTopp. Du
slipper å sjekke at brukeren skriver samme toppnummer flere ganger, at en og samme topp også
inngår på et urimelig antall andre etapper eller at to etapper faktisk blir helt identiske.
Vis hele sitatet...
Det jeg sliter med er å finne ut av hvor mange topper etappen går innom og hvordan jeg skal gjengi dette. Tenkte først noe alla dette:

Kode

	for (int i = 0; i < (sizeof(toppene) / sizeof(toppene[0])); i++) {
		char etappeTopp[STRLEN];
		cout << "\nTopper som inngår i etappen, nr " << i + 1 << ": ";
		cin >> etappeTopp;
		finnTopp(toppene[i].navn);
	}
men det fungerer jo ikke da, den vil fortsette å spørre helt til alle toppene er gjennomgått, og alle toppene er jo ikke på alle etappene.

Dette er forøvrig hele funksjonen jeg har så langt:

Kode

void Etappe::lesData() {               
	Etappe nyEtappe;
	const char start[STRLEN] = "Startsted?";
	const char slutt[STRLEN] = "Sluttsted?";
	const char lengde1[STRLEN] = "Lengde i km?";
	const int lengden = STRLEN;
	char startSvar[STRLEN];
	char sluttSvar[STRLEN];
	
	les(start, startSvar, lengden);
	les(slutt, sluttSvar, lengden);

	for (int i = 0; i < (sizeof(toppene) / sizeof(toppene[0])); i++) {
		char etappeTopp[STRLEN];
		cout << "\nTopper som inngår i etappen, nr " << i + 1 << ": ";
		cin >> etappeTopp;
		finnTopp(toppene[i].navn);
	}

	strcpy(nyEtappe.startsted, startSvar);
	strcpy(nyEtappe.sluttsted, sluttSvar);
	nyEtappe.lengde = les(lengde1, 0, 50);
	nyEtappe.antTopper = 
}
Sist endret av ClockWorx; 15. november 2017 kl. 13:17. Grunn: Automatisk sammenslåing med etterfølgende innlegg.
void Topp::lesData(char nvn[]) {
Topp nvnn;
char moh1[] = "Meter over havet?";
char hoyde1[] = "Hoyde fra start?";
char lengde1[] = "lengde fra start?";

strcpy(nvnn.navn, nvn);
nvnn.moh = les(moh1, 0, 8848);
nvnn.hoyde = les(hoyde1, 0, 8848);
nvnn.lengde = les(lengde1, 0, 50);
}
Vis hele sitatet...
Hvorfor lager du nye arrayer her? De eksisterer jo fra før av. les funksjonen du bruker behøver kun tekst, altså moh = les("Meter over havet?", 0, 8848) i neste linje kan du erstatte tallet 8848 med moh, siden høyde kan ikke overstige moh. Si du skriver moh er 4000, da må jo begrensningen gå på 4000 og ikke 8848.
const char start[STRLEN] = "Startsted?";
const char slutt[STRLEN] = "Sluttsted?";
const char lengde1[STRLEN] = "Lengde i km?";
Vis hele sitatet...
det samme gjelder her. Unødvendig å lage nye arrays

for (int i = 0; i < (sizeof(toppene) / sizeof(toppene[0])); i++) {
char etappeTopp[STRLEN];
cout << "\nTopper som inngår i etappen, nr " << i + 1 << ": ";
cin >> etappeTopp;
finnTopp(toppene[i].navn)
Vis hele sitatet...
Bør sette i = 1 her istedenfor. Du har dessuten en fin variabel som heter sisteTopp som forteller deg hvilken topp som er sist brukt. Slik slipper du å gå igjennom de ubrukte verdiene i arrayen.
Sist endret av Morsken; 15. november 2017 kl. 15:47.
Sitat av ClockWorx Vis innlegg
Ok, klarte å få det til slikleis:

Kode

void Topp::lesData(char nvn[]) {      
	Topp nvnn;
	char moh1[] = "Meter over havet?";
	char hoyde1[] = "Hoyde fra start?";
	char lengde1[] = "lengde fra start?";

	strcpy(nvnn.navn, nvn);
	nvnn.moh = les(moh1, 0, 8848);
	nvnn.hoyde = les(hoyde1, 0, 8848);
	nvnn.lengde = les(lengde1, 0, 50);
}
Og med denne

Kode

void nyTopp() {            //  Legger inn en ny topp:
	char toppNavn[STRLEN];
	if (sisteTopp < MAXTOPPER) {         //  Plass til flere:

		cout << "skriv ny toppnavn: ";
		cin >> toppNavn;

		if (finnTopp(toppNavn) == 0) {
			
			toppene[++sisteTopp].lesData(toppNavn);
		}
		else 
		{
			cout << "Den toppen eksisterer allerede.";
		}
	}
	else {
		cout << "\n\n\tFullt med topper i datastrukturen! \n\n";
	}	
}
Nå lurer jeg på følgende oppgave:


Det jeg sliter med er å finne ut av hvor mange topper etappen går innom og hvordan jeg skal gjengi dette. Tenkte først noe alla dette:

Kode

	for (int i = 0; i < (sizeof(toppene) / sizeof(toppene[0])); i++) {
		char etappeTopp[STRLEN];
		cout << "\nTopper som inngår i etappen, nr " << i + 1 << ": ";
		cin >> etappeTopp;
		finnTopp(toppene[i].navn);
	}
men det fungerer jo ikke da, den vil fortsette å spørre helt til alle toppene er gjennomgått, og alle toppene er jo ikke på alle etappene.

Dette er forøvrig hele funksjonen jeg har så langt:

Kode

void Etappe::lesData() {               
	Etappe nyEtappe;
	const char start[STRLEN] = "Startsted?";
	const char slutt[STRLEN] = "Sluttsted?";
	const char lengde1[STRLEN] = "Lengde i km?";
	const int lengden = STRLEN;
	char startSvar[STRLEN];
	char sluttSvar[STRLEN];
	
	les(start, startSvar, lengden);
	les(slutt, sluttSvar, lengden);

	for (int i = 0; i < (sizeof(toppene) / sizeof(toppene[0])); i++) {
		char etappeTopp[STRLEN];
		cout << "\nTopper som inngår i etappen, nr " << i + 1 << ": ";
		cin >> etappeTopp;
		finnTopp(toppene[i].navn);
	}

	strcpy(nyEtappe.startsted, startSvar);
	strcpy(nyEtappe.sluttsted, sluttSvar);
	nyEtappe.lengde = les(lengde1, 0, 50);
	nyEtappe.antTopper = 
}
Vis hele sitatet...
Tror du må poste en oppdatert kode her eller på pastebin, for det er ganske opplagt at du behøver hjelp med å rydde opp i den og organisere koden. Hele poenget med OOP eller programmering generelt er å gjenbruke kode, jo mer kode man kan gjenbruke, jo bedre. Også er det viktig å avgjøre variabler scopen slik at man unngår å deklarere for mange unødvendig variabler, men samtidig passe på at variabler ikke lever lengere enn nødvendig.
Sist endret av 0xFF; 15. november 2017 kl. 19:14.
Eg går samme linje, og er nå på siste året. Det eg anbefaler trådstarter er å lese bloggen til Bjarne Stroustrup, og flittig bruk av cppreference og C++CoreGuidelines. Da får du ein ide om kva C++ er. Kan vere ubehagelig å møte opp på eit C++ intervju og vise fram noko slikt. Skaff deg gjerne ei bok om OOD (Object Oriented Design) mens du først er i gang.

Om ingen nye regler har kommet (som det gjerne ikkje har siden 1990-tallet) så tillater ikkje lektor bruk av STL, med mindre unntak står skrevet/oppgitt i timen. Unntakene er bibliotek for lesing og skriving til filer. Vi klarte å klore oss til `std::string` noko dere burde gjer om dette fortsatt ikkje er "innafor".