Hilfe zu getpwent()
-
AbsoluterBeginner schrieb:
//...
void setMember(struct passwd *pwd);
//...Solche Konstrukte sehe ich zwar von Zeit zu Zeit, ich finde aber das es dem Sinn eines Konstruktors wiederspricht wenn er sich eben nicht um die Initialisierung seiner Member kümmert.
Zudem rufst du den Konstruktor auch auf und hinterlässt einen unsinnigen User wenn die Funktion "getpwent()" keine Rückgabe liefert.
//... User::User() //: <-- Hier kommentierst du gerade das aus, was ein Konstruktor eigentlich // verwenden sollte: die Initialisierungsliste zur Memberinitialisierung... { // So etwas habe ich nur unter C jemals gesehen... // struct passwd *pwd = getpwent(); // ...in C++ würde es einfach nur... passwd *pwd = getpwent(); // ... lauten if (pwd != NULL) //check if there is a entry setMembers(pwd); // <-- hier hinterlässt du ein unfertiges und unnötiges Objekt wenn pwd 0 ist }Ich würde statt dessen den Aufruf außerhalb erledigen und den Konstruktor wie folgt definieren:
User::User(struct passwd *pwd) : d_username(pwd->pw_name), d_password(pwd->pw_passwd), d_homedir(pwd->pw_dir), d_uid(pwd->pw_uid), d_gid(pwd->pw_gid), d_realname(pwd->pw_gecos), d_homedir(pwd->pw_dir), d_shellprog(pwd->pw_shell), { }Zudem empfinde ich es als fehlerträchtige Unsitte Allozierung/Freigabe bzw. Ressourcenanforderung und Freigabe zu trennen. Für mich gehört das "endpwent()" in die gleiche Funktion/Methode wie die Abfragen.
AbsoluterBeginner schrieb:
dann noch die diversen getter dazu eine frage, ich habe zB:
#include “user.ih” string const &User::getHomedir() const { return d_homedir; }Ich hoffe du schreibst nicht jede Funktion in separate Sourcedateien, den Includes nach würde ich das hierbei fast annehmen.
AbsoluterBeginner schrieb:
warum ist hier das & vor user? hab das von den folien der vorlesung uebernommen, also der prof wird sich was dabei gedacht haben, ich verstehe es nicht.
Du kannst es auch
string const & User::getHomedir() const
oder
const string & User::getHomedir() const
schreiben. Das Ändert nichts an dieser Funktion.Das "&" steht für eine Referenz, auch Aliasname genannt. Das heißt, diese Memberfunktion/Methode gibt keine Kopie (was ich üblicher finde), sondern eine Referenz zurück (sprich arbeitet auf einer bestehenden Variable ohne den Inhalt zu kopieren).
AbsoluterBeginner schrieb:
ich les das ganze so:
das const ganz rechts heißt das diese funktion nicht gaendert wird.Das const ganz rechts heißt, das diese Memberfunktion/Methode das Objekt selbst nicht ändert. Lokale Variablen etc. kann es aber dennoch ändern, nur keine Membervariablen.
AbsoluterBeginner schrieb:
dann das ich eine methode der kalsse user, und zwar getHomedir implementiere.
und zuletzt das diese einen konstanten string zurueckgibt.Du gibst eine Konstante Referenz auf die Membervariable zurück. Etwas das ich mir nie angewöhnt habe, und selbst auch wohl nie machen werde. Dies mag zwar performanter sein als wenn ich eine Kopie zurückgebe, ich schränke die Schnittstelle in meinen Augen aber zu sehr ein (Wenn ich später z.B. einige Member in ein anderes Objekt verschiebe oder gar erst in der Funktion zusammensetze, dann kann ich keine konstante Referenz mehr verwenden).
cu André
-
hallo, echt vielen dank fuer all die hinweise.
zu meiner verteidigung, ja ich mache fuer jede funktion eine eigene datei, ist vom professor gewuenscht. ob es gut ist oder nicht kann ich erst sagen wenn ich mehr c++ programmiert habe....was mit nicht eingeht is der punkt:
passwd *pwd = getpwent();ich verstehe eigentlich auch mein altes:
struct passwd *pwd = getpwent();nicht.
laut definition: Die Funktion getpwent() gibt die passwd-struktur zurück oder NULL, wenn keine weiteren Einträge vorhanden sind.also sollte dies funktionieren:
struct passwd = getpwent();dann einen pointer auf das struct:
.. da haperts ein bissl...
bei bp int habe ich: int *pa = &a; (wenn a eine int variable ist)
bei struct ist ja passwd der typ also: passwd *pwd = &passwd; (wenn es wie bei arrays ist das der name des struct auf den ersten speicher zeigt)
richtig?also ist es bei deiner loesung so das du einen pointer definierst der auf den typ passwd zeigt. und diesem gibst du aber ein komplettes struct. also ist es wie bei arrays oder?
*bisschenkonfused*
danke fuer die hilfe!
p.s.: bezueglich des unfertigen objects klar - danke, muss noch gemacht werden

