Das Programm ändert nicht die "Basisadresse" des Arrays. Es versucht nicht einmal.
Was Sie an Fn übergeben, ist die Adresse eines Stücks von 256 Zeichen im Speicher. Es ist numerisch identisch mit dem Zeiger, der str
würde in anderen Ausdrücken verfallen, nur anders getippt. Hier bleibt das Array wirklich ein Array - das Anwenden des Adressoperators auf ein Array ist eine der Instanzen, bei denen ein Array nicht zu einem Zeiger wird. Das Inkrementieren von &str
zum Beispiel würde es numerisch um 256 erhöhen. Dies ist wichtig für mehrdimensionale Arrays, die, wie wir wissen, tatsächlich eindimensionale Arrays von Arrays in C sind. Das Inkrementieren des ersten Index eines "zweidimensionalen" Arrays muss die Adresse an den Anfang des nächsten "Chunks" oder "Zeile" weiterleiten.
Jetzt der Haken. In Bezug auf fn verweist die Adresse, die Sie übergeben, auf einen Ort, der eine andere Adresse enthält. Das ist nicht wahr; Es zeigt auf eine Sequenz von Zeichen. Beim Ausdruck dieser als Zeiger interpretierten Bytefolge werden die Bytewerte 'A' 65 oder 0x41 angezeigt.
Fn, jedoch denken, dass der Speicher zeigte auf eine Adresse enthält, überschreibt es mit der Adresse, wo "kj" im Speicher residiert. Da in str genügend Speicher reserviert ist, um eine Adresse zu halten, ist die Zuweisung erfolgreich und führt zu einer verwendbaren Adresse an diesem Ort.
Es sollte beachtet werden, dass dies natürlich nicht garantiert funktioniert. Die häufigste Ursache für einen Fehler sollten Ausrichtungsprobleme sein - str
ist, denke ich, nicht erforderlich, um für einen Zeigerwert richtig ausgerichtet zu sein. Der Standard schreibt vor, dass Argumente für Funktionen mit den Parameterdeklarationen zuweisungskompatibel sein müssen. Beliebige Zeigertypen können nicht einander zugewiesen werden (man muss dafür Void-Pointer durchlaufen oder casten).
Bearbeiten: david.pfx wies darauf hin, dass (auch mit einer richtigen Besetzung) der Code ruft undefined Verhalten. Der Standard erfordert den Zugriff auf Objekte über kompatible lvalues (einschließlich referenzierter Zeiger) in Abschnitt 6.5/7 des letzten öffentlichen Entwurfs. Beim richtigen Casting und Kompilieren mit gcc -fstrict-aliasing -Wstrict-aliasing=2 ...
warnt gcc vor dem "typ punning". Der Grund dafür ist, dass der Compiler frei davon ausgehen kann, dass inkompatible Zeiger den gleichen Speicherbereich nicht modifizieren; hier muss nicht angenommen werden, dass fn den Inhalt von str ändert. Dies ermöglicht dem Compiler, Wegladungen (z. B. von Speicher zu Register), die ansonsten notwendig wären, zu optimieren. Dies wird eine Rolle bei der Optimierung spielen; ein wahrscheinliches Beispiel, bei dem eine Debugsitzung den Fehler nicht reproduzieren könnte (wenn das zu debuggende Programm ohne Optimierung für Debugzwecke kompiliert würde). Davon abgesehen würde ich mich wundern, wenn ein nicht optimierender Compiler hier unerwartete Ergebnisse erzeugen würde, also lasse ich den Rest der Antwort unverändert stehen.-
Ich habe eine Reihe von Debug-Printfs eingefügt, um zu veranschaulichen, was vor sich geht. Ein Live-Beispiel kann hier gesehen werden: http://ideone.com/aL407L.
#include<stdio.h>
#include<string.h>
static char* abc = "kj";
// Helper function to print the first bytes a char pointer points to
void printBytes(const char *const caption, const char *const ptr)
{
int i=0;
printf("%s: {", caption);
for(i=0; i<sizeof(char *)-1; ++i)
{
printf("0x%x,", ptr[i]);
}
printf("0x%x ...}\n", ptr[sizeof(char *)-1]);
}
// What exactly does this function do?
void fn(char**s) {
printf("Inside fn: Argument value is %p\n", s);
printBytes("Inside fn: Bytes at address above are", (char *)s);
// This throws. *s is not a valid address.
// printf("contents: ->%s<-\n", *s);
*s = abc;
printf("Inside fn: Bytes at address above after assignment\n");
printBytes(" (should be address of \"kj\")", (char *)s);
// Now *s holds a valid address (that of "kj").
printf("Inside fn: Printing *s as string (should be kj): ->%s<-\n", *s);
}
int main() {
char str[256];
printf("size of ptr: %zu\n", sizeof(void *));
strcpy(str, "AAAAAAAA"); // 9 defined bytes
printf("addr of \"kj\": %p\n", abc);
printf("str addr: %p (%p)\n", &str, str);
printBytes("str contents before fn", str);
printf("------------------------------\n");
// Paramter type does not match! Illegal code
// (6.5.16.1 of the latest public draft; incompatible
// types for assignment).
fn(&str);
printf("------------------------------\n");
printBytes("str contents after fn (i.e. abc -- note byte order!): ", str);
printf("str addr after fn -- still the same! --: %p (%p)\n", &str, str);
return 0;
}
für die Nachwelt, [hier] (http://stackoverflow.com/questions/25660493/assigning-to-a-char-array-using-assignment-operator-and-double-pointers) ist die gelöschte Frage –