Verständnisfrage zu int *iptr = 100;

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
Terep
Beiträge: 53
Registriert: 17.01.2008, 21:20
Wohnort: Hannover Region

Verständnisfrage zu int *iptr = 100;

Beitrag von Terep »

Die Anwendung eines Zeigers ist mir klar.

Code: Alles auswählen

      int *iptr = &x;   // x ist vom Typ int
Der Zeiger iptr erhält als Wertzuweisung die Adresse von x.
Mit dem Dereferenzierungsoperatior kann mittels *iptr der Inhalt von x gezeigt oder auch geändert werden.

Was passiert aber bei der folgenden Anwendung?

Code: Alles auswählen

int *iptr = 4;   // Hier erhält der Zeiger keine Adresse sondern ein Literal (Wertzuweisung)
Ist der Zeiger in der Lage statt einer Adresszuweisung direkt einen Wert (hier int) zu speichern?
Wie läuft dies intern ab?

Terep
Avatar = „Odyssee im Weltraum“ Film von Stanley Kubrick (Warner Brothers);
nach dem Buch von Arthur C. Clarke. It will becoming true ?!!
zwergmulch
Beiträge: 91
Registriert: 07.12.2009, 16:42
Echter Name: Fabian R

Re: Verständnisfrage zu int *iptr = 100;

Beitrag von zwergmulch »

int *iprt = 4; funktioniert bei meinem VS Express 2008 garnicht (liefert error C2440: 'Initialisierung': 'int' kann nicht in 'int *' konvertiert werden
Die Konvertierung eines ganzzahligen Typs in einen Zeigertyp erfordert ein reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat
).
Heisst: Konstanten haben keine Adressen.[EDIT]Du kannst zwar (wie von sternmull richtig bemerkt) mit

Code: Alles auswählen

int* iptr = reinterpret_cast<int*> (4); 
auf die Adresse zeigen, die die Konstante meint, aber nicht auf den Literalwert.[/EDIT]
Aber wenn du

Code: Alles auswählen

int i = 5; int* iptr = &i; iptr++; 
machst, verschiebst du den Zeiger um sizeof (int) im Speicher. Wenn er also vorher an Adresse 4 war, ist er jetzt an Adresse 4 + sizeof (int). Ist aber nicht zu empfehlen, sowas zu machen. Höchstens bei Zeigern auf Elemente eines Arrays, denn da liegen die Elemente ja hintereinander im Speicher.
Zuletzt geändert von zwergmulch am 03.10.2010, 13:45, insgesamt 3-mal geändert.
Bild
Benutzeravatar
Sternmull
Establishment
Beiträge: 264
Registriert: 27.04.2007, 00:30
Echter Name: Til
Wohnort: Dresden

Re: Verständnisfrage zu int *iptr = 100;

Beitrag von Sternmull »

Zumindest GCC sagt dazu erwartungsgemäß
error: invalid conversion from ‘int’ to ‘int*’
Folgendes geht aber:

Code: Alles auswählen

int * p1 = (int*) 4; // C style cast
int * p2 = reinterpret_cast<int*>(4); // C++ reinterpret cast
Dabei wird der Integer einfach direkt als Adresse interpretiert. Das geht weil die Adresse ja auch nichts anderes als eine Zahl ist (auf gängigen Plattformen ein vorzeichenloser 32-Bit oder 64-Bit Integer) die einen Speicherplatz im Heap beschreibt (der dort nichts anderes als ein Byte-Array ist). Praktisch gesehen macht das aber nur Sinn wenn man weiß was an dieser Adresse steht, oder darauf achtet diesen Zeiger nicht als Adresse zu interpretieren.

Um deine Frage zu beantworten: Ja, man kann einen Integer (und alles andere was klein genug ist) in den Bytes ablegen die durch einen Zeiger eingenommen werden. Allerdings sollte man sich darüber klar sein was man dort tut, und z.B. aufpassen das man diese Zahl nicht versehentlich als echten Zeiger interpretiert von dem man erwartet das er auf ein brauchbares Objekt zeigt (Normalerweise geht man ja davon aus das alle nicht-Null-Zeiger auf eine Instanz zeigen).

