2010-06-29 2 views
11

Mögliche Duplizieren:
Take the address of a one-past-the-end array element via subscript: legal by the C++ Standard or not?Darf ich die Adresse des one-over-the-end-Elements eines Arrays nehmen?

int array[10]; 

int* a = array + 10; // well-defined 
int* b = &array[10]; // not sure... 

Ist die letzte Zeile gültig ist oder nicht?

+2

Dupe des legendären http://stackoverflow.com/questions/988158/ Take-the-Adresse-von-einer-Vergangenheit-das-Ende-Array-Element-via-Subscript-Legal-by-the –

+0

@Johannes - Sie haben Recht, zu schließen zu stimmen. – Omnifarious

Antwort

19

Ja, Sie können die Adresse über das Ende eines Arrays hinaus nehmen, aber Sie können es nicht dereferenzieren. Für Ihr Array von 10 Elementen würde array+10 funktionieren. Es wurde ein paar Mal (ua vom Komitee) diskutiert, ob &array[10] wirklich undefiniertes Verhalten verursacht oder nicht (und wenn ja, ob es wirklich so ist). Die Quintessenz davon ist, dass es zumindest nach den aktuellen Standards (sowohl C als auch C++) offiziell undefiniertes Verhalten verursacht, aber wenn es einen einzigen Compiler gibt, für den es eigentlich nicht funktioniert, war niemand in der Lage um es zu finden oder zu zitieren.

Edit: Für einmal mein Gedächtnis halb richtig war - das war (Teil) eine offizielles Defect Report den Ausschuß, und zumindest einige Ausschussmitglieder (zB Tom Plum) dachte die Formulierung geändert worden ist, so wäre es nicht verursachen undefiniertes Verhalten. OTOH, der DR stammt aus dem Jahr 2000, und der Status ist immer noch "Drafting", also ist es offen zu fragen, ob es wirklich repariert ist oder jemals sein wird (ich habe nicht durch N3090/3092 geschaut, um herauszufinden). In C99 ist es jedoch klar nicht undefined Verhalten.

+1

Gute Antwort. Als ein vielleicht interessanter Punkt der Geschichte sah ich tatsächlich einen C-Compiler, der die & Dereferenzierung von Array [N] nicht richtig deutete. Es war auf HP RTE auf einem HP-1000 Mainframe.Es hatte einen Speicher- "Zaun" direkt über meinem Array gesetzt, so dass die Referenzadresse im Adressraum des Programms nicht existierte. Dies war vor dem C-Standard von 1989. Ich denke also, dass dieser Compiler nicht mehr existiert. –

+0

Die Sprache von dieser DR ist nicht in N3092. Obwohl ich sie jetzt nicht finden kann, gibt es mehrere _closed_ DRs, die auf die "leere Lvalue" Sprache in der vorgeschlagenen Auflösung zu diesem Fehler ... –

1

Nein. Es ist nicht definiert. array[10] entspricht *(array + 10). Mit anderen Worten, Sie haben einen ungültigen Zeiger dereferenziert.

+3

Aber er hat es nicht dereferenziert ... –

+1

@clmh Es gibt eine definitive Debatte darüber, ob '& * p' technisch ein No-Op darstellt, oder eine Dereferenz gefolgt von einer Adresse-of. –

+1

'& array [10]' ist legal und das Element wird nicht dereferenziert. –

2

array[10] entspricht *(array + 10) (und auch gleichwertig 10[array]), so &array[10] verhält sich wie die * von *(array+10) entfernen. Jeder vernünftige Compiler sollte den gleichen Code (und die gleiche Warnung) ausgeben.

8

Wie andere Antworten gezeigt haben, entspricht der Ausdruck array[10]*(array + 10), was zu einer undefinierten Dereferenzierung des Elements direkt nach dem Ende des Arrays führen würde. jedoch ist der Ausdruck &array[10] entspricht &*(array + 10) und der C99-Standard macht deutlich, (6.5.3.2-Adresse und Indirektion Operatoren):

unären & Operator gibt die Adresse des Operanden. Wenn der Operand den Typ '' type '' hat, hat das Ergebnis den Typ '' pointer to type ''. Wenn der Operand das Ergebnis eines unären *-Operators ist, wird weder dieser Operator noch der Operator & ausgewertet, und das Ergebnis ist so, als ob beide weggelassen würden, außer dass die Einschränkungen für die Operatoren weiterhin gelten und das Ergebnis kein Lvalue ist. Und falls der Operand das Ergebnis eines [] Betreiber weder die & Betreiber noch einstelligen *, die von den [] impliziert wird ausgewertet und das Ergebnis ist, als ob die & Betreiber wurden entfernt und die [] Betreiber zu einem Operator + geändert wurden .

Also, es gibt nichts Undefiniert über &array[10] - es gibt keine Dereferenzierungsoperation, die stattfindet.

+5

C99 ist nicht C++. –

-2

Dies ist eigentlich eine ziemlich einfache Sache zu beantworten.

Alles, was Sie tun, ist Zeiger Mathematik, es gibt nichts daran Ungültiges. Wenn Sie versuchen, die resultierenden Zeiger irgendwie zu VERWENDEN, hängt es davon ab, ob Ihr Prozess Zugriff auf den Speicher hat, auf den dieser Zeiger zeigt, und wenn ja, welche Berechtigungen haben sie?

foo.cc:

#include <iostream> 

using namespace std; 
int main() { 
     int array[10]; 
     int *a = array + 10; 
     int *b = &array[10]; 
     int *c = &array[3000]; 

     cerr << "Pointers values are: " << a << " " << b << " " << c << endl; 
     return 0; 
} 

kompilieren:

g++ -Werror -Wall foo.cc -o foo 

sollte keine Warnungen ergeben, da der int * b = & array [10] gültig ist

Eigentlich so ist die folgende Zeile, die ich hinzugefügt habe, um etwas über Zeigermathematik zu sagen.

nicht nur foo kompilieren, wird es ohne Probleme laufen:

./foo 
    Pointers are: 0x7fff1d356e68 0x7fff1d356e68 0x7fff1d359d20 

Grundsätzlich Array-Syntax foo [idx] ist kurz geschnitten und saubere Darstellung von Zeigermathematik.

Für den Fall, dass es etwas Verwirrung in Bezug auf c99 gibt, beeinflusst der Standard diese Mathematik in keiner Weise und gut definiert.

Dasselbe in C99:

#include <stdio.h> 

int main() { 
     int array[10]; 
     int *a = array + 10; 
     int *b = &array[10]; 
     int *c = &array[3000]; 

     fprintf(stderr, "Pointers are: %p, %p, %p\n" , a , b , c); 
     return 0; 
} 

Dann:

gcc -std=c99 -Wall -Werror -o foo foo.c 

./foo 

Ausgänge:

Pointers are: 0x7fff2c7d22c8, 0x7fff2c7d22c8, 0x7fff2c7d5180