2013-11-13, 02:06
  #1
Medlem
Hur kommer det sig att detta fungerar? Efter att man använt z i detta fall så kommer det ju städas från stacken, så hur kan man skicka tillbaka en referens till z till main och sedan skriva ut det från main i variabeln c? Det bör ju inte gå, eftersom z kommer städas bort från stacken så fort man kört funktionen. Eller är det så att det gamla värdet fortfarande står kvar i minnet på den minnesplatsen den hade i funktionen triangle och inte ännu har skrivits över men kommer att skrivas över så småning om?

double* triangle(double *tal1, double *tal2)
{
double z = (*tal1 * *tal2)/2;
return &z;
}

int main()
{
double a = 6, b = 8;
double* c = triangle(&a, &b);
cout << *c << endl;
return 0;
}
Citera
2013-11-13, 02:43
  #2
Medlem
Ger inte kompilatorn ifrån sej en varning om att skicka pekare till deallokerat utrymme ?

Vore intressant om koden kudne testas på olika kompilatorer o se vad som händer ?

Annars så är det med de primitiverna, dvs de basala typerna såsom char, int, long, double etc att de inte riktigt följer reglerna exakt, ofta så är det värdekopiering som gäller.

Det är mkt möjligt att referensen finns kvar till ett utrymme på stacken, men det är inte säkert, tex så kan kompilatorn optimera koden istället så att ngt av registerna används och då finns värdet ändå kvar.

Testa tex att loopa funktionen med ett helt set av värden, ev kan du oxå göra en djup rekursion för att vara säker på att stacken utnyttjas, typ..
Citera
2013-11-13, 03:06
  #3
Medlem
Uran233s avatar
Citat:
Ursprungligen postat av Janejja
Hur kommer det sig att detta fungerar? Efter att man använt z i detta fall så kommer det ju städas från stacken, så hur kan man skicka tillbaka en referens till z till main och sedan skriva ut det från main i variabeln c? Det bör ju inte gå, eftersom z kommer städas bort från stacken så fort man kört funktionen. Eller är det så att det gamla värdet fortfarande står kvar i minnet på den minnesplatsen den hade i funktionen triangle och inte ännu har skrivits över men kommer att skrivas över så småning om?

Stacken som datastruktur finns inte mer än som en enda pekare till den aktuella toppen av stacken. C kommer inte rénsa stacken, alltså, den kommer inte skriva över det minne stackframen använde, det enda den gör är att sätta om den aktuella stackpekaren till det undansparade pekaren till den anropande stacken. z finns kvar tills det stackområdet används igen. C gör ingenting i bakgrunden eg, det är ju det som är både styrkan och svagheten i C. C är inget högnivåspråk, snarare ett mellannivåspråk. En slags portabel assembler.
__________________
Senast redigerad av Uran233 2013-11-13 kl. 03:18.
Citera
2013-11-13, 03:30
  #4
Medlem
Citat:
Ursprungligen postat av Uran233
Stacken som datastruktur finns inte mer än som en enda pekare till den aktuella toppen av stacken. C kommer inte rénsa stacken, alltså, den kommer inte skriva över det minne stackframen använde, det enda den gör är att sätta om den aktuella stackpekaren till det undansparade pekaren till den anropande stacken. z finns kvar tills det stackområdet används igen. C gör ingenting i bakgrunden eg, det är ju det som är både styrkan och svagheten i C. C är inget högnivåspråk, snarare ett mellannivåspråk. En slags portabel assembler.

Men då kan det vara så att jag tänkte rätt kan man säga? Förutom att stacken rensas dvs.
Citera
2013-11-13, 03:38
  #5
Medlem
Uran233s avatar
Citat:
Ursprungligen postat av Janejja
Men då kan det vara så att jag tänkte rätt kan man säga? Förutom att stacken rensas dvs.

Ja. Jag skulle rekommendera dig att läsa http://en.wikibooks.org/wiki/X86_Disassembly/The_Stack , egentligen hela wikibooken, tar upp en del om hur C funkar "behind the scene".
Citera
2013-11-13, 08:24
  #6
Medlem
Kod:
   |             |
   | odefinierat |
   +-------------+ <-- SP
   | double *c   |
   | double b    |
   | ...         |
   | double a    |
   | ...         |
   +-------------+
   | startup-    |
   | kodens      |
   | variabler   |
   +-------------+
   | nåt annat   |
   | programs    |
   | variabler   |
   +-------------+
   | osv...      |
---+-------------+---
 BOTTEN AV STACKEN

Såhär skulle stacken kunna se ut när triangle() ska anropas. main() kommer åt sina variabler relativt via stackpekaren, t.ex. *SP för c och *(SP + 4) för b. Vid anropet ökas/minskas SP uppåt (det finns stackar som börjar på en låg adress och ökar, och de som börjar på en hög adress och minskar) för att ge plats för triangle()s parametrar och lokala variabler. Argumenten kopieras, resten av variablerna lämnas odefinierade och kontrollen överförs till triangle(). När triangle returnerar, minskas/ökas SP tillbaka igen och kontrollen överförs till main() som fortsätter att komma åt sina variabler via SP som om inget hade hänt.

Så ett funktionsanrop och en returnering går enormt fort. Det är egentligen bara kopieringen av argumenten som tar tid, och eventuell initialisering av variabler. Själva "allokeringen" av minnet får man nästan gratis (bara ändra SP).

Sen tillkommer returadresser, returvärden och att processorer har ett gäng register som är mycket snabbare att arbeta med än mot RAM. En kompilator kan t.ex. välja att istället spara undan ett par register på stacken, låta den anropade funktionen använda dem fritt, och återställa dem från stacken efteråt.
Citera
2013-11-13, 13:44
  #7
Medlem
Citat:
Ursprungligen postat av Uran233
Stacken som datastruktur finns inte mer än som en enda pekare till den aktuella toppen av stacken. C kommer inte rénsa stacken, alltså, den kommer inte skriva över det minne stackframen använde, det enda den gör är att sätta om den aktuella stackpekaren till det undansparade pekaren till den anropande stacken. z finns kvar tills det stackområdet används igen. C gör ingenting i bakgrunden eg, det är ju det som är både styrkan och svagheten i C. C är inget högnivåspråk, snarare ett mellannivåspråk. En slags portabel assembler.

Det stämmer bra, bra analys, det är riktigt att minnet som z upptar i triangle (om det nu finns på stacken ) finns kvar o med samma värde efter anropet, en eventuell pekare till det minnet är hellt legal och ingen sk wild pointer (pekare som pekar mot ett deallokerat utrymme). Även om det rent filosofiskt är en sk wild pointer.

Funktionen och main är så små att de kan säkeert köras med enbart registerna inblandade.

Det är riktigt att C inte rensar stacken (skriver nollor på oanvänt utrymme), istället återanvänds utrymmet nästa gång en funktion anropas oo körs. Det är bara stackpekaren som flyttas upp ellr ner, precis som Uran233 skriver.

Det finns en hyfsad sammanfattning här:
http://www-ee.eng.hawaii.edu/Courses...on2.1.1.8.html

Skulle va kul om ngn kunde köra koden i en debugger o testa ?
Citera

Skapa ett konto eller logga in för att kommentera

Du måste vara medlem för att kunna kommentera

Skapa ett konto

Det är enkelt att registrera ett nytt konto

Bli medlem

Logga in

Har du redan ett konto? Logga in här

Logga in