C++ Array als Kopie an Funktion übergeben

Squicky

Lt. Commander
Registriert
Sep. 2002
Beiträge
1.422
Hallo

In einem Integer Array sind Adressen von Variablen gespeichert:

Code:
unsigned int zeigerarray[laenge];
zeigerarray[0] = (unsigned int) &var1;
zeigerarray[1] = (unsigned int) &var2;
....

Dieses Array möchte ich nun als Kopie an die Funktion
sscanf (zeichenfolge, formatzeichenfolge, zeigerarray)
übergeben.

Wie kann ich ein Array (Bytefolge) einer Funktion als Kopie (auf dem Stack?!?) übergeben?

Da sich die Länge des Arrays erst zur Laufzeit berechnet, kann man dieses Array (- nach meinem Wissen -) auch nicht in ein Struct verpacken. Oder ?!?

Danke
 
So weit ich mich erinnern kann wird bei einem Array ein Zeiger auf das Anfangsbyte des Arrays übergeben für einen Funktionsaufruf.

Somit musst du eine Kopie in der Methode selbst erstellen.



Allerdings, wenn jemand eine Möglichkeit kennt, wäre ich auch interessiert.
 
Die Funktion, die das Array bzw. die Bytefolge erhalten soll, ist eine Standardfunktion (sscanf) und kann nicht bearbeitet werden!
Die Kopie auf dem Stack muss vorher passieren.
 
Die Funktion sscanf, die ich kenne, erwartet kein zeigerarray, sondern eine Liste von Zeigern.
Also etwa: sscanf (zeichenfolge, formatzeichenfolge, &var1, &var2, &var3)
Bist du sicher, dass du weißt was du tust?
 
Zum Teil ja.
Dies funktioniert.

Code:
struct int2 {
    unsigned int a[2];
};

int main() {
    char txt[] = "abc 13 abc 25";
    char format[] = "abc %d %*s %d";
    int a, b;
    a = 0;
    b = 0;

    struct int2 ar_int2;
    ar_int2.a[0] = (unsigned int) &a;
    ar_int2.a[1] = (unsigned int) &b;

    int ret = sscanf(txt, format, ar_int2);

    cout << "ret: " << ret << " | " << a << " | " << b << endl;

    return 0;
}

Aber diese Lösung arbeitet mit einer festen Arraylänge (2), und deshalb meine Anfrage.
 
Und das soll compilen? Das bezweifel ich eher.
Code:
// http://cplusplus.com/reference/clibrary/cstdio/sscanf/
int sscanf ( const char * str, const char * format, ...);
Was willst du denn genau machen?
Code:
ar_int2.a[0] = (unsigned int) &a;
ar_int2.a[1] = (unsigned int) &b;
Kann auch so gar nicht funktionieren, schließlich ist a[0] bzw. a[1] kein Zeiger.

Und wie soll %*s in ein int gespeichert werden?
 
Ja, es compiliert und funktioniert. Aber es hat den Nachteil, dass das Array im struct int2 eine feste Länge hat!
Wie könnte man dies lösen, wenn sich die Länge des Arrays erst zur Laufzeit ergibt?
 
Du nutzt da aber üble Tricks über das verwendete Stacklayout aus.
Den Formatstring müsstest du ja ebenfalls anhand der Anzahl der zu lesenden Zahlen neu berechnen. Dein struct sähe besser so aus:

struct int2 {
int *a[2];
};

die Zuweisungen dann:

ar_int2.a[0] = &a;
ar_int2.a[1] = &b;

Warum benutzt du keine Schleife?
 
Es soll sscanf(zeichenkette, format, var1, var2, var3, ...) aufgerufen werden.

Zur Laufzeit erhält man nur
zeichenkette als chararray
format als chararray
Anzahl und Art der Variablen (sortiert)

Anzahl und Art der Variablen können mal 2 int sein. Aber bei nächsten Aufruf können es z.B. 4 Var. sein: int, flot, char und int

Wie kann man dies in einer For Schleife umsetzen?
(Die Zeichenkette könnte auch Daten enthalten die z.B. per %*d im "format" übersprungen werden.)
 
So mal als Idee: Du könntest eine union verwenden.
Code:
union data
 {
   char  cdata;
   int   idata;
   float fdata;
 };

...
 union data udata;
 char *txtptr = txt;
...

do {
 sscanf(txtptr,form,&udata);
 txtptr = strchr(txtptr,' ');
 } while (txtptr);

