ubuntuusers.de

Problem in C - Segmentation Fault (Core Dumped)

Status: Gelöst | Ubuntu-Version: Nicht spezifiziert
Antworten |

stetro

Avatar von stetro

Anmeldungsdatum:
14. Oktober 2006

Beiträge: Zähle...

Hallo,
Also ich wollte jetzt anfangen in C zu Programmieren..
hab auch schon ein paar kleinere Projekte erstellt (Toturial bezogen).

Jetzt zu meinem Problem:
Den folgenden Code kann ich ohne Probleme mit gcc compilieren jedoch kommt beim Ausführen die Nachricht Segmentation fault (core dumped)

#include <stdio.h>
#include <stdlib.h>

void error_msg(const char *acError)				//Bei einem Fehler
{
	printf("Ein Fehler ist aufgetreten : %s",acError);	//Infotext
	getchar();						//Tastendruch
	exit(1);						//Beenden
}

int main()							//Hauptfunktion
{
	char **acFeld;
	char **acShow;
	int iGroesse=12;
	int i,j;
	acFeld=(char**)malloc(iGroesse);
	acShow=(char**)malloc(iGroesse);
	if(acShow==NULL||acFeld==NULL)
		error_msg("Felder konnten nicht reserviert werden");
	for(i=0;i<iGroesse;i++)
	{
		acFeld[i]=(char*)malloc(iGroesse);
		acShow[i]=(char*)malloc(iGroesse);
		if(acShow[i]==NULL||acFeld[i]==NULL)
			error_msg("Felder konnten nicht reserviert werden");
	}
	for(i=0;i<iGroesse;i++)
		for(j=0;j<iGroesse;j++)
			acFeld[i][j]=' ';
	for(i=0;i<iGroesse;i++)
		for(j=0;j<iGroesse;j++)
			acShow[i][j]=' ';
	return EXIT_SUCCESS;					//Programm beenden
}

Vielleicht ist es ein ganz einfacher Fehler aber ich weiß einfach nicht woran es liegen könnte ..
Danke schonmal

Bearbeitet von Mr. Kanister:

Überschrift aussagekräftiger gemacht 😉

weau

Avatar von weau

Anmeldungsdatum:
22. Januar 2006

Beiträge: 99

Hallo. Du hast da ein Problem mit den Pointern, was dir Segmentation fault (core dumped) auch sagt.
Du deklarierst deine Pointer mit **, obwohl es nur ein * sein müsste.
Gewöhne dir bei der einen if-Anweisung direkt an vernümftig Klammern zusetzen.
Habs jetzt nur mal grob überfolgen.

stetro

(Themenstarter)
Avatar von stetro

Anmeldungsdatum:
14. Oktober 2006

Beiträge: 25

Ja das mit den klammern habe ich nur jetzt einmal gemacht da das problem in einem komplexerem Programm auftrat..
Ich benötige dafür aber 2 deminsionale Arrays.. deshalb auch die Doppelzeiger

Hello_World

Anmeldungsdatum:
13. Juni 2006

Beiträge: 3620

Oberflächlich betrachtet ist das Problem, dass Du zu wenig Speicher allokierst. Bei

acFeld=(char**)malloc(iGroesse);

allokierst 12 Byte Speicher, Du willst aber

iGroesse*sizeof(char*)

Bytes allokieren.

Das eigentliche Problem ist aber, dass Du überhaupt dynamisch Speicher allokierst. Wenn zur Compilezeit bekannt ist, wie viel Speicher man zur Laufzeit braucht, dann ist es in jeder Hinsicht klüger, statisch allokierten Speicher, also ganz normale Arrays, zu verwenden:

char acFeld[12][12]


Allein dass Du es versäumst, den allokierten Speicher wieder freizugeben, spricht für diese Vorgehensweise. Außerdem besteht bei einer Allokation nach dem Schema malloc(bla*sizeof(blub)) immer das Risiko eines Integer-Überlaufs und daraus resultierenden Sicherheitslücken. Lern doch lieber eine vernünftige Sprache und nicht so einen veralteten Mist wie C...

