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

War es hilfreich?

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top