Wie ermittle ich die Größe eines Arrays wenn ich nur einen Pointer darauf habe?

#1
Hallo zusammen,
ich lerne gerade C++ in Eigenregie.
Beim Programmieren bin ich auf eine Situation gestoßen, bei der ich nicht mehr weiter weiß.
Wie kann ich die Größe eines Arrays ermitteln wenn ich nur einen Pointer darauf habe?
Etwa wenn es sich dabei um die Rückgabe einer Funktion handelt, die ich gar nicht geschrieben habe.
Wäre es ein char-Array, würde ich auf die string-Bibliothek wetten.
Obwohl auch das ein wenig unbefriedigend für mich wäre, denn so verstehe ich nicht die Mechanismen.
Es geht aber ganz allgemein um Arrays. Also nicht um jenes eines bestimmten Typs.
Vielleicht kann mir jemand einen Schubs in die richtige Richtung geben?

Lieben Gruß
Blue
 

German

Well-Known Member
c-b Experte
#3
In C++ wirst du nicht viel mit natürlichen Arrays und Pointern arbeiten. Dafür gibt es Klassen, wie bspw. std::vector und Referenzen statt Pointern.
Ansonsten ist es ganz einfach - wenn du nur einen Pointer auf das erste Element in einem Array hast, kannst du grundsätzlich nicht dessen Länge ermitteln. Und, falls du einen Pointer auf ein lokales Array in einer Funktion zurückgibst, ist dieser bereits ungültig wenn die Funktion beendet wird (falls es sich nicht um einen statischen Speicherbereich handelt). Außerdem haben natürliche Arrays immer eine feste Breite, wozu also eine Länge ermitteln. Die weißt du bereits beim Schreiben des Codes.
 
#4
Ich denke das es sich um ein std::array handelt.
Zumindest habe ich ein

using namespace std;

im Code stehen.
Das Array gibt es auch noch nach Beenden der Funktion. Da bin ich sicher, weil ich es ausprobiert habe.
Genau genommen handelte es sich um einen Linux-Systemaufruf. Der gab mir Informationen zum aktuellen Nutzer zurück.
Was da genau zurückgegeben wurde muss ich noch einmal nachsehen.
Ich habe den Code gerade nicht da.
Werde mich da aber auf jeden Fall schlau machen.

Gruß
Blue
 

-AB-

Well-Known Member
c-b Team
c-b Experte
#6
Ich denke das es sich um ein std::array handelt.
Zumindest habe ich ein

using namespace std;
....Ich glaube nicht. :)

Genau genommen handelte es sich um einen Linux-Systemaufruf. Der gab mir Informationen zum aktuellen Nutzer zurück.
Mhm, die Linux-Systemaufrufe sind (soweit ich weiß) alle reines C.

Die Doku sollte dir verraten ob du den Pointer, den zu zurück bekommst, löschen darfst(oder musst), und sollte dir auch sagen, ob das mit free oder delete geschehen soll.
Das ist alles so eine C-Geschichte.
Über sowas muss man in C++ normalerweise nicht so viel nachdenken.... :/

Jedenfalls, wenn du nur einen Pointer bekommst, sagt dir dieser nicht, wie viele Elemente dahinter noch dazu gehören.
In einem "C-String" wird dafür ein Wert, '\0' bzw NULL, für das Ende verwendet. Üblicherweise bekommt man für andere Daten die Anzahl/Länge des Arrays mitgeteilt.
 
#7
Hi,
ich habe den Code jetzt vorliegen.
Bitte entschuldigt wenn das bis jetzt alles ein wenig wirr war.
Zwischen der Erstellung des Codes und dem Post hier lag schon einige Zeit.

Das Programm soll prüfen ob eine fest eincodierte Verzeichnisstruktur schon besteht.
Wenn nicht soll sie angelegt werden.
Die eigentliche Idee dahinter ist mein Betriebssystem besser kennen zu lernen und , was die Programmierung betrifft, einfach nur möglichst viel dazuzulernen.
Learning by doing also.
Hier ist die relevante Stelle in meinem Quellcode:
Code:
uid_t BeforeWork::nutzer()
{
    uid_t userID = getuid();
    return userID;
}

char *BeforeWork::homeVerzeichnis(uid_t userID)
{
    struct passwd *pas_ptr;
    pas_ptr = getpwuid(userID);
    cout << userID << endl;
    char *verzeichnis = pas_ptr->pw_dir;
    cout << verzeichnis << endl;
    return verzeichnis;
}
Der Aufruf getpwuid(uid_t) gibt ein struct zurück.
Dessen Aufbau ist in pwd.h beschrieben.
pw_dir ist ein char Pointer.
Diese Referenz speichere ich in meiner Funktion in einen eigenen Pointer.
Wie das Array erstellt wird auf das pw_dir zeigt ist mir unklar und ich fand auch nichts dazu.
Trotzdem lässt sich das Array auslesen.