Darkcloud

Anmeldungsdatum:
10. Juni 2007

Beiträge: 69

Ich hab im Beispiel jetzt mal nur "acFeld" benutzt:

#include <stdio.h>
#include <stdlib.h>

void error_msg( const char* acError)
{
        printf( "Ein Fehler ist aufgetreten : %s\n", acError );
}

int main( int argc, char** argv )
{
        char** acFeld;
        int i, j, iGroesse = 12;

        /* iGroesse x Zeiger auf char* reservieren */
        acFeld = (char**)malloc( iGroesse * sizeof(char*) );
        if ( acFeld == NULL ) {
                error_msg( "Felder konnten nicht reserviert werden" );
                return EXIT_FAILURE;
        }
        for ( i = 0; i < iGroesse; i++ ) {
                acFeld[i] = (char*)malloc( iGroesse );
                if ( acFeld[i] == NULL ) {
                        error_msg( "Felder konnten nicht reserviert werden" );
                        /* clean up - bis hierher gings gut, deshalb vorheriges freigeben */
                        for ( j = 0; j < i; j++ ) {
                                free( acFeld[i] );
                        }
                        free( acFeld );
                        return EXIT_FAILURE;
                }
        }
        for ( i = 0; i < iGroesse; i++ ) {
                for ( j = 0; j < iGroesse; j++ ) {
                        acFeld[i][j] = (char)( i + 65 );
                        /* Beispielausgabe: */
                        printf( "%c", acFeld[i][j] );
                }
                printf( "\n" );
        }
        /* clean-up */
        for ( i = 0; i < iGroesse; i++ ) {
                free( acFeld[i] );
        }
        free( acFeld );

        return EXIT_SUCCESS;
} 

Was Hello World schreibt wegen der Speichergröße, die du anforderst ist richtig. Deshalb:

acFeld = (char**)malloc( iGroesse * sizeof(char*) );

Und freigeben solltest du den Speicher natürlich auch wieder!

Wenn zur Compilezeit bekannt ist, wie viel Speicher man zur Laufzeit braucht, dann ist es in jeder Hinsicht klüger, statisch allokierten Speicher, also ganz normale Arrays, zu verwenden

Naja, es ist ja ein Beispiel in dem es wohl um dynamische Speicherverwaltung geht.

pot24.com

Anmeldungsdatum:
5. Mai 2008

Beiträge: Zähle...

Du greifst auf ein 2-dimensionales Feld zu, allokierst aber zur ein eindimansionales.

D.h., du hast nur einen Vektor mit iGroesse Elementen, greifst aber auf ein Feld mit n*n Elementen zu.

Dort wo dein Array-Element sein soll, ist schon etwas ganz anderes, z.B. ein anderes Programm - oder noch schlimmer: Ein anderes Feld des selben Programmes, was keinen Absturz hervorruft, aber "sonderbare" Ergebnisse.

Ich habe die Erfahrung gemacht, dass es ohnehin viel leistungsfähiger ist, einen eindimensionalen Vektor mit n*n Elementen anzulegen und auf den z.B. mit vector[i * n + j] anstattvector[j] zuzugreifen. Der ist einfacher anzulegen und auch wieder freizugeben. Gruß Wolfgang

Darkcloud

Anmeldungsdatum:
10. Juni 2007

Beiträge: 69

Bei mir hat sich übrigens auch ein Fehler eingeschlichen (naja, schon spät):

/* clean up - bis hierher gings gut, deshalb vorheriges freigeben */
for ( j = 0; j < i; j++ ) {
        free( acFeld[j] ); /* Natürlich muss "j" anstatt "i" benutzt werden! */
}
free( acFeld );
return EXIT_FAILURE;


Deshalb mag ich i und j nicht... 😉

lilith2k3

Avatar von lilith2k3

Anmeldungsdatum:
14. Dezember 2006

Beiträge: 2999

Wohnort: OS

@Darkcloud

int i, j, iGroesse = 12;

