Czy powinienem użyć char * * argv lub char * argv []?

Właśnie uczę się C i zastanawiałem się, który z nich powinienem użyć w mojej głównej metodzie. Jest jakaś różnica? Który z nich jest bardziej powszechny?

Author: John Kugelman, 2009-04-23

10 answers

Ponieważ dopiero uczysz się C, polecam Ci naprawdę spróbować zrozumieć różnicemiędzy tablicami i wskaźnikami najpierw zamiast wspólne rzeczy.

W obszarze parametrów i tablic istnieje kilka mylących reguł, które powinny być jasne przed rozpoczęciem. Po pierwsze, to, co zadeklarujesz na liście parametrów, jest traktowane jako specjalne. są takie sytuacje, w których rzeczy nie mają sensu jako parametr funkcji w C. Te are

  • Funkcje jako parametry
  • Tablice jako parametry

Tablice jako parametry

Druga może nie jest od razu jasna. Ale staje się jasne, gdy weźmiemy pod uwagę, że rozmiar wymiaru tablicy jest częścią typu w C (a tablica, której rozmiar nie jest podany, ma niekompletny Typ). Tak więc, jeśli chcesz utworzyć funkcję, która pobiera tablicę według wartości (otrzymuje kopię), to może to zrobić tylko dla jednego rozmiaru! Ponadto tablice mogą stań się Duży, A C stara się być jak najszybciej.

W C, z tych powodów, wartości tablicy nie istnieją. Jeśli chcesz uzyskać wartość tablicy, to zamiast tego otrzymujesz wskaźnik do pierwszego elementu tej tablicy. I tutaj już leży rozwiązanie. Zamiast rysować nieprawidłowy parametr tablicy, kompilator C przekształci typ odpowiedniego parametru, który będzie wskaźnikiem. Pamiętaj o tym, to bardzo ważne. Parametr nie będzie będzie tablicą, ale zamiast tego będzie wskaźnikiem do odpowiedniego typu elementu.

Teraz, jeśli spróbujesz przekazać tablicę, to przekazywany jest wskaźnik do pierwszego elementu tablicy.

Excursion: funkcje jako parametry

Na zakończenie, a ponieważ myślę, że to pomoże Ci lepiej zrozumieć sprawę, spójrzmy jaki jest stan rzeczy, gdy próbujesz mieć funkcję jako parametr. Rzeczywiście, po pierwsze, to nie będzie miało sensu. Jak parametr może być funkcją? Chcemy zmienną w tym miejscu, oczywiście! Więc to, co robi kompilator, gdy to się stanie, to ponownie przekształcić funkcję w wskaźnik funkcji . Próba przekazania funkcji przekaże wskaźnik do danej funkcji zamiast tego. Tak więc poniższe są takie same (analogiczne do przykładu tablicy):

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

Zwróć uwagę, że potrzebne są nawiasy wokół *g. W przeciwnym razie określiłby funkcję zwracającą void*, zamiast wskaźnika do funkcji zwracającej void.

Powrót do tablic

Teraz, powiedziałem na początku, że tablice mogą mieć niekompletny Typ - co się dzieje, jeśli nie podasz jeszcze rozmiaru. Ponieważ zorientowaliśmy się już, że parametr tablicy nie istnieje, ale zamiast tego każdy parametr tablicy jest wskaźnikiem, rozmiar tablicy nie ma znaczenia. Oznacza to, że kompilator przetłumaczy wszystkie z następujących rzeczy i wszystkie są tym samym:

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]);

Oczywiście, nie ma sensu umieć umieścić w nim dowolny rozmiar, a to po prostu wyrzucony. Z tego powodu C99 wymyślił nowe znaczenie dla tych liczb i pozwala na pojawianie się innych rzeczy między nawiasami:

// 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);

Ostatnie dwie linie mówią, że nie będzie można zmienić "argv" w funkcji - stała się ona wskaźnikiem const. Tylko kilka kompilatorów C obsługuje te funkcje C99. Ale te cechy sprawiają, że jasne, że "tablica" nie jest w rzeczywistości jeden. To wskaźnik.

Słowo ostrzeżenia

Zauważ, że wszystko co powiedziałem powyżej jest prawdą tylko wtedy, gdy masz tablicę jako parametr funkcji. Jeśli pracujesz z tablicami lokalnymi, tablica nie będzie wskaźnikiem. Będzie ona zachowywała się jako wskaźnik, ponieważ jak wyjaśniono wcześniej tablica zostanie przekonwertowana na wskaźnik podczas odczytu jej wartości. Ale nie należy go mylić ze wskaźnikami.

Jeden klasyczny przykład jest następujący:

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;
 163
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-15 06:52:24

Możesz użyć albo. Są całkowicie równoważne. Zobacz komentarze litb i jego odpowiedź .

To naprawdę zależy jak chcesz go użyć (i możesz użyć albo w każdym przypadku):

// 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;
}

Co do tego, co jest bardziej powszechne - to nie ma znaczenia. Każdy doświadczony programista C czytający Twój kod zobaczy oba jako wymienne (w odpowiednich warunkach). Tak jak doświadczony angielski mówca czyta" oni "i" oni są " równie łatwo.

Więcej ważne jest, abyś nauczył się je czytać i rozpoznawać, jak są podobne. Będziesz czytał więcej kodu niż piszesz, i musisz być równie komfortowy z obu.

 12
Author: rampion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-09 18:09:56

To nie robi różnicy, ale używam char *argv[], ponieważ pokazuje, że jest to tablica o stałym rozmiarze ciągów o zmiennej długości (które zwykle są char *).

 9
Author: Zifre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-23 03:07:05

Możesz użyć jednej z dwóch form, ponieważ w C tablice i wskaźniki są wymienne w listach parametrów funkcji. Zobacz http://en.wikipedia.org/wiki/C_ (programming_language)#Array-pointer_interchangeability .

 9
Author: lothar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-23 08:10:19

To naprawdę nie robi różnicy, ale ta druga jest bardziej czytelna. To, co otrzymujesz, to tablica wskaźników znakowych, tak jak mówi druga wersja. Można go jednak bezwarunkowo przekonwertować na Podwójny wskaźnik znakowy, tak jak w pierwszej wersji.

 4
Author: jalf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-23 01:05:24

Powinieneś zadeklarować ją jako char *argv[], ze względu na wiele równoważnych sposobów deklarowania, które są najbliżej intuicyjnego znaczenia: tablicy łańcuchów.

 2
Author: Andras,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-08 07:41:44

Char ** → wskaźnik do wskaźnika znakowego, A char *argv [] oznacza tablicę wskaźników znakowych. Ponieważ możemy użyć wskaźnika zamiast tablicy, oba mogą być użyte.

 1
Author: Alphaneo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-23 01:10:22

Nie widzę szczególnych zalet używania jednego podejścia zamiast drugiego -- używaj konwencji, która jest najbardziej zgodna z resztą twojego kodu.

 0
Author: Christoffer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-23 08:25:10

Jeśli potrzebujesz zmiennej lub dynamicznej liczby łańcuchów, char * * może być łatwiejszy do pracy. Jeśli jednak liczba ciągów jest stała, preferowany jest char * var [].

 -2
Author: samoz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-23 01:21:38

Wiem, że to nieaktualne, ale jeśli dopiero uczysz się języka programowania C i nie robisz z nim nic większego, nie używaj opcji wiersza poleceń.

Jeśli nie używasz argumentów linii poleceń, nie używaj ich. Po prostu zadeklaruj główną funkcję jako int main() If you

  • chcesz, aby użytkownik Twojego programu mógł przeciągnąć plik na twój program, abyś mógł zmienić wynik programu za pomocą niego lub
  • chcesz obsługiwać opcje wiersza poleceń(-help, /?, lub każda inna rzecz, która pojawia się po program name w terminalu lub wierszu polecenia)

Użyj tego, co ma dla Ciebie większy sens. W przeciwnym razie wystarczy użyć int main() W końcu, jeśli chcesz dodać opcje wiersza poleceń, możesz je łatwo edytować później.

 -2
Author: Jesse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-02 20:45:33