-
Die Funktion getpwent() gibt die passwd-struktur zurück oder NULL
Dieser Satz geht so nicht. NULL ist kein gültiger Wert für ein struct.
Was NULL sein kann (und wahrscheinlich auch gemeint ist), ist ein Zeiger auf ein struct.bei struct ist ja passwd der typ also: passwd *pwd = &passwd; (wenn es wie bei arrays ist das der name des struct auf den ersten speicher zeigt)
richtig?also ist es bei deiner loesung so das du einen pointer definierst der auf den typ passwd zeigt. und diesem gibst du aber ein komplettes struct. also ist es wie bei arrays oder?
Ich bin nicht sicher, ob ich dich richtig verstehe, aber ich würde mal sagen "Nein".
Wenn passwd ein Objekt ist, dann ist &passwd (Adressoperator angewendet) der Zeiger auf das Objekt. (Sofern kein eigener & - Operator definiert wurde).
Aber man kann auch ein Array von Objekten haben, was sich äquivalent zu eingebauten Datentypen verhält.
struct foo {}; foo f; //ein Objekt von foo foo* pf = &f; //ein Zeiger auf ein foo-Objekt foo af[2]; //Array von 2 foo Objekten pf = af; // Geht auch, dann musst du bei der benutzung von pf aber wissen, wieviele Objekte dahinter sind!
-
asc meinte eigentlich, dass bei
struct passwd *pwd = getpwent();das struct unnötig ist. Der Compiler weiß auch so das passwd ein struct-Typ ist. Diese Art der Deklaration ist bei C notwendig.
-
AbsoluterBeginner schrieb:
...ja ich mache fuer jede funktion eine eigene datei, ist vom professor gewuenscht. ob es gut ist oder nicht kann ich erst sagen wenn ich mehr c++ programmiert habe....
Himmel hilf, und das sage ich als Atheist. Professoren sollten mal zu einen Jahr praktischer Arbeit zwangsverpflichtet werden. Wie soll dabei die Übersicht gewahrt bleiben?
Normalerweise: Eine Klasse, ein Header, eine Sourcedatei.
AbsoluterBeginner schrieb:
was mit nicht eingeht is der punkt:
passwd *pwd = getpwent();ich verstehe eigentlich auch mein altes:
struct passwd *pwd = getpwent();nicht.
passwd * pwd = getpwent();
passwd ist der Typ, pwd die Variable, * dazwischen heißt, das es sich um eine Zeigervariable handelt. Und diese Variable wird mit der Rückgabe von getpwent() initialisiert, den die Funktion scheint ja einen Zeiger auf eine passwd-Struktur zurück zu geben. Ein Zeiger ist NULL/0 wenn er auf nichts zeigt, und ansonsten beinhaltet er die Adresse.
Die Angabe "struct" davor ist in C++ unnötig und mehr als ungewöhnlich (dies wäre in C anders).
AbsoluterBeginner schrieb:
laut definition: Die Funktion getpwent() gibt die passwd-struktur zurück oder NULL, wenn keine weiteren Einträge vorhanden sind.
Ein wichtiger Unterschied: Sie gibt einen Zeiger auf eine passwd-struktur zurück, oder NULL. Sie gibt keine passwd-struktur zurück.
AbsoluterBeginner schrieb:
also sollte dies funktionieren:
struct passwd = getpwent();Nein, zumal selbst wenn sie ein Objekt zurückgeben würde, wäre die Syntax falsch:
// Unter der annahme das getpwent() ein Objekt liefert, und keinen Zeiger passwd psw = getpwent();1. Das struct ist auch hier verkehrt, dies wäre eine C-syntax
2. Du benötigst immer noch eine Variable die das Objekt aufnimmt, das wäre psw in diesen Fall (auch wenn ich keine Abkürzungen mag).
3. Und jetzt solltest du dir nochmal den Unterschied zwischen Zeigern und Objekten anschauen und verstehen.Dies wäre ein Objekt:
[ pw_name = "abc"... ]Ein Objekt ist etwas mehr oder weniger Greifbares, und hat konkrete Werte (im Gegensatz zu einer Struktur oder Klasse die nur angibt was für Arten von Werten sie enthalten kann, ist ein Objekt ein konkreter Fall der Klasse/Struktur).
Ein Zeiger ist aber nicht das Objekt. Nehmen wir von oben mal wieder das Objekt auf, es liegt irgendwo im Speicher - sagen wir einmal an der Adresse 0x4711:
0x4711 [ pw_name = "abc"... ]
Ein Zeiger hält die Adresse, in dem Fall die 0x4711, nicht das Objekt selber:
Zeiger, enthält Adresse
[0x4711]
Objekt, enthält konkrete Werte
[ pw_name = "abc"... ]Ein Objekt kann nicht NULL sein, ein Zeiger kann wiederum den Wert 0 annehmen, da es nur ein Integer ist (der eine Adresse darstellt).
AbsoluterBeginner schrieb:
bei bp int habe ich: int *pa = &a; (wenn a eine int variable ist), bei struct ist ja passwd der typ also: passwd *pwd = &passwd; (wenn es wie bei arrays ist das der name des struct auf den ersten speicher zeigt)
richtig?Jein, nicht ganz richtig aber auch nicht ganz falsch, die Formulierung gefällt mir nicht:
int a = 4; int * pa = &a;a ist nun eine Integervariable mit den Wert 4 (und sagen wir, diese Variable beginnt an der Speicheradresse 0x0815). pa ist auch eine Variable (besitzt auch eine eigene Speicheradresse, auch wenn dies hier erstmal egal ist), und zwar vom Typ: Zeiger auf int. Dieser Weisen wir nun die Adresse von a zu. Sprich pa enthält danach die Speicheradresse von a, in dem Fall 0x0815.
Soweit richtig.
AbsoluterBeginner schrieb:
...bei struct ist ja passwd der typ also: passwd *pwd = &passwd; (wenn es wie bei arrays ist das der name des struct auf den ersten speicher zeigt)
struct ist nur eine Angabe, das es sich um eine Struktur handelt. Die Struktur passwd hat den Aufbau wie unter der Manpage beschrieben. pwd ist nun die Variable, eine Variable des Typs: "Zeiger auf eine passwd-Struktur". Und ja, diese zeigt auf den Speicherbeginn der Struktur.
AbsoluterBeginner schrieb:
also ist es bei deiner loesung so das du einen pointer definierst der auf den typ passwd zeigt. und diesem gibst du aber ein komplettes struct. also ist es wie bei arrays oder?
Ich finde Arrays unter C die Wurzel aller Erklärungsübel. Ja, in gewisser Weise hast du recht, nur das Arrays sich von Haus aus eher wie Zeiger verhalten als irgendetwas anderes. Wenn ich jemanden C++ beibringe lasse ich Arrays aber aus guten Grund lange Zeit aus (und erkläre sie auch nur damit man weiß um was es sich handelt, den std::vector und std::tr1::array halte ich für deutlich verständlicher, wenn man den mal vom Namensraum absieht).
cu André
-
auch ein herzliches dankeschoen an die beiden letzen poster!
bin nun schlauer
werde mich sicher noch ein mal melden - heheschoenen tag noch!
-
AbsoluterBeginner schrieb:
auch ein herzliches dankeschoen an die beiden letzen poster!
Och.. und was ist mit mir.

