C++ - char * * argv vs. char * argv[]

Jaka jest różnica między char** argv a char* argv[]? w int main(int argc, char** argv) i int main(int argc, char* argv[])?

Czy są takie same? Zwłaszcza, że pierwsza część nie ma [].
Author: Nakilon, 2011-03-04

7 answers

Są całkowicie równoważne. char *argv[] musi być odczytywane jako tablica wskaźników do char, A argument tablicy jest zdegradowany do wskaźnika, więc wskaźnik do wskaźnika do char, lub char **.

To samo w C .

 47
Author: Fred Foo,
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
2017-05-23 10:31:23

Są dokładnie takie same.

Złota reguła tablic do zapamiętania to:

"nazwa tablicy jest wskaźnikiem do pierwszego elementu tablicy."

Więc jeśli zadeklarujesz co następuje:

char text[] = "A string of characters.";

Wtedy zmienna "text" jest wskaźnikiem do pierwszego znaku w tablicy znaków, które właśnie zadeklarowałeś. Innymi słowy, "tekst" jest typu char *. Gdy uzyskujesz dostęp do elementu tablicy za pomocą [index ], czym jesteś w rzeczywistości robi to dodanie przesunięcia indeksu do wskaźnika do pierwszego elementu tablicy, a następnie dereferowanie tego nowego wskaźnika. Następujące dwie linie zainicjalizują obie zmienne NA "t":

char thirdChar = text[3];
char thirdChar2 = *(text+3);

Używanie nawiasów kwadratowych jest wygodą zapewnianą przez język, który sprawia, że kod jest znacznie bardziej czytelny. Ale sposób, w jaki to działa, jest bardzo ważny, gdy zaczynasz myśleć o bardziej złożonych rzeczach, takich jak wskaźniki do wskaźników. char** argv jest tym samym co char* argv[] ponieważ w drugim przypadku "nazwa tablicy jest wskaźnikiem do pierwszego elementu tablicy".

Z tego powinieneś również być w stanie zobaczyć, dlaczego indeksy tablic zaczynają się od 0. Wskaźnik do pierwszego elementu jest nazwą zmiennej tablicy (złota reguła ponownie) plus offset of... nic!

Miałem dyskusje z moim przyjacielem, który jest lepszy do wykorzystania tutaj. Dzięki notacji char* argv[] czytelnikowi może być jaśniej, że jest to w rzeczywistości "tablica pointers to characters "w przeciwieństwie do notacji char** argv, która może być odczytywana jako "pointer to a pointer to a character". Moim zdaniem ta ostatnia notacja nie przekazuje tak wielu informacji czytelnikowi.

Dobrze jest wiedzieć, że są dokładnie takie same, ale dla czytelności myślę, że jeśli intencją jest tablica wskaźników, to notacja char* argv[] przekazuje to znacznie wyraźniej.

 18
Author: James Bedford,
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-07-26 20:12:06

Dla wszystkich praktycznych celów, są takie same. Jest to spowodowane obsługą przez C/C++tablic przekazywanych jako argumenty, gdzie tablica rozpada się na wskaźnik.

 3
Author: Erik,
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
2011-03-04 09:47:01

W pierwszej części Pytania:

  • char** argv: wskaźnik do wskaźnika do znaku
  • char * argv []: wskaźnik do tablicy

Więc pytanie brzmi, czy wskaźnik do Typu C i tablica C [] to te same rzeczy. Nie są one w ogóle, ale są równoważne, gdy są używane w podpisach.

Innymi słowy, nie ma różnicy w twoim przykładzie, ale ważne jest, aby pamiętać o różnicy między wskaźnikiem a tablicą inaczej.

 3
Author: David Cournapeau,
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
2016-08-02 18:24:53

Forma nawiasu jest przydatna tylko w deklaracjach typu:

char *a[] = {"foo", "bar", "baz"};
printf("%d\n", sizeof a / sizeof *a);
// prints 3

