2 strings aus Funktion übergeben
-
Hallo zusammen,
als fortgeschrittener Neuling bin ich gerade dabei, ein CGI in C zu schreiben. Dabei wird als Grundlage die Berkeley DB dienen, welche mir nach entsprechender Abfrage einen Hash, bzw. 2 Strings zurückgeben wird: String 1: Datum (z.B. "2010-07-01") und String 2: (z.B. "Passender Hashwert, welcher Plain Text ist.").
Um diese beiden Strings in weiteren Funktionen manipulieren und ausgeben zu können, müssen die ausgegebenen Hash-Werte der Berkeley DB in Variablen geschrieben- und weiter verarbeitet werden.
Wenn ich bis jetzt einen String übergeben wollte, habe ich bis jetzt immer einen Zeiger zurückgegeben, der auf den Anfang des Strings gezeigt hat. Bei 2 Strings funktioniert diese Methode natürlich nicht.
Daher meine Frage: Was wäre hier der Königsweg, um performant die beiden Strings in weiteren Funktionen zu benutzen? Meine Ideen dazu sind:
- Mit globalen Pointern arbeiten, die auf den Anfang der beiden Strings zeigen
- Beide Strings in einen zusammenfassen. Da das Datum immer gleich lang sein wird könnte man so den 2. Hashwert mit "pointer + 8" aufrufen. Der Nachteil hierbei wäre, so wie ich das sehe eine geringere Performance.
Über Ideen würde ich mich freuen.
Beste Grüße
Jan
P.S. Es geht um folgendes Projekt:
http://forum.ubuntuusers.de/topic/projektidee-hochperformantes-blog-in-c-unter-/
-
Die beiden Idee finde ich nicht gut. Stattdessen könntest du einfach deine 2 Strings (ob jetzt fixe char-Arrays, wenn die maximale Länge bekannt ist, oder zur Not halt Zeiger auf dynamischen Speicher...) in eine Struktur packen. Somit hast du einen Typ, den du dann als Rückgabe der Funktion nutzen kannst. Eine Alternative wären by-reference Parameter.
- Beide Strings in einen zusammenfassen. Da das Datum immer gleich lang sein wird könnte man so den 2. Hashwert mit "pointer + 8" aufrufen. Der Nachteil hierbei wäre, so wie ich das sehe eine geringere Performance.
Begründung?
-
jAIk schrieb:
Wenn ich bis jetzt einen String übergeben wollte, habe ich bis jetzt immer einen Zeiger zurückgegeben, der auf den Anfang des Strings gezeigt hat. Bei 2 Strings funktioniert diese Methode natürlich nicht.
Was hindert dich daran zwei Zeiger zu übergeben?
mfg Martin
-
Danke für die schnellen Antworten:
Was hindert dich daran zwei Zeiger zu übergeben?
Bitte nicht lachen, aber ich dachte immer, dass mit "return" immer nur ein Wert zurückgegeben werden könnte.
Die beiden Idee finde ich nicht gut. Stattdessen könntest du einfach deine 2 Strings (ob jetzt fixe char-Arrays, wenn die maximale Länge bekannt ist, oder zur Not halt Zeiger auf dynamischen Speicher...) in eine Struktur packen. Somit hast du einen Typ, den du dann als Rückgabe der Funktion nutzen kannst. Eine Alternative wären by-reference Parameter.
Klingt für mich sehr gut - warum sollte ich nur "zur Not" Zeiger auf dynamischen Speicher zeigen lassen? Ich sehe (mit meinen geringen Grundkenntnissen) bei der Verwendung von char-Arrays nur längeren Code und keine direkten Vorteile - aber wahrscheinlich übersehe ich dann etwas :).
Beste Grüße
Jan
-
Die lösung für dein Problem wird warscheinlich so aussehen:
void Funktion(char *String1,char *String2);
Du brachst gar kein return...
-
jAIk schrieb:
Was hindert dich daran zwei Zeiger zu übergeben?
Bitte nicht lachen, aber ich dachte immer, dass mit "return" immer nur ein Wert zurückgegeben werden könnte.
Ist auch so. Du kannst nur einen Wert eines Typs zurückgeben. Dieser Typ darf aber eine Struktur sein, die aus mehreren Werten besteht. Und es gibt noch mehr Möglichkeiten, wie z.B. by-reference Parameter. Binggi hat ein Beispiel gepostet. Wenn du an diese Funktion 2 Strings übergibst bzw. Zeiger darauf, dann veränderst du direkt diese Strings (denn du arbeitest ja mit Zeigern, die auf den Speicher dieser Strings zeigen), keine Kopien.
jAIk schrieb:
Klingt für mich sehr gut - warum sollte ich nur "zur Not" Zeiger auf dynamischen Speicher zeigen lassen? Ich sehe (mit meinen geringen Grundkenntnissen) bei der Verwendung von char-Arrays nur längeren Code und keine direkten Vorteile - aber wahrscheinlich übersehe ich dann etwas :).
Wieso längeren Code?
//statisches Array, Deklaration und Destruktion: char arr[128]; //wird automatisch beim Verlassen des Scopes zerstört //dynamisches Array, Deklaration und Destruktion: char *arr=malloc(128); free(arr);
Für mich sieht die dynamische Variante nach mehr Code aus.
Also ich sehe es so, dass man ein statisches Array erzeugen sollte, wenn die Maximalgröße des Arrays bekannt ist und eine gewisse Grenze nicht überschreitet, und wenn man die Arraygröße nicht zur Laufzeit anpassen will/muss. Ein solches Array liegt auf dem Stack, der schneller ist als der Heap. Außerdem muss man nicht selbst aufräumen (free), so dass keine memleak-Gefahr besteht.
-
jAIk schrieb:
- Mit globalen Pointern arbeiten, die auf den Anfang der beiden Strings zeigen
- Beide Strings in einen zusammenfassen. Da das Datum immer gleich lang sein
Weder noch.
Die Frage wäre nur, bekommst du die Strings von deiner DB schon als manipulierbare Strings übergeben (nicht <const>) oder nicht. Du brauchst die Strings nicht irgendwo rückzugeben sondern lediglich zu übergeben, in etwa soconst char *wertausDB1 = DBFunktion1(...); const char *wertausDB2 = DBFunktion2(...); /* o.ä. */ char *meinString1 = malloc(strlen(wertausDB1)+1); strcpy(meinString1,wertausDB1); char *meinString2 = malloc(strlen(wertausDB2)+1); strcpy(meinString2,wertausDB2); if( verarbeiteWerteNachMeinenVorstellungen(meinString1,meinString2) ) puts("OK"); else puts("Fehler"); free(meinString2); free(meinString1); /* alles hier ohne Fehlerbehandlung, gehört aber zu guten Programmen dazu */
wobei der Prototyp wäre
int verarbeiteWerteNachMeinenVorstellungen(char *s1,char *s2);
wobei der Rückgabewert nur ein Erfolgswert der Verarbeitung ist, und nicht die Werte selbst.
Vergessen habe ich noch:
Falls du die Werte aus der DB nur lesend verwendest (ich wüsste auch nicht, warum man Datums/Hash-Werte ändern sollte) kannst du dir den Aufwand natürlich sparen und direkt auf den <const> Werten arbeiten und nicht auf Kopien wie o.g.
-
Klingt für mich sehr gut - warum sollte ich nur "zur Not" Zeiger auf dynamischen Speicher zeigen lassen? Ich sehe (mit meinen geringen Grundkenntnissen) bei der Verwendung von char-Arrays nur längeren Code und keine direkten Vorteile - aber wahrscheinlich übersehe ich dann etwas
Wenn deine Strings immer die definierte Länge aufweisen musst du ja nicht dynamischen Speicher verwenden um mit call-by-reference zu arbeiten. Du kannst deiner Funktion deine char-Arrays einfach mit dem &-Adressoperator übergeben.
Dynamischer Speicher macht für mich nur dann Sinn wenn deine Strings wirklich situationsabhängig in der Länge variieren...
-
likegliss schrieb:
Du kannst deiner Funktion deine char-Arrays einfach mit dem &-Adressoperator übergeben.
Den brauchst du noch nicht mal (array-to-pointer decay).
-
Da hast du natürlich recht, ich verwende es trotzdem nur gerne, weil ich beim erneuten durchsehen gleich erkenne ob ich einer Funktion wirklich einen Pointer übergebe oder ein Array... is ne Angewohnheit
-
Wutz schrieb:
char *meinString1 = malloc(strlen(wertausDB1)+1); strcpy(meinString1,wertausDB1); char *meinString2 = malloc(strlen(wertausDB2)+1); strcpy(meinString2,wertausDB2);
Schon mal was von strdup (http://linux.die.net/man/3/strdup) gehört?
mfg Martin
-
Schon. Und hast du schon mal was von ANSI C gehört?
Scheinbar nicht, denn strdup ist weder C89 noch C99 und somit kein ANSI C und gehört nicht in dieses Forum.
-
Wutz schrieb:
Schon. Und hast du schon mal was von ANSI C gehört?
Scheinbar nicht, denn strdup ist weder C89 noch C99 und somit kein ANSI C und gehört nicht in dieses Forum.Hallo Wutz,
entschuldigung. Du hast recht, ich war davon überzeugt, daß es im Standard ist.
mfg Martin
-
likegliss schrieb:
Da hast du natürlich recht, ich verwende es trotzdem nur gerne, weil ich beim erneuten durchsehen gleich erkenne ob ich einer Funktion wirklich einen Pointer übergebe oder ein Array... is ne Angewohnheit
Hmm. Ich dachte immer, Arrays gibt es nur zur Compilezeit... Wenn das so ist, wie soll man ein Array dann zur Laufzeit übergeben?
-
Ich dachte dabei mehr an Themen wie Fehlersuche und Co als an Laufzeiteigenschaften...
-
Vielen Dank für die zahlreichen wirklich guten und hilfreichen Beiträge. Wenn ich eine entsprechende Lösung programmiert habe werde ich diese definitif hier uppen - dies kann auf Grund zahlreicher Verpflichtungen aber u.U. noch ein paar wochen dauern
Hmm. Ich dachte immer, Arrays gibt es nur zur Compilezeit... Wenn das so ist, wie soll man ein Array dann zur Laufzeit übergeben?
Zum Unterschied zwischen Arrays und Pointern - das könnte Dir u.U. weiterhelfen:
http://www.dclc-faq.de/kap2.htm
-
jAIk schrieb:
Zum Unterschied zwischen Arrays und Pointern - das könnte Dir u.U. weiterhelfen:
http://www.dclc-faq.de/kap2.htmHmm.
http://www.dclc-faq.de/kap2.htm schrieb:
Es ist wichtig zu begreifen, dass ein Bezug wie x[3] zu unterschiedlichem Maschinencode führt, je nach dem, ob x ein Array oder ein Zeiger ist.
_matze schrieb:
Das brauchst du noch nicht mal (array-to-pointer decay).
Wie jetzt?
-
Wenn du mal genau nachliest was array-to-pointer decay bedeutet dann wird dir vll klar, dass die erste aussage die zweite nicht ausschließt oder umgekehrt. Oder auf was genau willst du hinaus?
-
likegliss schrieb:
Oder auf was genau willst du hinaus?
Darauf, dass man x[3] ganz ohne Kenntnis des Typs von x übersetzen kann, wenn man Arrays als Zeiger auf ihren Anfang auswertet.