In seltenen Fällen macht das aber Sinn. Es gibt z.B. Situationen in denen einem nur das übergeben eines void * erlaubt ist (z.B. in vielen C-Implementierungen von Listen oder bei CreateThread der WinAPI). Wenn man dabei sowieso nur etwas übergeben will das in den Bytes des void * abgespeichert werden kann, dann kann man das auch tun.
Benutzeravatar
Aramis
Moderator
Beiträge: 1458
Registriert: 25.02.2009, 19:50
Echter Name: Alexander Gessler
Wohnort: 2016
Kontaktdaten:

Re: Verständnisfrage zu int *iptr = 100;

Beitrag von Aramis »

Code: Alles auswählen

int *iptr = 4; // fehler: keine standardkonversion: const int&& nach int*
int *iptr = 0;
Zu beachten waere, dass die untere Zeile tatsaechlich funktioniert. Das liegt daran, weil '0' wenn es im rvalue einer Anweisung mit Ergebnistyp Pointer-auf-T steht, kein Integer-Literal ist, sondern das Null-Pointer-Literal (dessen Wert implementation-defined ist).

Das nur als Warnung, denn hier gibt es wirklich eine Ausnahme in der Sprache.

Ansonsten kann man sich im Normalfall drauf verlassen dass der Standard-Datentyp std::size_t die Groeße eines Pointers hat. Wenn man also von Integer nach Pointer und zurueck castet, so ist size_t gut als Integer-Datentyp geeignet.
Benutzeravatar
Terep
Beiträge: 53
Registriert: 17.01.2008, 21:20
Wohnort: Hannover Region

Präzisierung

Beitrag von Terep »

Danke für die prompte Antwort Sternmull
Ich habe es nachvollziehen können (Linux, GNU C++ Compiler).
Im Detail:

Der Standard funktioniert:

Code: Alles auswählen

#include<iostream>
using namespace std;
int main ()
{
     int x = 10;
     int *iptr = &x;
     cout << "\n\n Variable x:   " << x;       // Ausgabe:  10
     cout << "\n Zeiger *iptr: " <<*iptr;      // Ausgabe:  10
     cout << "\n\nProgrammende\n\n";
}
Auch dies ist Standard und funktioniert

Code: Alles auswählen

#include<iostream>
using namespace std;
int main ()
{
     int x = 10;
     int *iptr = &x;
      *iptr = 4;
     cout << "\n\n Variable x:   " << x;       // Ausgabe:  4
     cout << "\n Zeiger *iptr: " <<*iptr;      // Ausgabe:  4
     cout << "\n\nProgrammende\n\n";
}
Dies funktioniert nicht. Fehlermeldung des Compilers:
error: invalid conversion from ‘int’ to ‘int*’

Code: Alles auswählen

#include<iostream>
using namespace std;
int main ()
{
     int *iptr = 4;
     cout << "\n Zeiger *iptr: " <<*iptr;      
     cout << "\n\nProgrammende\n\n";
}
Kein Compilerfehler, aber bei Programmstart Fehlermeldung Speicherzugriffsfehler

Code: Alles auswählen

#include<iostream>
using namespace std;
int main ()
{
    int *iptr;
    *iptr = 4;
     cout << "\n Zeiger *iptr: " <<*iptr;      
     cout << "\n\nProgrammende\n\n";
}
Angedeutete Möglichkeit von Sternmull
Kein Compilerfehler, aber bei Programmstart Fehlermeldung Speicherzugriffsfehler
aber erst dann, wenn cout <<*p2; verwendet wird.

Code: Alles auswählen