-
haha dich habe ich auch gemeint, habe nur uebersehen das auf der 2ten seite auch noch etwas steht

hmm zu deiner erklaerung mittels pointer habe ich dann noch eine frage...
Ein Objekt kann nicht NULL sein, ein Zeiger kann wiederum den Wert 0 annehmen, da es nur ein Integer ist (der eine Adresse darstellt).
dass habe ich mir auch shcon gedacht, dass ein zeiger imme rgleich groß ist. egal auf was er zeigt.
warum muss ich dann dem compiler mitteilen ob mein zeiger jetzt auf ein int oder ein float zeigt?
oder wird es eh nur dazu gebraucht damit der programmierer wieß wie weit er zb im speicher gehen kann bis er die naechste variable erreicht?
das wuerde mir klar erscheinen
und bzgl der einzelnen datei, ja habe ich mir auch gedacht aber er wird schon seine gruende haben. glaub mir der programmiert genug

schoenen tag noch...
-
dass habe ich mir auch shcon gedacht, dass ein zeiger imme rgleich groß ist. egal auf was er zeigt.
warum muss ich dann dem compiler mitteilen ob mein zeiger jetzt auf ein int oder ein float zeigt?
oder wird es eh nur dazu gebraucht damit der programmierer wieß wie weit er zb im speicher gehen kann bis er die naechste variable erreicht?Typsicherheit. Ansonsten könnte man ja gleich mit void* arbeiten..
Du kannst auch einen int in z.b Meine_Super_Klasse casten. Aber versuch nachher ja nicht etwas mit dem (nicht existenten) Objekt zu machen.
Wenn du jetzt einen normalen Zeiger hast, kann dir so eine Fehler ( zumindest Compileseitig) nicht passieren.
-
AbsoluterBeginner schrieb:
dass habe ich mir auch shcon gedacht, dass ein zeiger imme rgleich groß ist. egal auf was er zeigt.
warum muss ich dann dem compiler mitteilen ob mein zeiger jetzt auf ein int oder ein float zeigt?
Neben der bereits erwähnten Typsicherheit, alleine schon für die Zeigerarithmetik.
Sei pa ein Zeiger auf einen Typ T. Dann wird ++pa um genau die Länge des Typs T weiterspringen. Dies macht sich auch ein Array zunutze.
AbsoluterBeginner schrieb:
und bzgl der einzelnen datei, ja habe ich mir auch gedacht aber er wird schon seine gruende haben. glaub mir der programmiert genug

Dann müssen sich Hunderte C++ Programmierer in verschiedenen Projekten und Firmen in denen ich bislang gearbeitet habe irren.
Professoren an Unis sind - ohne es böse zu meinen - meist sehr fern ab jedweder echter Praxis (Zumindestens ist dies eine Erfahrung die ich gemacht habe). Zumindestens kennen viele keine Projekte aus der freien Marktwirtschaft, und diese laufen unter anderen Rahmenbedingungen als im Uni- und Forschungsbereich ab.
Wobei ich auch durchaus Professoren kenne die in der Praxis tätig waren und sind, deren Lehrstil hat sich zumindestens für mich wahrnehmbar, massiv von der rein theoretischen Betrachtung unterschieden.
cu André