übergeben Sie Zeichenfolgen, die durch Verweis in C
Ich habe Probleme, herauszufinden, wie übergeben Sie Zeichenfolgen zurück, die durch die Parameter einer Funktion. Ich bin neu in die Programmierung, also ich kann mir vorstellen das dies wahrscheinlich eine Anfänger-Frage. Jede Hilfe Sie ihm geben könnte wäre sehr dankbar. Dieser code seg-Fehler, und ich bin mir nicht sicher, warum, aber ich bin Angabe meine code zu zeigen, was ich habe, so weit.
Ich habe ein community-wiki, so fühlen sich frei zu Bearbeiten.
P. S. Dies ist nicht Hausaufgaben.
Dies ist die ursprüngliche version
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void
fn(char *baz, char *foo, char *bar)
{
char *pch;
/* this is the part I'm having trouble with */
pch = strtok (baz, ":");
foo = malloc(strlen(pch));
strcpy(foo, pch);
pch = strtok (NULL, ":");
bar = malloc(strlen(pch));
strcpy(bar, pch);
return;
}
int
main(void)
{
char *mybaz, *myfoo, *mybar;
mybaz = "hello:world";
fn(mybaz, myfoo, mybar);
fprintf(stderr, "%s %s", myfoo, mybar);
}
UPDATE Hier ist eine aktualisierte version mit einigen der Vorschläge umgesetzt:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLINE 1024
void
fn(char *baz, char **foo, char **bar)
{
char line[MAXLINE];
char *pch;
strcpy(line, baz);
pch = strtok (line, ":");
*foo = (char *)malloc(strlen(pch)+1);
(*foo)[strlen(pch)] = '\n';
strcpy(*foo, pch);
pch = strtok (NULL, ":");
*bar = (char *)malloc(strlen(pch)+1);
(*bar)[strlen(pch)] = '\n';
strcpy(*bar, pch);
return;
}
int
main(void)
{
char *mybaz, *myfoo, *mybar;
mybaz = "hello:world";
fn(mybaz, &myfoo, &mybar);
fprintf(stderr, "%s %s", myfoo, mybar);
free(myfoo);
free(mybar);
}
- für Ihre strtok segmentation Fault Blick auf meine Anregung unten
Du musst angemeldet sein, um einen Kommentar abzugeben.
Erste Sache, jene mallocs sollte für
strlen(whatever)+1
bytes. C-strings haben ein 0-Zeichen an das Ende, genannt das NUL-terminator, und es ist nicht enthalten in der Länge gemessen von strlen.Nächste Sache, strtok ändert die Zeichenfolge, die Sie suchen. Übergeben Sie einen Zeiger auf eine Zeichenkette, die darf man nicht ändern (die Sie nicht ändern können literal-Zeichenfolgen). Das könnte die Ursache für den segmentation Fault. Anstatt also mit einem Zeiger auf die nicht-modifizierbaren string-literal, Sie konnte kopieren, um Ihre eigene, veränderbare Puffer, wie diese:
Was dieser tut, ist legen Sie eine Größe 12 char-array auf dem stack, und kopieren Sie die bytes der string-literal in das array. Es funktioniert, weil der compiler weiß zur compile-Zeit, wie lange der string ist, und kann der Raum entsprechend. Dies spart malloc für die jeweilige Kopie.
Das problem, das Sie haben, mit Referenzen ist, dass Sie derzeit die übergabe der Wert von mybaz, myfoo, und mybar in Ihrer Funktion. Sie können nicht ändern der Anrufer-Variablen, es sei denn, Sie übergeben ein Zeiger zu myfoo und mybar. Da myfoo ist ein char* ein Zeiger auf es ist ein char**:
Ändern foo in die Funktion in Ihrem code hat absolut keine Auswirkung auf die
myfoo
.myfoo
ist uninitialised, also wenn keiner von den ersten beiden Dingen ist, die es verursacht, der segfault ist am wahrscheinlichsten auftreten, wenn Sie kommen, um zu drucken, wobei das uninitialised Zeiger.Sobald du Sie hast, im Grunde arbeiten, möchten Sie vielleicht, um etwas Fehler-handling.
strtok
NULL zurückgeben kann, wenn es nicht die separator-es sucht, und Sie kann nicht anrufenstrlen
mit NULL.malloc
NULL zurückgeben kann, wenn es nicht genug Speicher, und Sie können nicht nennenstrcpy
mit NULL entweder.Eins, was jeder Blick ist, dass Sie den Aufruf strtok auf ein array gespeichert const Speicher. strtok schreibt in das array, das Sie es weiterleiten, so stellen Sie sicher, dass Sie Kopie, um ein temporäres array vor dem Aufruf von strtok oder nur reservieren, das original mag:
In C, Sie in der Regel übergeben durch Referenz übergeben 1), einen Zeiger für das erste element des array, und 2) die Länge des Arrays.
Die Länge des Arrays kann entfallen manchmal, wenn Sie sicher sind, über Ihre Puffer-Größe, und man würde wissen, die Länge der Zeichenkette suchen für eine null-terminierte Zeichen (Ein Zeichen mit dem Wert 0 oder
'\0'
.Scheint es aus deinem code-Beispiel ist zwar, dass Sie versuchen, den Wert dessen, was ein Zeiger zeigt. So möchten Sie wahrscheinlich ein
char**
Zeiger. Und Sie würde übergeben Sie die Adresse Ihreschar*
variable(N), die Sie festlegen möchten.Ooh ja, kleines problem gibt es.
Regel, wenn Sie gehen, um die Manipulation von strings in einer Funktion, die Speicher für strings besser werden außerhalb der Funktion. Der einfache Weg um dies zu erreichen, ist zu deklarieren arrays außerhalb der Funktion (z.B. in
main()
) und das übergeben des arrays (was automatisch zu Zeiger auf Ihre Anfänge), um die Funktion. Dies funktioniert gut, so lange, wie Sie Ihre Ergebnis-strings nicht überlauf des zugewiesenen Platzes in die Felder.Ihnen gegangen sind, die vielseitiger, aber etwas schwieriger route: verwenden Sie
malloc()
um Platz zu schaffen für Ihre Ergebnisse (gut so weit!) und dann versuchen, weisen die malloc hatte Platz, um die Hinweise, die Sie übergeben. Dass, ach, wird nicht funktionieren.Den Zeiger kommen, ist ein Wert; Sie kann es nicht ändern. Die Lösung ist, übergeben Sie einen Zeiger an einen Zeiger und verwenden Sie es innerhalb der Funktion zu ändern, welche der Zeiger verweist.
Wenn du den hast, ist das Super. Wenn nicht, Fragen Sie bitte für weitere Klärung.
Sie wollen, sind zu pass zurück 2 Zeiger. So müssen Sie rufen Sie es mit einem paar von Zeigern auf Zeiger. So etwas wie dieses:
malloc()
! BOO ICH SAGEN!den code wahrscheinlich segfaults, weil Sie zuweisen von Speicherplatz für den string aber zu vergessen, dass ein string hat eine extra-byte auf das Ende der null-terminator.
Auch Sie sind nur die übergabe eines Zeigers in. Da ein Zeiger ist eine 32-bit-Wert (auf einem 32-bit-Maschine) Sie sind einfach übergeben Sie den Wert der unitialised Zeiger in den "fn". In der gleichen Weise würden Sie nicht expact eine Ganzzahl, die einer Funktion übergeben werden zurückgegeben an die aufrufende Funktion (ohne Sie explizit Rückgabe) Sie können nicht erwarten, dass der Mauszeiger, das gleiche zu tun. So ist die neue pointer-Werte sind nie wieder zurück in die main-Funktion. Gewöhnlich tun Sie dies, indem ein Zeiger auf einen Zeiger in C.
Vergessen Sie auch nicht frei von dynamisch zugewiesenen Speicher!!
Anderen Antworten beschreiben, wie zu beheben Ihre Antwort zu arbeiten, aber einen einfachen Weg, das zu erreichen, was Sie meine zu tun ist, strdup(), die reserviert neuen Speicher in passender Größe und kopiert die korrekten Zeichen in.
Müssen noch fix das Geschäft mit char* vs char**, obwohl. Es gibt einfach kein Weg vorbei.
Das wesentliche problem ist, dass, obwohl Speicher ist immer reserviert (mit
malloc()
) für die Ergebnisse, die Sie versuchen, um returnmyfoo
undmybar
die Zeiger auf diese Zuweisungen nicht tatsächlich zurückgegebenmain()
. Als ein Ergebnis, das später nennen zuprintf()
ist durchaus wahrscheinlich, um einen Speicherauszug.Die Lösung ist zu erklären, dass die Argumente als ponter, um Zeiger auf
char
ab und übergeben die Adressen vonmyfoo
undmybar
zufn
. So etwas (ungetestet) sollte den trick tun:Vergessen Sie nicht, die frei jeden zugewiesenen string zu einem späteren Zeitpunkt, oder erstellen Sie Speicher-Lecks.
Sowohl die malloc() und strcpy() in einen Aufruf, es wäre besser, verwenden
strdup()
, wie es sich auch an, um zu reservieren Zimmer für das abschließende NUL, die Sie Links aus deinem code.*foo = strdup(pch)
ist viel klarer und leichter zu pflegen, dass die alternative. Dastrdup()
ist POSIX und nicht ANSI-C, möglicherweise müssen Sie es selbst implementieren, aber der Aufwand ist auch getilgt durch die daraus resultierende Klarheit für diese Art der Nutzung.Andere traditionelle Möglichkeit zum zurückgeben einer Zeichenfolge aus einer C-Funktion ist für den Anrufer zuweisen, die Lagerung und geben Sie die Adresse der Funktion. Dies ist die Technik, die von
sprintf()
zum Beispiel. Es leidet unter dem problem, dass es keine Möglichkeit, einen solchen Anruf Website völlig sicher vor buffer-overrun-Fehlern verursacht, die durch die aufgerufene Funktion die übernahme von mehr Raum zugewiesen wurde, als tatsächlich verfügbar ist. Die traditionellen Reparatur für dieses problem ist zu verlangen, dass ein buffer-length-argument übergeben werden, und prüfen Sie sorgfältig, ob sowohl die ist-Allokation und die Länge behauptete auf der call-Seite in einem code-review.Edit:
Den tatsächlichen segfault, die Sie bekommen ist wahrscheinlich im inneren
strtok()
, nichtprintf()
weil dein Beispiel, wie geschrieben versucht, übergeben Sie eine Zeichenfolge Konstantestrtok()
muss in der Lage sein, die Zeichenfolge zu ändern. Das ist offiziell nicht definiertes Verhalten.Den fix für dieses Problem ist, um sicherzustellen, dass
bybaz
ist deklariert als ein array initialisiert, und nicht als Zeiger aufchar
. Das array initialisiert wird sich im beschreibbaren Speicher, während die string-Konstante dürfte sich im nur-lese-Speicher. In vielen Fällen, string-Konstanten gespeichert sind, in dem gleichen Teil des Speichers verwendet, um den ausführbaren code selbst, und moderne Systeme, die alle versuchen, zu machen es schwierig für ein Programm zu ändern, seinen eigenen code.In der embedded-Systeme, ich arbeite für ein Leben, der code ist wahrscheinlich zu sein, gespeichert in einem ROM einer Art, und nicht physisch geändert.