Soll ich char** argv oder char* argv verwenden[]?

Lesezeit: 7 Minuten

Benutzeravatar von Kredns
Kredns

Ich lerne gerade C und habe mich gefragt, welche davon ich in meiner Hauptmethode verwenden sollte. Gibt es einen Unterschied? Welche ist häufiger?

  • Ich bevorzuge ‘char **argv’ und sehe es daher öfter, aber beides ist richtig und ich würde eine Deklaration nicht ändern, nur weil sie ‘char *argv’ geschrieben wurde[]’.

    – Jonathan Leffler

    23. April 2009 um 2:36 Uhr

  • +1, weil es wichtig ist, die tieferen Probleme von Array vs. Pointer gut zu verstehen.

    – RBerteig

    23. April 2009 um 23:13 Uhr

  • Wirklich, wirklich gute Frage. Vielen Dank.

    – Frank v

    28. Juni 2009 um 20:07 Uhr

  • Lesen Sie Abschnitt 6 der comp.lang.c FAQ; es ist die beste Erklärung für die Beziehung zwischen C-Arrays und Zeigern, die ich gesehen habe. Zwei relevante Punkte: 1. char **argv ist genau gleichbedeutend mit char *argv[] als Parameterdeklaration (und nur als Parameterdeklaration). 2. Arrays sind keine Zeiger.

    – Keith Thompson

    22. August 2012 um 2:05 Uhr

Johannes Schaub - Benutzerbild der litb
Johannes Schaub – litb

Da Sie gerade C lernen, empfehle ich Ihnen, wirklich zu versuchen, C zu verstehen Unterschiede zwischen Arrays und Zeigern zuerst statt der gemeinsames Dinge.

Im Bereich Parameter und Arrays gibt es ein paar verwirrende Regeln, die klar sein sollten, bevor Sie fortfahren. Zuerst, Was Sie in einer Parameterliste deklarieren, wird speziell behandelt. Es gibt solche Situationen, in denen Dinge als Funktionsparameter in C keinen Sinn machen. Dies sind

  • Funktioniert als Parameter
  • Arrays als Parameter

Arrays als Parameter

Das zweite vielleicht ist nicht sofort klar. Aber es wird klar, wenn man bedenkt, dass die Größe einer Array-Dimension Teil des Typs in C ist (und ein Array, dessen Dimensionsgröße nicht angegeben ist, einen unvollständigen Typ hat). Wenn Sie also eine Funktion erstellen würden, die ein Array als Wert nimmt (eine Kopie erhält), dann könnte sie dies nur für eine Größe tun! Außerdem können Arrays groß werden und C versucht, so schnell wie möglich zu sein.

In C ist aus diesen Gründen Array-Werte sind nicht vorhanden. Wenn Sie den Wert eines Arrays erhalten möchten, erhalten Sie stattdessen einen Zeiger auf das erste Element dieses Arrays. Und hierin liegt eigentlich schon die Lösung. Anstatt einen Array-Parameter im Voraus ungültig zu zeichnen, wird ein C-Compiler dies tun verwandeln der Typ des jeweiligen Parameters ein Zeiger sein. Denken Sie daran, es ist sehr wichtig. Der Parameter ist kein Array, sondern ein Zeiger auf den jeweiligen Elementtyp.

Wenn Sie nun versuchen, ein Array zu übergeben, wird stattdessen ein Zeiger auf das erste Element des Arrays übergeben.

Exkursion: Funktioniert als Parameter

Zur Vervollständigung, und weil ich denke, dass dies Ihnen helfen wird, die Sache besser zu verstehen, schauen wir uns an, wie der Stand der Dinge ist, wenn Sie versuchen, eine Funktion als Parameter zu haben. In der Tat wird es zunächst keinen Sinn machen. Wie kann ein Parameter eine Funktion sein? Huh, wir wollen natürlich eine Variable an dieser Stelle! Was der Compiler also tut, wenn das passiert, ist wieder to verwandeln die Funktion in a Funktionszeiger. Beim Versuch, eine Funktion zu übergeben, wird stattdessen ein Zeiger auf die entsprechende Funktion übergeben. Das Folgende ist also dasselbe (analog zum Array-Beispiel):

