2014-09-30 17 views
5

Questa è più una domanda concettuale a questo punto piuttosto che una pratica, ma mi dà davvero fastidio.Trovare la dimensione di una stringa in argv usando sizeof

Diciamo che ho un programma c chiamato "test.c" e voglio trovare il numero di spazi in array ci sono per una parola che l'utente digita come argomento. Ad esempio "./test.c test_run" dovrebbe stampare 9 perché ci sono 8 caratteri e quindi uno per il carattere di terminazione null. Quando cerco di usare sizeof su argv, ho qualche problema.

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

stampa il risultato: "La dimensione buf10 è: 10.". Questo ha senso perché ho scelto un array di caratteri. In C, la dimensione di un carattere è 1 byte. Se ho scelto int, questo numero sarebbe 4.

Ora la mia domanda è perché non posso farlo con 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 con "./test Hello_SO" dà l'output:

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

La lunghezza della stringa senso perché esso deve essere 9 ma meno il "\ 0" rende 8.

Tuttavia non capisco perché sizeof restituisca 4 (la dimensione del puntatore). Capisco che * argv [] può essere pensato come ** argv. Ma ne ho già tenuto conto. Nel mio primo esempio stampo "buf" ma qui stampo "argv [1]". So che potrei ottenere facilmente la risposta usando strlen ma come ho detto prima questo è solo concettuale a questo punto.

+0

Sembra che tu abbia forse risposto alla tua stessa domanda. – alex

+0

'argv [1]' ha tipo 'char *', quindi 'sizeof argv [1]' significa 'sizeof (char *)'. Questo è ciò che fa sizeof. –

+0

Ma perché buf10 print 10 e argv [1] non stampano 9. buf10 è anche un puntatore vero? –

risposta

3

I puntatori e gli array non sono la stessa cosa, anche se sono abbastanza simili in molte situazioni. sizeof è una differenza fondamentale.

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

Il tipo di arr sopra è int[10]. Un altro modo per vedere la differenza tra i tipi di array e i puntatori è cercare di assegnarli.

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

non è possibile assegnare gli array a.

Ciò che è più confuso è che quando si dispone di un array come parametro di funzione, in realtà è lo stesso ha un puntatore.

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

Per rispondere alla sua domanda del perché non è possibile utilizzare sizeof argv[1] e ottenere la dimensione della stringa (più il 1 per il \0), è perché si tratta di una matrice irregolare. In questo caso la prima dimensione è di dimensioni sconosciute, così come la seconda. sizeof si comporta come un'operazione di compilazione in questo caso e la lunghezza della stringa non è nota fino al runtime.

Si consideri il seguente programma:

#include <stdio.h> 

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

L'assemblea generato per questo è:

.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 

come si può vedere, il risultato di sizeof argv[1] è fatto al momento della compilazione, nulla al di sopra sta calcolando la lunghezza della corda. Sono a 64 bit, quindi i miei indicatori sono 8 byte.

+1

La confusione è veramente causata dal fatto che NON PUOI avere un array come parametro di funzione - se tu dichiarare un parametro di funzione come una matrice, il compilatore silenziosamente lo trasforma in un puntatore per te, "utile" che nasconde ogni incomprensione e porta a errori come questi. –

+0

@ChrisDodd sì, ma non dimenticare gli array multidimensionali che hanno regole diverse. –

+0

Non esistono array multidimensionali in C: solo array di matrici, che diventano puntatori quando vengono utilizzati come argomenti, proprio come qualsiasi altro array. Poi c'è anche la confusione tra array di matrici e array di puntatori, che sono completamente diversi nonostante siano accessibili con la stessa sintassi. –

1

La variabile buf10 è nota al momento della compilazione come una matrice (contigua) di dieci caratteri. Gli altri puntatori sono allocati dinamicamente e sono indicatori di un carattere. Questo è il motivo per cui ottieni la dimensione dell'array di caratteri rispetto a sizeof (char *).

+0

Quindi c'è una differenza tra char buf10 [10] = "Ciao" e char buf10 [] = "Ciao" allora? –

+1

quest'ultimo calcola la lunghezza dell'array in base a quanto spazio è necessario per memorizzare "Hello". quindi la dimensione sarà 6. Comunque è ancora un array. Se hai fatto 'const char * s =" Hello "' allora 'sizeof s' sarebbe' sizeof (char *) ' –