Wäre es nicht sinnvoller, da die Variable im ganzen Programm nur einen einzigen Zweck verfolgt (es also im Grunde eine Konstante ist), die Variable mit

#define MAXSIZE 12


festzulegen?

acFeld = (char*)malloc( iGroesse );[/quote]
Sollte nicht auch hier mit sizeof() gearbeitet werden?

acFeld[j] = (char)( i + 65 );[/quote]
Passenderweise evtl.
{{{acFeld[i] = (char*)malloc(iGroesse * sizeof(char))}}}

for ( i = 0; i < iGroesse; i++ ) {
free( acFeld );
return EXIT_SUCCESS;
} [/quote]

for ( j = 0; j < i; j++ ) {
free( acFeld[j] ); /* Natürlich muss "j" anstatt "i" benutzt werden! */
}
free( acFeld );
return EXIT_FAILURE;

Wieso die Korrektur? 😲
Was denn nun? SUCCESS oder FAILURE? 😀 @Hello World

Lern doch lieber eine vernünftige Sprache und nicht so einen veralteten Mist wie C...

Danach hat kein Mensch gefragt!

BadBoy

Avatar von BadBoy

Anmeldungsdatum:
25. Oktober 2007

Beiträge: 479

lilith2k3 hat geschrieben:

Wäre es nicht sinnvoller, da die Variable im ganzen Programm nur einen einzigen Zweck verfolgt (es also im Grunde eine Konstante ist), die Variable mit

#define MAXSIZE 12


festzulegen?[...]

na dann lieber ne const-Variable

Darkcloud

Anmeldungsdatum:
10. Juni 2007

Beiträge: 69

lilith2k3 hat geschrieben:

int i, j, iGroesse = 12;

Wäre es nicht sinnvoller, da die Variable im ganzen Programm nur einen einzigen Zweck verfolgt (es also im Grunde eine Konstante ist), die Variable mit

#define MAXSIZE 12

festzulegen?

Darum geht es hier doch gar nicht.
Aber um die dynamische Natur nochmal zu verdeutlichen:

int main( int argc, char** argv )
{
	char** acFeld;
	int i, j, iGroesse;

	if ( argc > 1 ) {
            iGroesse = atoi( argv[1] );
        } else {
            iGroesse = 12;
        }
        /* Evtl. Fehler abfangen (ich machs hier mal einfach) */
        if ( iGroesse < 1 || iGroesse > 26 ) {
            iGroesse = 12;
        }
    } else {
        iGroesse = 12;
    }
.....

lilith2k3 hat geschrieben:

acFeld = (char*)malloc( iGroesse );[/quote]
Sollte nicht auch hier mit sizeof() gearbeitet werden?

acFeld[j] = (char)( i + 65 );[/quote]
Passenderweise evtl.{{{acFeld[i] = (char*)malloc(iGroesse * sizeof(char))}}}[/quote]Nein, da hier kein Speicher angefordert wird, sondern das Zeichen 'A'+i zugewiesen wird - kompilier das Ding, dann wird's vlt. klarer. lilith2k3 hat geschrieben:

Wieso die Korrektur? 😲

Weil der bisher erfolgreich angeforderte Speicher aufgeäumt werden muss. Bis zu (i - 1) ging ja alles gut (äussere Schleife), deswegen eben

for ( j = 0; j < i; j++ ) {
    free( acFeld[j] );
} 


lilith2k3 hat geschrieben:

Was denn nun? SUCCESS oder FAILURE? 😀

In dem Fall FAILURE. Schliesslich bekam man nicht den kompletten, angeforderten Speicher. Das ganze ist nun doch etwas größer geworden, deshalb: http://ubuntuusers.de/paste/213092/''

Hello_World

Anmeldungsdatum:
13. Juni 2006

Beiträge: 3620

lilith2k3 hat geschrieben:

@Darkcloud
Wäre es nicht sinnvoller, da die Variable im ganzen Programm nur einen einzigen Zweck verfolgt (es also im Grunde eine Konstante ist), die Variable mit

