C & Zeiger: Speicherzugriffsfehler

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
Prickelpit
Beiträge: 89
Registriert: 29.07.2003 17:22:04
Wohnort: Dreiländereck

C & Zeiger: Speicherzugriffsfehler

Beitrag von Prickelpit » 13.12.2003 01:43:24

Hi!

Ich versuche gerade ein 2d-Array zu bauen, das während der Laufzeit mit dynamischer Grösse erzeugt wird. Dazu alloziere ich mir mit Hilfe des Zeigers "pointer" einen Speicherblock, den ich mir so zurechtbiege, dass ich mit pointer[x][y] auf die einzelnen Elemente des Arrays zugreifen kann.

Das klappt auch, allerdings nur für relativ kleine Werte für DIM_X bzw. DIM_Y.

Bei DIM_X = 50 und DIM_Y = 1000 schmiert das Programm ab, wenn auf pointer[13, 0] zugegriffen wird:

Code: Alles auswählen

 (12,995) <- 12995
 (12,996) <- 12996
 (12,997) <- 12997
 (12,998) <- 12998
 (12,999) <- 12999
Speicherzugriffsfehler
Scheinbar alloziere ich zu wenig Speicher, aber das kann ich nicht nachvollziehn.

Code: Alles auswählen

#include <stdio.h>

int main () {

    const int DIM_X = 50;    /* 1te Dimension des Arrays */
    const int DIM_Y = 1000;  /* 2te Dimension des Arrays */
    
    int i, j, **pointer;

    /* Speicher allozieren */

    pointer = (int**) malloc (DIM_X * sizeof (int*) + DIM_X * DIM_Y * sizeof (int));


    /* Speicherblock in ein 2d-Array "zurechtbiegen" */

    for (i = 0; i < DIM_X; i++)
        pointer[i] = (int*) (pointer + DIM_X * sizeof (int*) + i * DIM_Y * sizeof (int));
    

    /* Array mit Werten füllen */

    for (i = 0; i < DIM_X; i++)
        for (j = 0; j < DIM_Y; j++) {
	    pointer[i][j] = (i * DIM_Y) + j;
	    printf (" (%i,%i) <- %i\n" , i, j, pointer[i][j]);
	}
	    

    /* Array durchlaufen und Werte ausgeben */

    for (i = 0; i < DIM_X; i++)
        for (j = 0; j < DIM_Y; j++)
	    printf (" (%i,%i) -> %i\n" , i, j, pointer[i][j]);

	    
    /* Speicher freigeben */

    free (pointer);	    

    return 0;	
}
Wahrscheinlich ist das ein dummer Fehler, aber ich sehe den einfach nicht. Bin zeigermässig etwas aus der Übung. Danke schonmal für eure Hilfe!

Gruß
Pit
"Wenn Sie den Sturz einer größeren Regierung planen, dann halten Sie sich an die erprobten Algorithmen am Ende des Buchs"
(Bruce Schneider)

Benutzeravatar
spiffi
Beiträge: 1128
Registriert: 09.08.2003 19:02:27

Beitrag von spiffi » 13.12.2003 02:03:16

Hier ist der Fehler:

Code: Alles auswählen

    /* Speicherblock in ein 2d-Array "zurechtbiegen" */

    for (i = 0; i < DIM_X; i++)
        /* pointer[i] = (int*) (pointer + DIM_X * sizeof (int*) + i * DIM_Y * sizeof (int));  */
        pointer[i] = (int*) (pointer + DIM_X * sizeof (int*) + i * sizeof (int));
Es muß nicht i * DIM_Y * sizeof(int) heißen, sondern i * sizeof(int). Sonst platzierst die pointer Arrays alle hinter den allokierten Bereich.

Benutzeravatar
Prickelpit
Beiträge: 89
Registriert: 29.07.2003 17:22:04
Wohnort: Dreiländereck

Ich wer' noch bekloppt..

Beitrag von Prickelpit » 13.12.2003 09:04:14

Hi!

