Ein Array von Zeichenketten als Parameter einer Funktion in C
-
20-08-2019 - |
Frage
Ich mag eine einfache Funktion, die eine Zeichenfolge empfängt und gibt einen Array von Strings nach einigem Parsing. Also, das ist meine Funktion Unterschrift:
int parse(const char *foo, char **sep_foo, int *sep_foo_qty) {
int i;
char *token;
...
strcpy(sep_foo[i], token); /* sf here */
...
}
Dann rufe ich es wie folgt aus:
char sep_foo[MAX_QTY][MAX_STRING_LENGTH];
char foo[MAX_STRING_LENGTH];
int sep_foo_qty, error;
...
error = parse(foo, sep_foo, &sep_foo_qyt);
...
So kann ich eine Warnung während der Kompilierung erhalten:
warning: passing argument 2 of 'parse' from incompatible pointer type
Und dann ein Zugriffsfehler während der Ausführung in der Zeile markiert mit / * sf hier * /
Was in meinem C-Code ist falsch?
Vielen Dank im Voraus
Lösung
Die Warnung ist hier genau richtig. Ihre Funktion will ein Array von Zeigern. Sie sind es ein Array von Arrays zu geben.
Erwartet:
sep_foo: +------+ +-----+ |char**|--> 0: |char*|-->"string1" +------+ +-----+ 1: |char*|-->"string2" +-----+ *sep_foo_qty-1: |... | +-----+
Was Sie zur Verfügung gestellt:
sep_foo: +--------------------------------+ 0: | char[MAX_STRING_LENGTH] | +--------------------------------+ 1: | char[MAX_STRING_LENGTH] | +--------------------------------+ MAX_QTY-1: | ... | +--------------------------------+
Ein Array mit Elementen des Typs X
can „decay“ in einen Zeiger zu X
oder X*
. Aber der Wert des X
nicht in dieser Umwandlung zu ändern erlaubt. Nur ein Zerfall Betrieb erlaubt. Sie würden es brauchen zweimal passieren. In Ihrem Fall ist X
Array-of-MAX_STRING_LENGTH
-Zeichen. Die Funktion will X
Zeiger auf char zu sein. Da diejenigen, die nicht die gleichen sind, warnt Sie der Compiler. Ich bin ein wenig überrascht, es war nur eine Warnung, da nichts Gutes aus kommen kann, was der Compiler erlaubt passieren.
In Ihrer Funktion, können Sie diesen Code schreiben:
char* y = NULL;
*sep_foo = y;
Das ist, Rechtskode seit sep_foo
ein char**
ist, so *sep_foo
ist ein char*
, und so ist y
; Sie können sie zuordnen. Aber mit dem, was Sie zu tun versucht, *sep_foo
nicht wirklich sein ein char*
; es würde zu einem Array von char zeigen. Ihr Code in der Tat würde versuchen, dies zu tun:
char destination[MAX_STRING_LENGTH];
char* y = NULL;
destination = y;
Sie können einen Zeiger in ein Array zuweisen und damit der Compiler warnt davor, dass der Anruf nicht gut.
Es gibt zwei Möglichkeiten, dies zu lösen:
-
Ändern Sie die Art und Weise Sie erklären und
sep_foo
auf der rufenden Seite zuweisen, so dass es dem entspricht, was die Funktion zu erhalten erwartet:char** sep_foo = calloc(MAX_QTY, sizeof(char*)); for (int i = 0; i < MAX_QTY; ++i) sep_foo[i] = malloc(MAX_STRING_LENGTH);
oder äquivalent
char* sep_foo[MAX_QTY]; for (int i = 0; i < MAX_QTY; ++i) sep_foo[i] = malloc(MAX_STRING_LENGTH);
-
Ändern Sie den Prototyp der Funktion zu übernehmen, was Sie geben es wirklich:
int parse(const char *foo, char sep_foo[MAX_QTY][MAX_STRING_LENGTH], int *sep_foo_qty);
Andere Tipps
Parameter 2 sollte
char sep_foo[][MAX_STRING_LENGTH]
Um zu klären, Sie übergeben einen Zeiger zu analysieren () und als Zeiger auf einen Zeiger zu behandeln. Ein mehrdimensionales Array in C ist kein Array von Zeigern. Es ist ein einziger Speicherblock, der dem von den Array-Variablen gerichtet ist. Sie können nicht dereferenzieren es zweimal.
sep_foo
wird als Array von Arrays definiert. Mit anderen Worten, wenn Sie sep_foo
verwenden, verweist es auf den Beginn des sequentiellen Speichers. Hier ist ein Modell:
(assume MAX_STRING_LENGTH = 16, MAX_QTY = 2)
sep_foo = &&0000
sep_foo[0] = &0000
sep_foo[0][0] = *&0000 = 12
sep_foo[0][8] = *&0008 = 74
sep_foo[1] = &0010
sep_foo[1][0] = *&0010 = 12
0000 12 34 56 78 9A BC DE F0 74 10 25 89 63 AC DB FE
0010 12 34 56 78 9A BC DE F0 74 10 25 89 63 AC DB FE
Allerdings erwartet Ihre Funktion ein Array von Zeigern (tatsächlich einen Zeiger auf einen Zeiger). Dies ist ein Modell als solches:
sep_foo_arg = &&0000
sep_foo_arg[0] = *&&0000 = &0010
sep_foo_arg[0][0] = *&*&0000 = 12
sep_foo_arg[0][8] = *(&*&0000 + 8) = 74
sep_foo_arg[1] = *&&0002 = &0020
sep_foo_arg[1][0] = *&*&0000 = 12
0000 0010 0020 xxxx xxxx xxxx xxxx xxxx xxxx
0010 12 34 56 78 9A BC DE F0 74 10 25 89 63 AC DB FE
0020 12 34 56 78 9A BC DE F0 74 10 25 89 63 AC DB FE
Ja ... Syntax kann für meine Erklärungen ein wenig verwirrend ...
Wie auch immer, können Sie dieses Problem lösen, indem Sie Ihre Funktion zu sagen, wie der Zeiger zu behandeln wies auf. Insbesondere würden Sie es als ein Array (eine Folge von Speicher) zu behandeln:
int parse(const char *foo, char (*sep_foo)[MAX_STRING_LENGTH], int *sep_foo_qty);
Wenn das Ihr genauer Code ist, dann vermute ich die segfault ist wegen der Tatsache, dass Sie Speicher auf die char* token
in Ihrer Parse-Funktion nicht zugeordnet haben, und die Verwendung dieser dann in Ihrem strcpy.