#define MAXSIZE 12


festzulegen?

Nein, das ist es nicht. Es gibt keinen vernünftigen Grund, den Präprozessor zum definieren von Konstanten zu verwenden, denn dafür gibt es das Schlüsselwort const. Also const size_t groesse = 12; oder so.
lilith2k3 hat geschrieben:

acFeld = (char*)malloc( iGroesse );[/quote]
Sollte nicht auch hier mit sizeof() gearbeitet werden?[/quote]
Nein. sizeof(char) liefert per Definition 1, daher kann man das weglassen.
lilith2k3 hat geschrieben:

Lern doch lieber eine vernünftige Sprache und nicht so einen veralteten Mist wie C...

Danach hat kein Mensch gefragt!

Das ist mir völlig egal. Ich werde auch in Zukunft versuchen, möglichst viele Leute von der Krankheit namens "C" wegzubringen.

stetro

(Themenstarter)
Avatar von stetro

Anmeldungsdatum:
14. Oktober 2006

Beiträge: 25

Guten Morgen allerseits..

Danke erst mal für die vielen Antworten !! Mein Problem hat sich dann auch damit gelöst..
Den Speicher hab ich deshalb nicht freigestellt da dies ja wie gesagt nur ein schnell abgetippter Auszug aus nem anderen Projekt war..

So .. und die Feldgröße wollte ich wie Darkcloud nett gezeigt hat vom Benutzer abfragen..
Deshalb wollt ich auch keine konstante nehmen (#define) ..

Jetzt bleibt natürlich noch eine Frage offen..
Was schlägst du Hello World denn als andere Sprache vor, mit der man ('relativ') Speichergering Programmieren kann?
Noch kann ich ja noc umsteigen xD ..

Danke nochmals ..

Gruß

lilith2k3

Avatar von lilith2k3

Anmeldungsdatum:
14. Dezember 2006

Beiträge: 2999

Wohnort: OS

@Hello World

Es gibt keinen vernünftigen Grund, den Präprozessor zum definieren von Konstanten zu verwenden

Wie wäre es mit dem Argument: Übersichtlichkeit?

Nein. sizeof(char) liefert per Definition 1, daher kann man das weglassen.


Inhaltlich hast du recht!
Aber ich finde es dann lesbarer :]

Ich werde auch in Zukunft versuchen, möglichst viele Leute von der Krankheit namens "C" wegzubringen.

Naja, das hilft dem Fragesteller aber nicht viel; vorallem dann nicht, wenn er es nicht "freiwillig" lernt *g*

@BadBoy

na dann lieber ne const-Variable

Warum, es handelt sich doch nur um eine Symbolische Konstante?

@Darkcloud
ah, hab mich im Block vertan. Ich hatte gedacht, Du hättest das letzte cleanup verändert *tsts*
Da nehm ich alles zurück 😉

Nein, da hier kein Speicher angefordert wird, sondern das Zeichen 'A'+i zugewiesen wird - kompilier das Ding, dann wird's vlt. klarer.

Nee, das haut schon so hin (12 Byte reserviert, da passen auch 12 char rein). Das is mir soweit auch klar. (cf. Hello World's Einwand und meine Begründung).

@stetro

Was schlägst du Hello World denn als andere Sprache vor, mit der man ('relativ') Speichergering Programmieren kann?

Warum speicherschonend?

Edit: http://ubuntuusers.de/paste/213092/
Huch, da gibt's ja sogar 'n define *gg*

stetro

(Themenstarter)
Avatar von stetro

Anmeldungsdatum:
14. Oktober 2006

Beiträge: 25

Hab ich mal so gehört \^^..

Also wir lernen C in der Schule jedoch Das was ich mache ist eigendlich unabhänig davon..
Wenns da nämlich was besseres unter linux gibt würd ich das nämlich auch einmal austesten..

audax

Avatar von audax

Anmeldungsdatum:
15. September 2006

Beiträge: 1253

Warum denn eigentlich so arg speicherschonend?

Antworten |