webentwicklung-frage-antwort-db.com.de

Übergeben eines Arrays als Funktionsparameter in C++

In C++ können Arrays nicht einfach als Parameter übergeben werden. Bedeutet, wenn ich so eine Funktion erstelle:

void doSomething(char charArray[])
{
    // if I want the array size
    int size = sizeof(charArray);
    // NO GOOD, will always get 4 (as in 4 bytes in the pointer)
}

Ich kann nicht wissen, wie groß das Array ist, da ich nur einen Zeiger auf das Array habe.

Wie kann ich ohne Änderung der Methodensignatur die Größe des Arrays ermitteln und seine Daten durchlaufen?


EDIT: Nur eine Ergänzung zur Lösung. Wenn das char-Array speziell wie folgt initialisiert wurde:

char charArray[] = "i am a string";

dann ist der \0 bereits an das Ende des Arrays angehängt. In diesem Fall funktioniert die Antwort (markiert als akzeptiert) sozusagen außerhalb der Box.

17
Yuval Adam

Ohne die Signatur zu ändern? Hängen Sie ein Sentinel-Element an. Für Char-Arrays kann es sich insbesondere um den nullterminierten '\0' handeln, der für Standard-C-Strings verwendet wird. 

void doSomething(char charArray[])
{
    char* p = charArray;
    for (; *p != '\0'; ++p)
    {
         // if '\0' happens to be valid data for your app, 
         // then you can (maybe) use some other value as
         // sentinel
    }
    int arraySize = p - charArray;

    // now we know the array size, so we can do some thing
}

Natürlich kann Ihr Array selbst das Sentinel-Element nicht als Inhalt enthalten. Bei anderen Arten von Arrays (d. H. Nicht mit Chargen versehenen Arrays) kann es sich um einen beliebigen Wert handeln, der keine legalen Daten ist. Wenn kein solcher Wert vorhanden ist, funktioniert diese Methode nicht.

Darüber hinaus erfordert dies die Zusammenarbeit auf Anruferseite. Sie müssen wirklich sicherstellen, dass der Aufrufer ein Array von arraySize + 1-Elementen reserviert, und always setzt das Sentinel-Element.

Wenn Sie die Signatur wirklich nicht ändern können, sind Ihre Optionen eher begrenzt.

23
Reunanen

Verwenden Sie Vorlagen. Dies entspricht technisch nicht Ihren Kriterien, da die Signatur geändert wird, aber der aufrufende Code muss nicht geändert werden.

void doSomething(char charArray[], size_t size)
{
   // do stuff here
}

template<size_t N>
inline void doSomething(char (&charArray)[N])
{
    doSomething(charArray, N);
}

Diese Technik wird von Microsofts Secure CRT-Funktionen und von STLSoft array_proxy class-Vorlage verwendet.

38
Josh Kelley

Wenn Sie mit C oder Low-Level-C++ arbeiten, sollten Sie in der Regel eine Umschulung Ihres Gehirns in Erwägung ziehen, um niemals Array-Parameter in eine Funktion zu schreiben, da der C-Compiler sie immer als Zeiger behandelt. Wenn Sie diese eckigen Klammern eintippen, täuschen Sie sich selbst damit, dass Sie denken, dass ein reales Array übergeben wird, einschließlich der Größeninformationen. In C können Sie nur Zeiger übergeben. Die Funktion

void foo(char a[])
{
    // Do something...
}

ist aus Sicht des C-Compilers genau äquivalent zu:

void foo(char * a)
{
    // Do something
}

und offensichtlich enthält der Zeiger nekkid keine Längeninformationen.

Wenn Sie in einer Ecke stecken bleiben und die Funktionssignatur nicht ändern können, sollten Sie ein Längenpräfix wie oben vorgeschlagen in Betracht ziehen. Ein nicht portabler, aber kompatibler Hack besteht darin, die Arraylänge in einem size_t-Feld in vor dem Array anzugeben, etwa wie folgt:

void foo(char * a)
{
    int cplusplus_len = reinterpret_cast<std::size_t *>(a)[-1];
    int c_len = ((size_t *)a)[-1];
}