Das die Linux-Systemaufrufe in C geschrieben sind stimmt schon.
Ich dachte, ich könne sie ohne weiteres in mein C++ Programm integrieren.
Der Umkehrschluss wäre ja, dass alle Programme welche solche Aufrufe nutzen, in C geschrieben sein müssten.
Das wäre doch nicht sehr pragmatisch. (So meine Überlegungen)

Ich hoffe mein Problem ist etwas klarer geworden.
Am Code habe ich jetzt nicht bewusst gespart, ich wollte ihn nur so übersichtlich als nur möglich halten.
Wenn mehr benötigt wird, gebe ich gerne Auskunft.

Gruß
Blue
 

asc

Well-Known Member
c-b Experte
#8
In der manpage steht ausdrücklich:
The return value may point to a static area, and may be overwritten by subsequent calls to getpwent(3), getpwnam(), or getpwuid(). (Do not pass the returned pointer to free(3).)
Also einfach so lassen wie es ist. Nicht freigeben oder herumreichen (es sei denn du kopierst dir die Struktur oder deren Eigenschaften).
 
#9
So weit so gut.
Aber ändert das jetzt etwas an meinem Problem?
Ich möchte je auf das Array direkt zugreifen.
Also die Größe ermitteln.
Und im zurück gegebenen struct sind ja nur Pointer.
 

asc

Well-Known Member
c-b Experte
#10
Welches Array denn? Die char* Felder? Das sind Null-terminierte Strings.
Kannst du dir mit strdup() oder strcpy() (+ calloc/malloc via strlen) kopieren. Bzw. in C++ mit std::string(pw_dir).

Oder willst du die komplette Struktur kopieren?
 

German

Well-Known Member
c-b Experte
#11
Zurückgegeben wird ein Pfad, also ein nullterminierter C-String. Hier kannst du mit strlen() ran. Aber warum meinst du das überhaupt zu brauchen? Und warum initialisierst du nicht einfach einen std::string mit dem zurückgegebenen C-String, schließlich willst du ja mit C++ arbeiten. Dann hast du keine Sorgen mehr.
 
Gefällt mir: asc
#12
Danke.
Ihr habt mir sehr geholfen.
Ich weiß nicht was ich mir gedacht hatte, aber ich war auf dem Holzweg.
Der von euch beschriebene Weg funktioniert einwandfrei.
Ich habe trotzdem noch einige Fragen für das Verständnis:
Strings sind im Grunde char-Arrays mit Null-terminierung. Dabei unterscheidet sich aber die Typbezeichnung.
Ist das soweit richtig?
Bei Arrays wird sowieso nur mit Pointern gearbeitet. Also call-by-reference.
In der Pointer-Variable befindet sich aber nur eine Speicheradresse.
Der Compiler dereferenziert die Variable automatisch wenn beispielsweise das Array mit cout ausgegeben werden soll?
 

-AB-

Well-Known Member
c-b Team
c-b Experte
#13
Ich dachte, ich könne sie ohne weiteres in mein C++ Programm integrieren.
Kannst du.

Bloß stoßen dann ein paar Programmierparadigmen zusammen. Saubererweise trennst du C/C++ soweit möglich in deinem Code, und greifst z.B. nur in der einen Funktion/Klasse auf die C-Schnittstellen zu, und außerhalb behältst du den C++-Weg bei.

Sprich, um mich meinen früh aufstehenden Vorrednern anzuschließen, am besten du kopierst den zurückgegebenen C-String (nullterminiertes char-array) in einen std::string, indem du einfach den std::string mit dem c-string initialisierst.
:)

Strings sind im Grunde char-Arrays mit Null-terminierung. Dabei unterscheidet sich aber die Typbezeichnung.
Jein. Ein C-String (weil... es in C keine Strings gibt) ist ein char-Array, dessen letztes Zeichen NULL ist.
Ein C++ (std:.string) ist eine Klasse, die intern irgendwo einen Pointer hält auf einen Speicherbereich, der vermutlich nullterminiert ist, es aber nicht sein muss. Dafür hat die Klasse noch einen Member, der die Länge speichert.

Wenn du einen C-String "kopierst" (also den Pointer kopierst), dann zeigen zwei Pointer auf denselben String. Um den Wert zu kopieren musst du mit strcpy etc arbeiten.
Wenn du einen C++-String kopierst, hast du zwei Strings, die du unabhängig voneinander ändern kannst.

Bei Arrays wird sowieso nur mit Pointern gearbeitet. Also call-by-reference.
Eigentlich call-by-pointer, aber prinzipiell..... Ja.

Der Compiler dereferenziert die Variable automatisch wenn beispielsweise das Array mit cout ausgegeben werden soll?
Nein, aber es gibt einen überladenen ostream <<-Operator, der Zeichen für Zeichen ausgibt, bis er die Nullterminierung erreicht. Der Operator selbst bekommt aber noch schön einen Pointer. (Sonst bekäme er auch nur den Wert des ersten Zeichens.)
 
Oben