#include<iostream>
using namespace std;
int main ()
{
    int * p2 = reinterpret_cast<int*>(4); // C++ reinterpret cast
    cout << "\n Zeiger *p2: " <<*p2;      
    cout << "\n\nProgrammende\n\n";
}
Warum funktioniert das ?

Code: Alles auswählen

#include<iostream>
using namespace std;
int main ()
{
    int * iptr = new int (4); // C++ reinterpret cast
    cout << "\n Zeiger *iptr: " <<*iptr;      // Ausgabe 4
    cout << "\n\nProgrammende\n\n";
}
Ist es so richtig?: Mit new wird Speichplatz für eine int-Variable allokiert. Intern gibt es für diesen Speicherplatz eine Adresse, die dem Anwender nicht bekannt gemacht wird, da der Zugriff über den Zeiger *iptr zustande kommt. Somit verweist der Zeiger *iptr auf eine Variable und nicht auf einen Wert. Einem int-Zeiger direkt einen Wert zuzuweisen geht nicht.

In meinem ersten Posting habe ich meine Literatur (C++ von Ulrich Breymann) falsch interpretiert.
Er schreibt zwar *ip = 99; hat aber auf der Vorseite *ip = &i, stehen und somit keine direkte Wertzuweisung getätigt.

Nicht erklären kann ich, warum die Lösung von Sternmull erst zu einer Fehlermeldung kommt, wenn der Zeiger mit cout verwendet wird.

Terep
Avatar = „Odyssee im Weltraum“ Film von Stanley Kubrick (Warner Brothers);
nach dem Buch von Arthur C. Clarke. It will becoming true ?!!
Benutzeravatar
Aramis
Moderator
Beiträge: 1458
Registriert: 25.02.2009, 19:50
Echter Name: Alexander Gessler
Wohnort: 2016
Kontaktdaten:

Re: Verständnisfrage zu int *iptr = 100;

Beitrag von Aramis »

Weil es syntaktisch in Ordnung ist -- der reinterpret_cast deaktiviert die Typchecks des Compilers mehr oder weniger komplett. Da ein Pointer auch nur ein Speicherbereich ist, der eine Zahl, eben die Adresse der Daten auf die verwiesen wird, haelt, kann er problemlos mit einer 4 belegt werden. Sobald aber drauf zugegriffen wird mit *iptr, kracht es - an Speicheradresse '4' liegen keine lesbaren Daten.

Solange du nicht drauf zugreifst (mit einer Dereferenzierung, also entweder *quak oder quak->), kannst du in einem Pointer ablegen was du willst. Ich wuerde aber eher davon abraten :-)
Benutzeravatar
Krishty
Establishment
Beiträge: 8268
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Verständnisfrage zu int *iptr = 100;

Beitrag von Krishty »

Falls du tatsächlich mal eine Indirektion mit einem Wert initialisieren willst (wobei ints ein schlechtes Beispiel sind, da sie aufgrund der geringen Größe höchstselber immer effizienter sind als Zeiger oder Referenzen), läufst du mit Referenzen deutlich geringere Gefahr, verprügelt, vergewaltigt und getötet (in beliebiger Reihenfolge) zu werden.
int const & fourLiteralRef = 4;

int four = 4;
int & fourRef = four;
int & newFourRef = *new int(4);
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Schrompf
Moderator
Beiträge: 4884
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Verständnisfrage zu int *iptr = 100;

Beitrag von Schrompf »

Krishty hat geschrieben: int & newFourRef = *new int(4);
Aua. Mach doch bitte nicht solche Beispiele vor C++-Anfängern. Die Gefahr, dass die das ausprobieren, ist viel zu hoch!
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8268
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Verständnisfrage zu int *iptr = 100;

Beitrag von Krishty »

Sorry. Ich stelle klar: Das Beispiel sollte nur illustrieren, dass man dynamisch allokierte Objekte an Referenzen binden kann. Extra für die Referenz mit new zu allokieren ist nur in ganz wenigen Ausnahmefällen sinnvoll, wovon keiner int einschließt :)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Antworten