void f(void g(void));
void f(void (*g)(void));

Beachten Sie, dass Klammern um *g wird gebraucht. Andernfalls würde es eine Funktion angeben, die zurückkehrt void*anstelle eines Zeigers auf eine zurückkehrende Funktion void.

Zurück zu Arrays

Nun, ich sagte am Anfang, dass Arrays einen unvollständigen Typ haben können – was passiert, wenn Sie noch keine Größe angeben. Da wir bereits festgestellt haben, dass ein Array-Parameter nicht existiert, sondern jeder Array-Parameter ein Zeiger ist, spielt die Größe des Arrays keine Rolle. Das heißt, der Compiler übersetzt alles Folgende, und alle sind gleich:

int main(int c, char **argv);
int main(int c, char *argv[]);
int main(int c, char *argv[1]);
int main(int c, char *argv[42]);

Natürlich macht es nicht viel Sinn, jede Größe hineinstecken zu können, und es wird einfach weggeworfen. Aus diesem Grund hat C99 eine neue Bedeutung für diese Zahlen entwickelt und lässt andere Dinge zwischen den Klammern erscheinen:

// says: argv is a non-null pointer pointing to at least 5 char*'s
// allows CPU to pre-load some memory. 
int main(int c, char *argv[static 5]);

// says: argv is a constant pointer pointing to a char*
int main(int c, char *argv[const]);

// says the same as the previous one
int main(int c, char ** const argv);

Die letzten beiden Zeilen besagen, dass Sie “argv” innerhalb der Funktion nicht ändern können – es ist zu einem konstanten Zeiger geworden. Allerdings unterstützen nur wenige C-Compiler diese C99-Features. Aber diese Merkmale machen deutlich, dass das “Array” eigentlich keins ist. Es ist ein Zeiger.

Ein Wort der Warnung

Beachten Sie, dass alles, was ich oben gesagt habe, nur wahr ist, wenn Sie ein Array als a haben Parameter einer Funktion. Wenn Sie mit lokalen Arrays arbeiten, ist ein Array kein Zeiger. Es wird sich verhalten als Zeiger, da, wie bereits erklärt, ein Array in einen Zeiger konvertiert wird, wenn sein Wert gelesen wird. Aber es sollte nicht mit Zeigern verwechselt werden.

Ein klassisches Beispiel ist das folgende:

char c[10]; 
char **c = &c; // does not work.

typedef char array[10];
array *pc = &c; // *does* work.

// same without typedef. Parens needed, because [...] has 
// higher precedence than '*'. Analogous to the function example above.
char (*array)[10] = &c;

  • Hatte keine Ahnung, dass es diesen hier gibt: *argv[static 1]

    – Superlukas

    1. März 2015 um 3:33 Uhr

Benutzeravatar von rampion
Rapunzel

Du könntest beides verwenden. Sie sind völlig gleichwertig. Siehe litbs Kommentare und seine Antwort.

Es hängt wirklich davon ab, wie Sie es verwenden möchten (und Sie können in jedem Fall beides verwenden):

// echo-with-pointer-arithmetic.c
#include <stdio.h>
int main(int argc, char **argv)
{
  while (--argc > 0)
  {
    printf("%s ", *++argv);
  }
  printf("\n");
  return 0;
}

// echo-without-pointer-arithmetic.c
#include <stdio.h>
int main(int argc, char *argv[])
{
  int i;
  for (i=1; i<argc; i++)
  {
    printf("%s ", argv[i]);
  }
  printf("\n");
  return 0;
}

Was häufiger vorkommt – es spielt keine Rolle. Jeder erfahrene C-Programmierer, der Ihren Code liest, wird beide als austauschbar ansehen (unter den richtigen Bedingungen). So wie ein erfahrener Englischsprecher “they’re” und “they are” gleichermaßen leicht lesen kann.

Wichtiger ist, dass Sie lernen, sie zu lesen und zu erkennen, wie ähnlich sie sind. Sie werden mehr Code lesen als schreiben, und Sie müssen mit beiden gleichermaßen vertraut sein.

  • Zeichen* argv[] ist zu 100 % äquivalent zu char** argv, wenn es als Parametertyp einer Funktion verwendet wird. kein “const” beteiligt, auch nicht implizit. Beide sind Zeiger auf Zeiger auf Zeichen. Anders verhält es sich mit dem, was Sie deklarieren. Aber der Compiler passt den Typ des Parameters so an, dass er ein Zeiger auf einen Zeiger ist, obwohl Sie gesagt haben, dass es ein Array ist. Daher sind die folgenden alle gleich: void f(char *p[100]); void f(char *p[]); void f(char **p);

    – Johannes Schaub – litb

    23. April 2009 um 2:12 Uhr

  • In C89 (das die meisten Leute verwenden) gibt es auch keine Möglichkeit, die Tatsache zu nutzen, dass Sie erklärt es als Array (also semantisch spielt es keine Rolle, ob Sie dort einen Zeiger oder ein Array deklariert haben – beide werden als Zeiger genommen). Ab C99 können Sie davon profitieren, es als Array zu deklarieren. Das Folgende sagt: “p ist immer nicht null und zeigt auf eine Region mit mindestens 100 Byte”: void f(char p[static 100]); Beachten Sie, dass p typisiert ist still ein Zeiger.

    – Johannes Schaub – litb

    23. April 2009 um 2:14 Uhr

  • (insbesondere &p gibt dir ein char**, aber kein char()[100] was der Fall wäre, wenn p *würde ein Array sein). Ich bin überrascht, dass noch niemand in einer Antwort erwähnt wurde. Ich halte es für sehr wichtig zu verstehen.

    – Johannes Schaub – litb

    23. April 2009 um 2:19 Uhr

  • Ich persönlich bevorzuge char** weil es mich daran erinnert, dass es nicht wie ein echtes Array behandelt werden sollte sizeof[arr] / sizeof[*arr].

    – raymai97

    23. April 2017 um 3:33 Uhr

Benutzeravatar von Zifre
Zifre

Es macht keinen Unterschied, aber ich benutze char *argv[] weil es zeigt, dass es sich um ein Array mit fester Größe aus Zeichenfolgen variabler Länge handelt (was normalerweise char *).

lothars Benutzeravatar
Lothar

Sie können eine der beiden Formen verwenden, da in C Arrays und Zeiger in Funktionsparameterlisten austauschbar sind. Sehen http://en.wikipedia.org/wiki/C_(programming_language)#Array-pointer_interchangeability.

Es macht keinen wirklichen Unterschied, aber letzteres ist besser lesbar. Was Sie erhalten, ist ein Array von Zeichenzeigern, wie die zweite Version sagt. Es kann jedoch wie in der ersten Version implizit in einen doppelten Zeichenzeiger umgewandelt werden.

Benutzeravatar von Andras
Andreas

Sie sollten es als deklarieren char *argv[]wegen all der vielen äquivalenten Deklarationsmöglichkeiten, die ihrer intuitiven Bedeutung am nächsten kommt: ein Array von Strings.

Benutzeravatar von Alphaneo
Alphaneo

char ** → Zeiger auf Zeichenzeiger und char *argv [] bedeutet Array von Zeichenzeigern. Da wir anstelle eines Arrays einen Zeiger verwenden können, können beide verwendet werden.

1423150cookie-checkSoll ich char** argv oder char* argv verwenden[]?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy