2014-09-30 15 views
5

Jest to raczej pytanie koncepcyjne w tym miejscu, a nie praktyczne, ale naprawdę przeszkadza mi.Znaleźć rozmiar ciągu w argv używając sizeof

Załóżmy, że mam program c o nazwie "test.c" i chcę znaleźć liczbę spacji w tablicy dla słowa, które użytkownik wpisze jako argument. Na przykład "./test.c test_run" powinno wypisać 9, ponieważ jest 8 znaków, a potem 1 znak kończący zero. Kiedy próbuję użyć sizeof na argv chociaż mam problemy.

int main(int argc, char *argv[]) { 
    char buf10[10]; 
    printf("The size of buf10 is: %i.\n", sizeof(buf10)); 
    return 0; 
} 

drukuje wynik: "Wielkość buf10 jest: 10.". Ma to sens, ponieważ wybrałem tablicę znaków. W języku C rozmiar znaku to 1 bajt. Jeśli wybiorę int, ta liczba będzie 4.

Teraz moje pytanie brzmi: dlaczego nie mogę tego zrobić z argv?

int main(int argc, char *argv[]) { 
    printf("argv[1] has the value: %s\n", argv[1]); 
    printf("strlen of argv[1] is: %i\n", strlen(argv[1])); 
    printf("sizeof of argv[1] is: %i\n", sizeof(argv[1])); 
    return 0; 
} 

Ran z "./test Hello_SO" daje wynik:

argv[1] has the value: Hello_SO 
strlen of argv[1] is: 8 
sizeof of argv[1] is: 4 

Długość ciąg sens, ponieważ powinno być 9 ale minus "\ 0" sprawia 8.

Jednak nie rozumiem, dlaczego sizeof powraca 4 (rozmiar wskaźnika). Rozumiem, że * argv [] można uważać za ** argv. Ale już to uwzględniłem. W moim pierwszym przykładzie drukujemy "buf", ale tutaj drukujemy "argv [1]". Wiem, że mogę łatwo uzyskać odpowiedź za pomocą strlen, ale jak powiedziałem wcześniej, jest to po prostu koncepcyjne w tym momencie.

+0

Wygląda na to, że prawdopodobnie odpowiedziałeś na własne pytanie. – alex

+0

'argv [1]' ma typ 'char *', więc 'sizeof argv [1]' oznacza 'sizeof (char *)'. To właśnie robi sizeof. –

+0

Ale dlaczego buf10 drukuje 10, a argv [1] nie drukuje 9. buf10 jest także wskaźnikiem czy nie jest? –

Odpowiedz

3

Wskaźniki i tablice to nie to samo, choć w wielu sytuacjach są bardzo podobne. sizeof to kluczowa różnica.

int arr[10]; 
assert(sizeof arr == (sizeof(int) * 10)); 
int *ip; 
assert(sizeof ip == sizeof(int*)); 

Typ arr powyżej int[10]. Innym sposobem odróżnienia typów tablic od wskaźników jest próba przypisania im.

int i; 
ip = &i; // sure, fine 
arr = &i; // fails, can't assign to an int[10] 

tablic nie można przypisać.

Najbardziej mylące jest to, że gdy masz tablicę jako parametr funkcji, to faktycznie to to samo ma wskaźnik.

int f(int arr[10]) { 
    int x; 
    arr = &x; // fine, because arr is actually an int* 
    assert(sizeof arr == sizeof(int*)); 
} 

Aby zaadresować pytanie, dlaczego nie można używać sizeof argv[1] i uzyskać rozmiaru łańcucha (plus 1 dla \0), to dlatego, że to poszarpany tablicą. W tym przypadku pierwszy wymiar ma nieznany rozmiar, a także drugi. sizeof zachowuje się jak operacja czasu kompilacji w tym przypadku, a długość łańcucha nie jest znana do czasu wykonywania.

Rozważmy następujący program:

#include <stdio.h> 

int main(int argc, char *argv[]) { 
    printf("%zu\n", sizeof argv[1]); 
} 

Zespół generowany jest:

.LC0: 
    .string "%zu\n" 
    .text 
    .globl main 
    .type main, @function 
main: 
.LFB3: 
    .cfi_startproc 
    subq $8, %rsp 
    .cfi_def_cfa_offset 16 
    movl $8, %esi  # this 8 is the result of sizeof 
    movl $.LC0, %edi  # the format string 
    movl $0, %eax 
    call printf   # calling printf 
    movl $0, %eax 
    addq $8, %rsp 
    .cfi_def_cfa_offset 8 
    ret 
    .cfi_endproc 

jak widać, wynik sizeof argv[1] odbywa się w czasie kompilacji, nic powyżej obliczaniu długość struny. Mam 64-bitowe, więc moje wskaźniki są 8 bajtów.

+1

To zamieszanie jest tak naprawdę spowodowane tym, że NIE MOŻESZ MIEĆ tablicy jako parametru funkcji - jeśli zadeklaruj parametr funkcji jako tablicę, kompilator po cichu zamieni go w wskaźnik dla ciebie, "pomocniczo", ukrywając wszelkie nieporozumienia i prowadząc do takich błędów. –

+0

@ChrisDodd tak, ale nie zapominaj o tablicach wielowymiarowych, które mają różne reguły. –

+0

Nie ma czegoś takiego jak wielowymiarowe tablice w C - tylko tablice tablic, które zamieniają się w wskaźniki, gdy są używane jako argumenty, tak jak każda inna tablica. Istnieje również zamieszanie między tablicami tablic i tablicami wskaźników, które są zupełnie inne, mimo że można je uzyskać za pomocą tej samej składni. –

1

Zmienna buf10 jest znana w czasie kompilacji jako (ciągła) tablica złożona z dziesięciu znaków. Pozostałe wskaźniki są przydzielane dynamicznie i są wskaźnikami do postaci. Dlatego otrzymujesz rozmiar tablicy znaków vs sizeof (char *).

+0

Czy istnieje różnica między char buf10 [10] = "Hello" i char buf10 [] = "Hello", a następnie? –

+1

ten ostatni obliczy długość tablicy w oparciu o to, ile miejsca potrzeba do przechowywania "Hello". więc rozmiar będzie wynosił 6. To wciąż jest tablica. Jeśli zrobiłeś "const char * s =" Hello ", to' sizeof s' to będzie 'sizeof (char *)' –