Anzeige:
Seite 2 von 2 ErsteErste 12
Ergebnis 16 bis 27 von 27

Thema: Frage zu Segmentation fault (Unterschied zwischen Array und Zeiger)

  1. #16
    Registrierter Benutzer
    Registriert seit
    27.05.2005
    Beiträge
    31
    Natürlich ist "NULL" definiert, sonst könntest du es ja gar nicht verwenden.
    Ist in irgendeiner Header mithilfe der Präprozessor Direktiven definiert worden.
    Wenn ich mir den Wert von NULL ausgeben lasse erscheint 0, also denke
    ich mal das die Symbolische-Konstante NULL den dezimalen Wert 0 hat.

  2. #17
    Registrierter Benutzer Avatar von peschmae
    Registriert seit
    14.03.2002
    Ort
    Schweizland
    Beiträge
    4.549
    Ach jetzt heissts plötzlich NULL. Ein kleines Chamäleon haben wir da

    Na, egal, ich halts mit Stroustrup und find NULL blöd.

    MfG Peschmä
    The greatest trick the Devil ever pulled was convincing the world he didn't exist. -- The Usual Suspects (1995)
    Hey, I feel their pain. It's irritating as hell when people act like they have rights. The great old one (2006)

  3. #18
    Registrierter Benutzer Avatar von BLUESCREEN3D
    Registriert seit
    08.11.2002
    Beiträge
    665
    Zitat Zitat von bischi
    Ich schreib da jeweils char a = null;
    Ich vermute du meinst NULL?

    Das bevorzuge ich eigentlich auch, aber manchmal ist das als Zeiger definiert und dann kriegt man eine Warnung bei der Zuweisung...

  4. #19
    Registrierter Benutzer Avatar von guardian
    Registriert seit
    16.07.2003
    Beiträge
    25
    BTW hier (FAQ in de.comp.lang.c) ist eine recht interessant FAQ bezüglich der Null- bzw. NULL-Zeiger.

    Bezieht sich zwar nicht auf den aktuellen FinalDraft bzw. Standard (welchen ich moment nicht zur Hand hab) aber trotzdem ganz gut
    Geändert von guardian (07-02-2006 um 10:59 Uhr)
    If you have any problems feel free to mail me and I'll probably feel free to ignore you :p

  5. #20
    Registrierter Benutzer
    Registriert seit
    23.05.2004
    Beiträge
    592
    Zitat Zitat von locus vivendi Beitrag anzeigen

    Aber warum wird zwischen bla1 und bla2 überhaupt ein Unterschied gemacht? Eigentlich sind Arrays und Zeiger intern doch das gleiche!?
    Ein recht verbreiteter Irtum. Nein, Zeiger und Arrays sind nicht das gleiche. Aber deshalb stürzt dein Programm nicht ab. bla1 und bla2 unterscheiden sich in der Beziehung gar nicht, auch wenn du das glaubst. Beide sind Zeiger, und beide Zeigen auf ein Array. Der Unterschied ist bloß, das bla2 auf eine Array zeigt, welches du nicht verändern darfst.
    Keine Ahnung warum ich das damals geschrieben habe. Im zweiten Satz schreibe ich korrekt, das Zeiger und Arrays nicht das gleiche sind. Zwei Sätze weiter widerspreche ich mir dann quasi selber, und schreibe fälschlicherweise das "bla1" und "bla2" aus dem Ursprungspost beides Zeiger wären. Richtig ist natürlich das "bla1" tatsächlich ein Array ist, wie Bluescreen3d auch angedeuet hat. Hingegen ist "bla2" tatsächlich ein Zeiger.

  6. #21
    Registrierter Benutzer
    Registriert seit
    07.05.2007
    Beiträge
    656
    Moin,

    Zitat Zitat von bischi Beitrag anzeigen
    Wundert mich sowieso, dass

    char a=0;

    einfach so geht; Mach doch zumindest ' ' drumherum...
    Selbstverständlich geht das. char ist nichts weiter als ein 8-Bit-Wert, warum soll man dem nicht 0 zuweisen können? Alle numerischen Werte von -127...127 gehen. '0' ist was anderes, das ist das Gleiche wie char a=48; Dem char a=0; würde in "Character"-Schreibweise ein char a='\0'; entsprechen, aber das ist nur eine andere Schreibweise. Übrigens: char a=NULL; ist nicht zwingend identisch dazu.

    Jan

  7. #22
    Registrierter Benutzer Avatar von ContainerDriver
    Registriert seit
    10.01.2003
    Beiträge
    418
    Zitat Zitat von locus vivendi Beitrag anzeigen
    Da sollte man nicht vermuten. In eine Stringliteral darf man nicht schreiben.
    Hab die letzten paar Tage das selbe Problem gehabt. Wieso darf man das nicht? Weil es der Standard so vorschreibt oder hat das einen praktischen Nutzen?


    Gruß, Florian
    Ein gebrechlich Wesen ist der X-Server.

  8. #23
    Registrierter Benutzer
    Registriert seit
    16.06.2003
    Beiträge
    73
    Hi,

    der praktische Nutzen ist der, dass der Compiler einen Stringliteral fest mit in den Sourcecode einbetten kann. Damit gehört der Stringliteral zum eigentlichen Programmcode.
    Arrays werden erst zur Laufzeit auf dem Heap angelegt und gehören damit zu den Programmdaten, welche zur Laufzeit entstehen und damit auch verändert werden können.
    Man versuchtst also mit dem Pointer auf ein Stringliteral außerhalb des Heaps des Programms zu schreiben. Da moderne Systeme das verändern des eigentlichen Programmcodes zur Laufzeit verhindern gibt es dann einen Segmentation Fault.

    Gruß

    almoeli

  9. #24
    Registrierter Benutzer Avatar von BLUESCREEN3D
    Registriert seit
    08.11.2002
    Beiträge
    665
    Zitat Zitat von ContainerDriver Beitrag anzeigen
    Wieso darf man das nicht? Weil es der Standard so vorschreibt oder hat das einen praktischen Nutzen?
    Der praktische Nutzen, dass es überhaupt read-only-Bereiche im virtuellen Speicher gibt, sind Sicherheit und z.B. die Möglichkeit, dass bei einem fork() der neu entstehende Prozess den alten Speicherbereich mit dem Code mitnutzen kann (mittels Copy-On-Write kann auch der restliche Speicher erstmal gemeinsam genutzt werden).

    Zitat Zitat von almoeli Beitrag anzeigen
    Arrays werden erst zur Laufzeit auf dem Heap angelegt und gehören damit zu den Programmdaten, welche zur Laufzeit entstehen und damit auch verändert werden können.
    Das kann so nicht ganz stimmen, denn irgendwo muss der Inhalt des Arrays ja auch her kommen.
    Hier steht auch, dass die Daten nicht im Heap liegen: http://en.wikipedia.org/wiki/Data_segment

    Warum in C/C++ gerade festgelegt wurde, dass char *bla = "text" in den read-only-Bereich kommt und char bla[] = "text" nicht, wüsste ich auch gerne
    edit: Liegt wohl daran, dass man wegen der Möglichkeit, Arrays ohne Inhalt definieren zu können, einfach erwartet, dass der Inhalt eines Arrays im Normalfall geändert werden kann. Und die Array-Schreibweise ist ja nur eine Abkürzung für char bla[] = {'t', 'e', 'x', 't', 0}. Insofern ist das eben ein Sonderfall, während man beim Zeiger ein ganz normales String-Literal hat, wie es auch in printf("%d", a) auftauchen kann und da ist es schon besser, wenn das read-only ist.
    Geändert von BLUESCREEN3D (12-03-2008 um 15:02 Uhr)

  10. #25
    Registrierter Benutzer Avatar von ContainerDriver
    Registriert seit
    10.01.2003
    Beiträge
    418
    Zitat Zitat von BLUESCREEN3D Beitrag anzeigen
    Der praktische Nutzen, dass es überhaupt read-only-Bereiche im virtuellen Speicher gibt, sind Sicherheit und z.B. die Möglichkeit, dass bei einem fork() der neu entstehende Prozess den alten Speicherbereich mit dem Code mitnutzen kann (mittels Copy-On-Write kann auch der restliche Speicher erstmal gemeinsam genutzt werden).
    Hab dazu etwas in Linux/Unix-Systemprogrammierung von Helmut Herold gefunden, das Buch habe ich aber jetzt nicht hier. Da sind Beispiele für Variablen angegeben, die im Data-Segment landen, und da war neben globalen Variablen auch ein char* zu finden.
    Ein gebrechlich Wesen ist der X-Server.

  11. #26
    Registrierter Benutzer Avatar von BLUESCREEN3D
    Registriert seit
    08.11.2002
    Beiträge
    665
    Ich habe in meinem Programm aus dem 1. Post einfach mal beide Strings durch unterschiedlichen Text ersetzt, das ganze ohne Optimierungen kompiliert und objdump -s a.out aufgerufen.
    Da sieht man dann, dass beide Strings in der Sektion .rodata landen. Also weder in .text noch in .data.

    Demnach müsste der Arrayinhalt beim Programmstart doch nochmal in einen anderen Speicherbereich kopiert werden, um schreibbar zu sein. Dazu habe ich ein Programm mit einem 1-MB-String einmal als char* und einmal als char[] gestartet und die char[]-Version braucht tatsächlich zur Laufzeit 1 MB mehr Speicher.

  12. #27
    Registrierter Benutzer Avatar von ContainerDriver
    Registriert seit
    10.01.2003
    Beiträge
    418
    Zitat Zitat von BLUESCREEN3D Beitrag anzeigen
    Demnach müsste der Arrayinhalt beim Programmstart doch nochmal in einen anderen Speicherbereich kopiert werden, um schreibbar zu sein. Dazu habe ich ein Programm mit einem 1-MB-String einmal als char* und einmal als char[] gestartet und die char[]-Version braucht tatsächlich zur Laufzeit 1 MB mehr Speicher.
    Genau, so ist es:
    seg.c:
    Code:
    #include <stdio.h>
    
    int main(void)
    {
        char*s1="Hallo Welt 1";   
        char s2[]="Hallo Welt 2"; 
    
        *s1='B';
        s2[0]='B';
    }
    objdump -s seg
    Code:
    Contents of section .rodata:
     8048458 03000000 01000200 48616c6c 6f205765  ........Hallo We
     8048468 6c742031 0048616c 6c6f2057 656c7420  lt 1.Hallo Welt 
     8048478 3200                                 2.
    Zu seg gehöriger Assemblercode:
    Code:
    (gdb) disassemble main
    Dump of assembler code for function main:
    0x08048344 <main+0>:	lea    ecx,[esp+0x4]
    0x08048348 <main+4>:	and    esp,0xfffffff0
    0x0804834b <main+7>:	push   DWORD PTR [ecx-0x4]
    0x0804834e <main+10>:	push   ebp
    0x0804834f <main+11>:	mov    ebp,esp
    0x08048351 <main+13>:	push   ecx
    0x08048352 <main+14>:	sub    esp,0x20
    0x08048355 <main+17>:	mov    DWORD PTR [ebp-0x8],0x8048460
    0x0804835c <main+24>:	mov    eax,ds:0x804846d
    0x08048361 <main+29>:	mov    DWORD PTR [ebp-0x15],eax
    0x08048364 <main+32>:	mov    eax,ds:0x8048471
    0x08048369 <main+37>:	mov    DWORD PTR [ebp-0x11],eax
    0x0804836c <main+40>:	mov    eax,ds:0x8048475
    0x08048371 <main+45>:	mov    DWORD PTR [ebp-0xd],eax
    0x08048374 <main+48>:	movzx  eax,BYTE PTR ds:0x8048479
    0x0804837b <main+55>:	mov    BYTE PTR [ebp-0x9],al
    0x0804837e <main+58>:	mov    eax,DWORD PTR [ebp-0x8]
    0x08048381 <main+61>:	mov    BYTE PTR [eax],0x42
    0x08048384 <main+64>:	mov    BYTE PTR [ebp-0x15],0x42
    0x08048388 <main+68>:	add    esp,0x20
    0x0804838b <main+71>:	pop    ecx
    0x0804838c <main+72>:	pop    ebp
    0x0804838d <main+73>:	lea    esp,[ecx-0x4]
    0x08048390 <main+76>:	ret    
    End of assembler dump.
    (gdb)
    .

    In 0x08048355 <main+17> wird die Speicheradresse von "Hallo Welt 1" (besser gesagt von "H") in .rodata auf dem Stack abgelegt. Dann wird von 0x0804835c <main+24> bis 0x08048371 <main+45> der Inhalt von 0x804846d bis 0x8048478 (= 12 Byte, "Hallo Welt 2" = 12 Byte) aus .rodata kopiert, bei 0x08048374 <main+48> bis 0x0804837b <main+55> kommt dann vermutlich das Nullbyte auf den Stack.
    Schließlich wird in 0x0804837e <main+58> die Speicheradresse des Hs von "Hallo Welt 1" in das A Register kopiert (diese Speicheradresse wurde ja vorher bei ebp-0x8 auf den Stack abgelegt). Bei 0x08048381 <main+61> kommt es dann zum Speicherzugriffsfehler, weil versucht wird, an die Speicheradresse, die in EAX steht, etwas zu schreiben.
    0x08048384 <main+64> geht, weil da nur der Stack verändert wird.

    Gruß, Florian
    Geändert von ContainerDriver (15-03-2008 um 13:03 Uhr)
    Ein gebrechlich Wesen ist der X-Server.

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •