2011-01-10 3 views

Antwort

5

Sie sind funktionell gleich. Sie sollten die zweite Methode verwenden und einen Parameter für die Länge des Arrays übergeben.

Andernfalls Sie Ärger bringen:

// this will compile without warning, even if using -Wall 
int myArray[50] = {0}; 
foo(myArray); 

Wenn foo() geht davon aus, dass das Array tatsächlich 100 Elemente lang ist, wird es das Array überrannt.

bessere Art und Weise:

int foo(int *array, size_t array_len) { 
    // do stuff 
} 

Noch besser, verwenden Sie einen vector, die mit ihm seine Größe trägt und Sie können nicht (unter normalen Umständen) Zugang über das Ende des Vektors:

int foo(const std::vector<int>& array) { 
    // do stuff 
} 
+0

... oder Sie können das [Array durch Verweis] übergeben (http://stackoverflow.com/questions/4650974/was-hat-es-sich-zu-haben-array-mit-size-in-function-parameters/4651412 # 4651412). –

+0

Schön. Ich vermeide heutzutage die Verwendung von nackten Arrays, daher wusste ich nichts darüber. – Nate

1

Kein Unterschied mit dieser Deklaration

int foo(int array[100]) //1 
int foo(int array[]) //2 
int foo(int *array) //3 

Wenn Funktion übernehmen kann ly feste Größe Array, in diesem Fall 100 Elemente, 1 Version sind klarer zu programmieren, die diese Funktion verwenden. In allen anderen Fällen - 3 sind gute Wahl

+2

Korrigieren Sie, dass es keinen Unterschied gibt, aber ich würde argumentieren, dass das zweite oder dritte klarer ist, weil sie nicht in die Irre führen. –

+1

Wenn die Funktion nur Arrays mit genau 100 Elementen aufnehmen kann, können Sie dies durch Verwendung der Referenzsemantik 'int foo (int (& array) [100]) 'erzwingen, die sowohl klar als auch sicher ist. Option 1 ist eindeutig unsicher. Es kann ein falsches Gefühl von Sicherheit erzeugen - es müssen 100 Elemente sein !, aber der Compiler akzeptiert gerne, wenn Sie (aus Versehen) ein Array von 10 Elementen übergeben, und dann haben Sie undefiniertes Verhalten: Pufferüberlauf, möglicher Absturz. .. –

2

Nichts, sie funktionieren auf die gleiche Weise. Hier ein kurzes Beispiel:

int WithArray(int array[10]) 
{ 
    return array[1] + array[2];     // breakpoint 1 
} 

int WithPointer(int *pointer) 
{ 
    return *(pointer + 1) + *(pointer + 2);  // breakpoint 2 
} 

void main() 
{ 
    int array[] = {0,1,2,3,4,5,6,7,8,9}; 

    int b = WithPointer(array); 
    int a = WithArray(array); 

    printf("a = %d\nb = %d\n", a, b); 
} 

Ok, werde ich rufen WithPointer() zunächst nur für den Fall WIthArray() kopiert das Array auf dem Stapel. Hier ist der Stapel an dem zweiten Unterbrechungspunkt:

Breakpoint 2, WithPointer (pointer=0xbffff418) at prova.c:10 
10  return *(pointer + 1) + *(pointer + 2); 
(gdb) x/20x ($esp - 8) 
0xbffff404: 0x08049ff4 0xbffff418 0xbffff448 0x0804843b 
0xbffff414: 0xbffff418 0x00000000 0x00000001 0x00000002 
0xbffff424: 0x00000003 0x00000004 0x00000005 0x00000006 
0xbffff434: 0x00000007 0x00000008 0x00000009 0x08048460 
0xbffff444: 0x00000000 0xbffff4c8 0x00144bd6 0x00000001 

Wie erwartet gibt es unsere Zeiger (0xbffff418, der erste Wert in der zweiten Zeile) und direkt danach, array [] (die auf Haupt ist()‘ s Stapelrahmen). Lasst uns den Stapel innerhalb WithArray überprüfen():

(gdb) continue 
Continuing. 

Breakpoint 1, WithArray (array=0xbffff418) at prova.c:5 
5  return array[1] + array[2]; 
(gdb) x/20x ($esp - 8) 
0xbffff404: 0x08049ff4 0xbffff418 0xbffff448 0x08048449 
0xbffff414: 0xbffff418 0x00000000 0x00000001 0x00000002 
0xbffff424: 0x00000003 0x00000004 0x00000005 0x00000006 
0xbffff434: 0x00000007 0x00000008 0x00000009 0x08048460 
0xbffff444: 0x00000003 0xbffff4c8 0x00144bd6 0x00000001 

Genau die gleiche Sache! Es gibt also keinen Unterschied darüber, wie sie an Funktionen weitergegeben werden. Und sie sind in der gleichen Weise behandelt, aussehen:

(gdb) disass WithPointer 
Dump of assembler code for function WithPointer: 
    0x080483cc <+0>: push %ebp 
    0x080483cd <+1>: mov %esp,%ebp 
    0x080483cf <+3>: mov 0x8(%ebp),%eax   # get base address 
    0x080483d2 <+6>: add $0x4,%eax    # compute offset 
    0x080483d5 <+9>:  mov (%eax),%edx   # dereference and get val. 
    0x080483d7 <+11>: mov 0x8(%ebp),%eax   # base address 
    0x080483da <+14>: add $0x8,%eax    # offset (2 * sizeof(int)) 
    0x080483dd <+17>: mov (%eax),%eax   # get *eax 
    0x080483df <+19>: lea (%edx,%eax,1),%eax  # tricky way to add them 
    0x080483e2 <+22>: pop %ebp 
    0x080483e3 <+23>: ret  
End of assembler dump. 
(gdb) disass WithArray 
Dump of assembler code for function WithArray: 
    0x080483b4 <+0>:  push %ebp 
    0x080483b5 <+1>:  mov %esp,%ebp 
    0x080483b7 <+3>:  mov 0x8(%ebp),%eax   # first element of array 
    0x080483ba <+6>:  add $0x4,%eax    # move to the second 
    0x080483bd <+9>:  mov (%eax),%edx   # and get its value 
    0x080483bf <+11>: mov 0x8(%ebp),%eax   # base of array 
    0x080483c2 <+14>: add $0x8,%eax    # compute address of second 
    0x080483c5 <+17>: mov (%eax),%eax   # element and get load it 
    0x080483c7 <+19>: lea (%edx,%eax,1),%eax  # compute sum 
    0x080483ca <+22>: pop %ebp 
    0x080483cb <+23>: ret  
End of assembler dump. 

Codes sind identisch. Beachten Sie, dass das Array wie ein Zeiger behandelt wird.

3

In C++ können Sie kein Array als Argument an eine Funktion übergeben. Eine Funktionsdeklaration, die einen Parameter vom Typ array of T aufweist, wird gemäß §8.3.5 in pointer to T umgewandelt.Dies bedeutet, dass die folgenden Erklärungen sind genau äquivalent:

void f(int a[10]); 
void f(int a[]); 
void f(int *a); 

Also in der Tat, wie Sie sie für den Compiler genau gleichwertig weisen darauf hin, sind selbst dann, wenn der erste könnte man den Code zu lesen, als die angegebene Größe für Entwickler irreführend sein in der Erklärung wird nicht durchgesetzt.

Dies unterscheidet sich von Funktionsparametern, die reference to array of T vom Typ sind, wobei das Argument Zerfall auf einen Zeiger nicht, sondern hält vielmehr die volle Art:

void f(int (&a)[10]); // takes an array of exactly 10 integers 

In diesem Fall wird der Compiler tatsächlich Erzwingen Sie den Typ der Referenz, die array of 10 int (einschließlich Größe) ist. Der Code innerhalb der Funktion kann davon ausgehen, dass es immer 10 Elemente geben wird, und der Compiler stellt dies sicher.

§8.3.5 [dcl.fct]/3

[...] den Typs jeden Parameter, beliebige Parameter des Typs „array of T“ oder „-Funktion zurückkehren T“ Nach der Bestimmung ist, eingestellt auf "Zeiger auf T" oder "Zeiger auf Funktion, die T zurückgibt", [...]

Verwandte Themen