Nur bist du gezwungen den formatstring ebenfalls zu parsen und in einzelne Abschnitte für form zu zerlegen. Aber das musst ja sowieso, insbesondere, wenn du mit den eingelesenen Daten im Programm noch rechnen willst. Du musst ja wissen mit welchem Datentyp du jeweils zu tun hast. Wenn du den Formatstring selbst festlegen kannst, kannst du den natürlich vereinfachen.
 
r0b0t schrieb:
So mal als Idee: Du könntest eine union verwenden.
Code:
union data
 {
   char  cdata;
   int   idata;
   float fdata;
 };

...
 union data udata;
 char *txtptr = txt;
...

do {
 sscanf(txtptr,form,&udata);
 txtptr = strchr(txtptr,' ');
 } while (txtptr);

Davon möchte ich dringend abraten. Der C++-Standard sagt aus, daß in einer union immer nur eins der Member verwendet werden darf. Alles andere führt zu undefiniertem Verhalten.
Ich würde mich Blitzmerkers Vorschlag anschließen. Du programmierst in C++, also programmier auch in C++!
 
immer nur eins der Member verwendet werden darf.
Das war ja auch von mir so beabsichtigt. Das geht auch gar nicht anders, da der Speicherplatz in einer union ja nur einmal vorhanden ist. Deshalb darf dann form nur ein einzulesendes Format enthalten plus eventuelle zu überlesende Formatangaben.

sscanf("1.234","%f",&udata);
float f = udata.fdata;
sscanf("567","%d",&udata);
int i = udata.idata;
sscanf("8","%c",&udata);
char c = udata.cdata;

Dafür ist doch gerade eine union vorgesehen.
 
std::array willeine fest Größe haben --> also nicht brauchbar!
Bei std::vector fangen die Nutzdaten erst ab dem 6. oder 8 Byte an --> nicht brauchbar.

Gibt es eine Alternative zu einer zwischengeschalteten selbst geschriebenen Assemblerfunktion?
 
Ja:
std::stringstream (<sstream>)
std::istream:: operator>>
Oder auch std:: (tr1:: )regex (<regex>).

BTW: std::vector<T> a; Zugriff auf alle Elemente: &a[0] gibt dir einen Zeiger auf das Array. (Das funktioniert aber nicht mit sscanf, deine Lösung funktioniert auch nur duch Zufall).

Meine Idee, falls du tatsächlich C-Formatstrings bearbeiten musst:
Code:
string text;
string format;
format=regex_replace("%[^*][dsf]","(\\d*)");//So ungefähr, einfach das Format in einen regex umwandeln
cmatch treffer;
regex_match(text,treffer,format);
for(each treffer)
set_return_var();

Was du bisher gemacht hast, ist großer Murks. Es gibt keine Möglichkeit, eine Funktion mir variabeln Argumenten aufzurufen (eine Funktion kann aber variable Argumente annehmen, aber das ist eine andere Baustelle).

BTW:
Wie bekommst du die Information über die Variabeltypen und warum verwendest du C-Strings, wenn es C++ ist?
 
Wenn du deinen Array auf dem Stack speicherst, brauchst du auch eine feste Größe.
Wenn du deinen Array auf dem Heap erzeugst, wird auch dafür extra Speicher mit der Größe angelegt. Ob std::vector jetzt vielleicht doch 4 Byte größer ist, ist doch wohl kaum relevant, oder?

Code:
#include <string>
#include <iostream>
#include <regex>

using namespace std;

int main ()
{
  string input;
  getline(cin, input);

  regex reg("(abc)\\s+(\\d+)\\s+?(\\w+)");
  cmatch regex_results;
  regex_search(input.c_str(), regex_results, reg);

  cout << regex_results[1] << " | " << regex_results[2] << " | " << regex_results[3] << endl;
  
  return 0;
}
 
r0b0t schrieb:
Das war ja auch von mir so beabsichtigt.

Sorry, mein Fehler. :o Ich hatte deinen Code nicht gründlich genug gelesen und angenommen, du würdest einen bestimmten Member der union beschreiben und dann einen völlig anderen Member lesen. Aber das tust du natürlich gar nicht.
 
regex für C++

ist es richtig, dass es zwei regex Versionen für C++ (linux) gibt:
- boost (Externe Bib)
- regex ab c++0x

Wenn ich das Beispiel von Wurstinator mit gcc 4.6.1 und -std=c++0x teste, erhalte ich bei
Code:
regex reg("(abc)\\s+(\\d+)\\s+?(\\w+)");
ein sigabrt.

Gibt es eine Standard regex für C++ mit Release Status? (Nicht test, beta, ...)
 
Zurück
Oben