2014-09-30 12 views
5

Dieses ist eher eine begriffliche Frage an diesem Punkt eher als eine praktische aber es stört mich wirklich.Finden der Größe einer Zeichenkette in argv using sizeof

Lassen Sie uns sagen, ich habe ein c-Programm namens "test.c" und ich möchte die Anzahl der Leerzeichen in Array gibt es für ein Wort, das der Benutzer als ein Argument eingibt. Zum Beispiel sollte "./test.c test_run" 9 drucken, da es 8 Zeichen und dann eins für das nullende Zeichen gibt. Wenn ich versuche, sizeof auf argv zu verwenden, habe ich einige Probleme.

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

das Ergebnis Druckt: "Die Größe buf10 ist: 10.". Das macht Sinn, weil ich ein Char-Array gewählt habe. In C ist die Größe eines Zeichens 1 Byte. Wenn ich int wählen würde, wäre diese Zahl 4.

Jetzt ist meine Frage, warum kann ich das nicht mit Argv tun?

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 mit "./test Hello_SO" gibt die Ausgabe:

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

Die Stringlänge macht Sinn, weil es 9 sein sollte, aber minus der "\ 0" macht 8.

Allerdings verstehe ich nicht, warum sizeof 4 (die Größe des Zeigers) zurückgibt. Ich verstehe, dass * argv [] als ** argv gedacht werden kann. Aber ich habe dies bereits berücksichtigt. In meinem ersten Beispiel drucke ich "buf", aber hier drucke ich "argv [1]". Ich weiß, ich könnte leicht die Antwort bekommen, indem ich strlen benutze, aber wie ich schon sagte, das ist an dieser Stelle nur konzeptionell.

+0

Klingt, als ob Sie vielleicht Ihre eigene Frage beantwortet haben. – alex

+0

'argv [1]' hat den Typ 'char *', also bedeutet 'sizeof argv [1]' 'sizeof (char *)'. Das ist, was Größe macht. –

+0

Aber warum druckt buf10 10 und argv [1] nicht 9. buf10 ist auch ein Zeiger, ist es nicht? –

Antwort

3

Zeiger und Arrays sind nicht dasselbe, obwohl sie in vielen Situationen sehr ähnlich sind. sizeof ist ein wichtiger Unterschied.

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

Die Art der oben arrint[10] ist. Eine andere Möglichkeit, den Unterschied zwischen Array-Typen und -Zeigern zu erkennen, besteht darin, ihnen zuzuordnen.

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

Arrays können nicht zugewiesen werden.

Was die meisten verwirrend ist, dass wenn Sie ein Array als Funktionsparameter haben, ist es tatsächlich ist das gleiche einen Zeiger hat mit.

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

Ihre Frage zu beantworten, warum Sie nicht sizeof argv[1] verwenden können und die Größe der Zeichenfolge (plus 1 für die \0) erhalten, ist es, weil es ein zerlumpter Array ist. In diesem Fall ist die erste Dimension ebenso unbekannt wie die zweite. sizeof verhält sich in diesem Fall wie eine Kompilierzeit, und die Länge der Zeichenfolge ist erst zur Laufzeit bekannt.

Betrachten Sie das folgende Programm:

#include <stdio.h> 

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

Die Anordnung für diese erzeugt:

.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 

wie Sie sehen können, ist das Ergebnis von sizeof argv[1] bei der Kompilierung durchgeführt wird, nichts über das ist das Berechnen Länge der Zeichenfolge. Ich bin auf 64-Bit, also sind meine Zeiger 8 Bytes.

+1

Die Verwirrung wird wirklich durch die Tatsache verursacht, dass du kein Array als Funktionsparameter haben kannst - wenn du Deklariere einen Funktionsparameter als Array, der Compiler verwandelt ihn still in einen Zeiger für dich, "hilfreich", der jedes Missverständnis verdeckt und zu Fehlern wie diesen führt. –

+0

@ChrisDodd ja, aber nicht zu mehrdimensionalen Arrays, die unterschiedliche Regeln haben. –

+0

Keine mehrdimensionalen Arrays in C - nur Arrays von Arrays, die wie andere Arrays zu Zeigern werden, wenn sie als Argumente verwendet werden. Dann gibt es auch die Verwirrung zwischen Arrays von Arrays und Arrays von Zeigern, die völlig unterschiedlich sind, obwohl sie mit derselben Syntax zugänglich sind. –

1

Die buf10-Variable ist zur Kompilierungszeit als (zusammenhängendes) Array von zehn Zeichen bekannt. Die anderen Zeiger werden dynamisch zugewiesen und sind Zeiger auf ein Zeichen. Aus diesem Grund erhalten Sie die Größe des Zeichenarrays gegenüber der Größe von (char *).

+0

Also gibt es einen Unterschied zwischen char buf10 [10] = "Hallo" und char buf10 [] = "Hallo" dann? –

+1

Letztere berechnet die Länge des Arrays basierend darauf, wie viel Speicherplatz zum Speichern von "Hello" benötigt wird. also wird die Größe von 6. Es ist immer noch ein Array. Wenn du 'const char * s =" Hello "' hättest, dann wäre 'sizeof s'' sizeof (char *) ' –