Offensichtlich muss Ihr Anrufer die Arrays auf geeignete Weise erstellen, bevor Sie sie an foo übergeben. 

Es ist unnötig zu erwähnen, dass dies ein schrecklicher Hack ist, aber dieser Trick kann Ärger aus der Klemme nehmen. 

6
John Källén

Es war tatsächlich eine recht gebräuchliche Lösung, die Länge im ersten Element des Arrays zu übergeben. Diese Art von Struktur wird häufig als BSTR (für "BASIC-String") bezeichnet, obwohl dies auch andere (aber ähnliche) Typen bezeichnet.

Der Vorteil gegenüber der akzeptierten Lösung besteht darin, dass das Bestimmen der Länge mit einem Wächter für große Zeichenfolgen langsam ist. Der Nachteil ist offensichtlich, dass es sich hierbei um einen eher niedrigen Level handelt, der weder Typen noch Strukturen berücksichtigt.

In der unten angegebenen Form funktioniert es auch nur für Zeichenfolgen der Länge <= 255. Dies kann jedoch leicht erweitert werden, indem die Länge in mehr als einem Byte gespeichert wird.

void doSomething(char* charArray)
{
    // Cast unnecessary but I prefer explicit type conversions.
    std::size_t length = static_cast<std::size_t>(static_cast<unsigned char>(charArray[0]));
    // … do something.
}
6
Konrad Rudolph

wenn es nullterminiert ist, würde strlen () funktionieren. 

4
Jimmy

Sie können die Größe nicht allein von charArray bestimmen. Diese Informationen werden nicht automatisch an die Funktion weitergegeben.

Wenn es sich um eine mit Null endende Zeichenfolge handelt, können Sie strlen() verwenden, aber das haben Sie wahrscheinlich bereits berücksichtigt!

Erwägen Sie, einen std::vector<char> & -Parameter oder ein Zeigerpaar oder einen Zeiger plus einen Größenparameter zu übergeben.

2
finnw

Dies ist eigentlich mehr C als C++, in C++ verwenden Sie wahrscheinlich eher einen std :: -Vektor. In C gibt es jedoch keine Möglichkeit, die Größe eines Arrays zu ermitteln. Die Kompilierung ermöglicht es Ihnen, eine sizeof durchzuführen, wenn das Array im aktuellen Bereich deklariert wurde und nur, wenn es explizit mit einer size deklariert wurde (BEARBEITEN: und "mit einer Größe" meine ich, dass es entweder mit einer ganzzahligen Größe deklariert oder bei der Deklaration initialisiert wurde, anstatt als Parameter übergeben zu werden (danke für die Downvote).

Die übliche Lösung in C besteht darin, einen zweiten Parameter zu übergeben, der die Anzahl der Elemente im Array beschreibt.

BEARBEITEN:
Entschuldigung, ich habe den Teil verpasst, die Methodensignatur nicht ändern zu wollen. Dann gibt es keine andere Lösung als die, die auch von anderen beschrieben wird. Wenn Daten innerhalb des Arrays nicht zulässig sind, können sie als Abschlusszeichen verwendet werden (0 in C-Strings, -1 ist ebenfalls üblich, hängt jedoch von Ihnen ab tatsächlicher Datentyp, vorausgesetzt das char-Array ist hypothetisch

2
falstro

Damit eine Funktion die Anzahl der Elemente in einem Array erkennt, die an sie übergeben wurden, müssen Sie eine der beiden folgenden Aktionen ausführen: 

  1. Übergeben Sie einen Größenparameter 
  2. Geben Sie die Größeninformationen in das Array ein.

Letzteres können Sie auf verschiedene Arten tun:

  • Beenden Sie es mit einem NULL-Wert oder einem anderen Anderen Sentinel, der nicht in __.
  • speichern Sie die Elementanzahl im ersten Eintrag, wenn das Array Zahlen enthält
  • einen Zeiger auf den letzten Eintrag speichern, wenn das Array Zeiger enthält
1
AShelly

versuchen Sie es mit strlen (charArray); mit der cstring-Header-Datei. Dadurch wird die Anzahl der Zeichen einschließlich Leerzeichen bis zum Schluss erzeugt. ".

0
Percy Stainwall