Danke für die schnelle Antwort. Mit deiner Änderung funktioniert es in allen Fällen. Der Programmfehler ist also behoben, nicht aber mein Denkfehler.

Angenommen, DIM_X = 2, DIM_Y = 5 beliebig, dann sieht der allokierte Speicherbereich ja wie folgt aus:

Code: Alles auswählen

pointer -> [int*a|int*b|0a|1a|2a|3a|4a|0b|1b|2b|3b|4b]
Jetzt hab ich in der alten Version int*a auf 0a umgebogen, und int*b auf 0b.

Code: Alles auswählen

[int*a|int*b|0a|1a|2a|3a|4a|0b|1b|2b|3b|4b]
   |---------^
         |------------------^
Deine Version biegt jetzt int*a auf 0a und int*b auf 1a?

Code: Alles auswählen

[int*a|int*b|0a|1a|2a|3a|4a|0b|1b|2b|3b|4b]
   |---------^
         |------^


Dann ist in deiner Version meiner Überlegung nach pointer[0][1] = pointer[1][0] = 1a. Dass das aber nicht wirklich der Fall ist, sehe ich an der Ausgabe vom Programm.

Wenn du nach dem Programmfehler meinen Denkfehler jetzt auch noch fixen kannst, bin ich wunschlos glücklich 8)

Gruß
Pit
"Wenn Sie den Sturz einer größeren Regierung planen, dann halten Sie sich an die erprobten Algorithmen am Ende des Buchs"
(Bruce Schneider)

Olaf Dietsche
Beiträge: 520
Registriert: 12.06.2003 23:18:50
Wohnort: Siegburg

Re: C & Zeiger: Speicherzugriffsfehler

Beitrag von Olaf Dietsche » 13.12.2003 09:34:16

Prickelpit hat geschrieben:[Speicherzugriffsfehler]

Scheinbar alloziere ich zu wenig Speicher, aber das kann ich nicht nachvollziehn.
Die Pointerarithmethik sagt

Code: Alles auswählen

pointer[1] == pointer + 1 == (char *) pointer + sizeof(int*)
Deshalb mußt du deinen Code so ändern

Code: Alles auswählen

    /* Speicherblock in ein 2d-Array "zurechtbiegen" */

    for (i = 0; i < DIM_X; i++)
-        pointer[i] = (int*) (pointer + DIM_X * sizeof (int*) + i * DIM_Y * sizeof (int));
+        pointer[i] = (int*) ((char *) pointer + DIM_X * sizeof (int*) + i * DIM_Y * sizeof (int));
    

    /* Array mit Werten füllen */
Noch besser wäre es jedoch wenn du diese zwei Dinge nicht vermischen würdest und einen Speicherbereich für die erste Dimension und einen für die zweite Dimension anfordern würdest

Code: Alles auswählen

	int **p1, *p2;
	p1 = (int **) malloc(DIM_X * sizeof(int *));
	p2 = (int *) malloc(DIM_Y * sizeof(int));
	for (i = 0; i < DIM_X; ++i)
		p1[i] = &p2[i * DIM_Y];

Benutzeravatar
spiffi
Beiträge: 1128
Registriert: 09.08.2003 19:02:27

Beitrag von spiffi » 13.12.2003 15:25:50

*Graaah*
Olaf hat natürlich Recht und ich hab Dummfug geredet. Ich sollte mich demnächst hüten Nachts um Zwei Fragen zu Pointerarithmetik zu beantworten. :oops:

Benutzeravatar
Prickelpit
Beiträge: 89
Registriert: 29.07.2003 17:22:04
Wohnort: Dreiländereck

Ah, jetzt, ja.

Beitrag von Prickelpit » 14.12.2003 09:02:10

Supi, danke nochmals für die Hilfe.

Gruß
Pit
"Wenn Sie den Sturz einer größeren Regierung planen, dann halten Sie sich an die erprobten Algorithmen am Ende des Buchs"
(Bruce Schneider)

Antworten