Ich lerne gerade C und habe mich gefragt, welche davon ich in meiner Hauptmethode verwenden sollte. Gibt es einen Unterschied? Welche ist häufiger?
Soll ich char** argv oder char* argv verwenden[]?
Kredns
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
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 solltesizeof[arr] / sizeof[*arr]
.– raymai97
23. April 2017 um 3:33 Uhr
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 *
).
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.
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.
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.
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 mitchar *argv[]
als Parameterdeklaration (und nur als Parameterdeklaration). 2. Arrays sind keine Zeiger.– Keith Thompson
22. August 2012 um 2:05 Uhr