Ponieważ w czasie kompilacji zna rozmiar tablicy. Kiedy przekazujesz formę nawiasu jako parametr do funkcji (głównej lub innej), kompilator nie ma pojęcia jaki rozmiar tablicy będzie w czasie wykonywania, więc jest dokładnie taki sam jak char * * a. preferuję char * * argv, ponieważ jest jaśniejsze, że sizeof nie będzie działał tak, jak na formularzu deklaracji.

 2
Author: Jake,
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
2013-10-29 15:59:41

Istnieje różnica pomiędzy TYPE * NAME i TYPE NAME[] zarówno w C jak i C++. W C++ oba typy nie są interchagnable. Na przykład następująca funkcja jest nielegalna (otrzymasz błąd) w C++, ale legalna w C (otrzymasz ostrzeżenie):

int some (int *a[3]) // a is array of dimension 3 of pointers to int
{
    return sizeof a;
}

int main ()
{
    int x[3][3];
    std::cout << some(x)<< std::endl;
    return 0;
}

Aby uczynić to legalnym wystarczy zmienić sygnaturę na int some (int (*a)[3]) (Wskaźnik do tablicy 3 ints) lub int some (int a[][3]). Liczba w ostatnich nawiasach kwadratowych musi być równa argumentowi. Konwersja z tablicy tablic do tablicy wskaźników jest nielegalna. Konwersja ze wskaźnika na wskaźnik do tablicy tablic też jest nielegalny. Ale konwersja wskaźnika na wskaźnik do tablicy wskaźników jest legalna!

Więc pamiętaj: tylko najbliższa do typu dereferencji sygnatura nie ma znaczenia, inne robią (w kontekście wskaźników i tablic, oczywiście).

Rozważmy, że mamy jako wskaźnik do wskaźnika do int:

int ** a;
&a     ->     a    ->    *a    ->    **a
(1)          (2)         (3)          (4)
  1. nie można zmienić tej wartości, typem jest int ***. Może być przyjmowana przez funkcję jako int **b[] lub int ***b. Najlepszy jest int *** const b.
  2. typ jest int **. Może być przyjmowana przez funkcję jako int *b[] lub int ** b. Nawiasy tablicy mogą być puste lub zawierać dowolną liczbę.
  3. typem jest int *. Może być przyjmowana przez funkcję jako int b[] lub int * b lub nawet void * b
  4. należy przyjąć jako parametr int. Nie chcę wpadać w szczegóły, jak Ukryte wywołanie konstruktora.

Odpowiadając na twoje pytanie: prawdziwy typ argumentów w funkcji głównej to char ** argv, więc można go łatwo przedstawić jako char *argv[] (ale nie jako char (*argv)[]). Również argv Nazwa głównej funkcji może byćbezpiecznie zmieniona. Możesz to łatwo sprawdzić: std::cout << typeid(argv).name(); (PPc = wskaźnik do znaku P. to)

Przy okazji: jest fajna funkcja, przekazująca tablice jako odniesienia:

void somef(int (&arr)[3])
{
    printf("%i", (sizeof arr)/(sizeof(int))); // will print 3!
}

Ponadto wskaźnik do czegokolwiek może być niejawnie akceptowany (konwertowany) przez funkcję jako wskaźnik void. Ale tylko pojedynczy wskaźnik (Nie wskaźnik do wskaźnika itp.).

Czytaj dalej:

  1. Bjarne Stroustrup, C++, rozdział 7.4
  2. CP FAQ
 -1
Author: yanpas,
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
2016-08-02 18:39:38

Oba są takie same dla Twojego użycia z wyjątkiem następujących subtelnych różnic:

  • Sizeof da różne wyniki dla obu
  • również drugi nie może być przypisany do nowego obszaru pamięci, ponieważ jest tablicą
  • z drugim można używać tylko tych indeksów, które są ważne. Nie jest określony przez C / C++, jeśli spróbujesz użyć indeksu tablicy poza długość tablicy. Jednak z char * * możesz użyć dowolnego indeksu od 0 do ...
  • druga forma może być używana tylko jako formalna parametry do funkcji. While first może być nawet używany do deklarowania zmiennych wewnątrz stosu.
 -2
Author: user5858,
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
2016-05-10 04:42:55