[C] Segmentation fault beim Einlesen, Verarbeiten und Schreiben einer Tabelle.

Kashrlyyk

Grünschnabel
Ich muß ein Programm schreiben, mit dem ich eine dreispaltige Tabelle mit 100000 Zeilen einlesen kann. Ich habe mir dann gedacht die Spalten in verschiedenen eindimensionalen Array zu speichern.
Dann werden die Daten in 3 if-Bedingungen benutzt, um die Daten in kleinere Würfel aufzuteilen. In der if-Bedingung wird dann eine Summe berechnet, das Ergebnis kommt dann in ein dreidimensionales Array.

Beim Ausführen des Programmes kommt es aber zu einem "Segmentation Fault". Ich bin ziemlich neu was C Programmierung angeht. Das Betriebsystem ist Linux.

Code:
#include <stdio.h>

int main()
{
    int j, npart, i, lon,lat,rad,k,hl,hb;
    float pos[3],mass, r[100000],l[100000],b[100000],summe[301][361][181];
    char line[40];
    FILE *Datei, *Quelle;
    mass=0.0449866;
    npart=100000;  
  
 
/* Einlesen */
 
Quelle = fopen("plum094rlb","r");
  
 for (j=0;j<npart;j++)
{	fgets(line,40,Quelle);
	sscanf(line,"%f %f %f", pos[0], pos[1], pos[2]);
	r[j] = pos[0];
	l[j] = pos[1];
	b[j] = pos[2];
}

fclose(Quelle);
  
/* Verarbeiten */ 
 
for (lon = -180; lon< 175; lon +=5)
{
   for (lat = -90; lat< 85; lat +=5)
   {
	   for (rad = 0; rad<295; rad +=5)
		{
		for (i= 0;i< npart; i++)
     		 {
		    if (l[i]<lon+5 || l[i]>= lon) 
			    {if (b[i]<lat+5 || b[i]>= lat)
			        {if (r[i]<rad+5 || r[i]>=rad)
			            {hl=lon+180;
			             hb=lat+90;
			             summe[rad][hl][hb]+=mass/((rad+2.5)*(rad+2.5));
							 /* Schreiben */						      
					       if (Datei == NULL)
                      printf("\n\nDatei nicht erzeugt/geoeffnet!\n");
                      else			        
			             fprintf(Datei,"%f %f %f %f \n",rad,lon,lat,summe[rad][hl][hb]);
			             }
			        }    
			    }
		    }		
		}

   }

}

fclose(Datei);


    return 0;

}
 
Also wenn ich jetzt nicht allzu blind bin, hast du einfach ein
Code:
Datei = fopen(...);
vergessen. Oder ich hab's einfach nur übersehen, würd mich grad auch nicht wundern^^
 
Habe ich eingefügt. Es gibt trotzdem einen Segmentation Fault.
Weißt du an welcher Stelle?

//EDIT: Hab's grad eingrenzen können. Er hapert an der Stelle
Code:
float pos[3],mass, r[100000],l[100000],b[100000],summe[301][361][181];
Irgendetwas hat er gegen die Schreibweise "float summe[301][361][181];"
 
Zuletzt bearbeitet:
Weißt du an welcher Stelle?

//EDIT: Hab's grad eingrenzen können. Er hapert an der Stelle
Code:
float pos[3],mass, r[100000],l[100000],b[100000],summe[301][361][181];
Irgendetwas hat er gegen die Schreibweise "float summe[301][361][181];"

Aber es sollte ein legitimer Ausdruck sein. Vllt. brauche ich eine weitere Header-Datei dafür?
 
Hi.

Das Problem ist das du die Arrays auf dem Stack anlegst. Die Stackgröße ist bei jedem Betriebssystem begrenzt. Unter Linux ist die Standardstackgröße 8172KB.

Ein float ist normalerweise 4 Byte groß, du versuchst 3 eindimensionale Arrays anzulegen die 100,000 Elemente haben. Macht 4 * 3 * 100,000 = ca. 1171 KB.

Für das 3 dimensionale Array: 4 * 301 * 361 * 181 = ca. 75 MB. Das ist viel zu groß.

Du solltest deine Arrays auf dem Heap - also dynamische Speicherallozierung mit malloc bzw. calloc - anlegen. Und dann mit free wieder freigeben.

Gruß
 
Zuletzt bearbeitet:
Segmentation fault beim Einlesen, Verarbeiten und Schreiben einer Tabelle.

Ich habe das Programm jetzt abgeändert, da es in der alten Form unnötig war. Das neue Programm erzeugt aber denselben Fehler. Ich bin in der c-shell um das Programm zu kompilieren und zu benutzen, hat das vllt. damit was zu tun?


Code:
/* 
 * Intensitaet addieren
 *	2007 
 *                      
 */

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



int main()
{

    int j, npart, i,k;
    int pos[3];
    float *intensitaet,sum[360][16],*l,*b;    
    char line[100];
    npart=71568;  
    FILE *Datei,*Quelle;

intensitaet=(float *) malloc(npart*sizeof(float));
l=(float *) malloc(npart*sizeof(float));
b=(float *) malloc(npart*sizeof(float));
/* Einlesen */

Quelle = fopen("ccdtdall.txt","r");
Datei  = fopen("versuchtest","w");
  
 for (j=0;j<npart;j++)
{	fgets(line,40,Quelle);
	sscanf(line,"%d %d %f", pos[0], pos[1], pos[2]);
	l[j] = pos[0];
	b[j] = pos[1];
	intensitaet[j] = pos[2];
 }   
  
/* Verarbeiten */ 
 
for (j = 0; j< 360; j++)
{
   for (i = 0; i< 180; i++)
   {
	   if (b[i]<=30 || b[i]>= 0) 
			    {sum[j][15]+=intensitaet[i];}
		if (b[i]<=50 || b[i]>= 30) 
			    {sum[j][14]+=intensitaet[i];}    		
		if (b[i]<=60 || b[i]>= 50) 
			    {sum[j][13]+=intensitaet[i];}
		if (b[i]<=70 || b[i]>= 60) 
			    {sum[j][12]+=intensitaet[i];}	    
      if (b[i]<=75 || b[i]>= 70) 
			    {sum[j][11]+=intensitaet[i];}
      if (b[i]<=80 || b[i]>= 75) 
			    {sum[j][10]+=intensitaet[i];} 
		if (b[i]<=85 || b[i]>= 80) 
			    {sum[j][9]+=intensitaet[i];}      
      if (b[i]<=90 || b[i]>= 85) 
			    {sum[j][8]+=intensitaet[i];}
      if (b[i]<=95 || b[i]>= 90) 
			    {sum[j][7]+=intensitaet[i];}
      if (b[i]<=100 || b[i]>= 95) 
			    {sum[j][6]+=intensitaet[i];}
      if (b[i]<=105 || b[i]>= 100) 
			    {sum[j][5]+=intensitaet[i];}			    
		if (b[i]<=110 || b[i]>= 105) 
			    {sum[j][4]+=intensitaet[i];}	    
      if (b[i]<=120 || b[i]>= 110) 
			    {sum[j][3]+=intensitaet[i];}
  		if (b[i]<=130 || b[i]>= 120) 
			    {sum[j][2]+=intensitaet[i];}		
		if (b[i]<=150 || b[i]>= 130) 
			    {sum[j][1]+=intensitaet[i];}	    
		if (b[i]<=180 || b[i]>= 150) 
			    {sum[j][0]+=intensitaet[i];}
			    for(k=0;k<16;k++)
		fprintf(Datei,"%d %d %f \n",(j-180),k,sum[j][k]);	        
   }

}return 0; 
}
 
Hi.

Erstmal solltest du immer prüfen, ob das Öffnen der Dateien und die Ein-/Ausgabe in die Dateien geklappt hat. Sonst erhälst du tatsächlich einen SegFault.

Außerdem kannst du ganz einfach einen Debugger verwenden (z.B. DDD) um das Programm schrittweise auszuführen und herauszufinden wo der Fehler auftritt.

C:
if ((Quelle = fopen("ccdtdall.txt","r")) == NULL) {
  /* Fehler: Datei konnte nicht geöffnet werden */
  return 1;
}

/* ... für das Ziel genauso. */

for (j = 0; j < npart && fgets(line, 40, Quelle) != NULL; ++j) {
  ...
}

Übrigens, der || Operator ist der boolsche OR-Operator. Der wird zu true ausgewertet wenn einer der beiden Operanden true ist.

Wenn du schreibst
C:
(b[i]<=30 || b[i]>= 0)
kann dieser Ausdruck nicht falsch werden, denn
Code:
b[i]
ist entweder größer gleich 0 oder kleiner gleich 30 oder sogar beides. Du wolltest ja evtl. eher
C:
(b[i] <= 30 && b[i] >= 0)
schreiben?! Das gleiche gilt natürlich auch für die anderen Abfragen.

Gruß
 
Hi.

Erstmal solltest du immer prüfen, ob das Öffnen der Dateien und die Ein-/Ausgabe in die Dateien geklappt hat. Sonst erhälst du tatsächlich einen SegFault.

Außerdem kannst du ganz einfach einen Debugger verwenden (z.B. DDD) um das Programm schrittweise auszuführen und herauszufinden wo der Fehler auftritt.

C:
if ((Quelle = fopen("ccdtdall.txt","r")) == NULL) {
  /* Fehler: Datei konnte nicht geöffnet werden */
  return 1;
}

/* ... für das Ziel genauso. */

for (j = 0; j < npart && fgets(line, 40, Quelle) != NULL; ++j) {
  ...
}



Gruß

Wenn ich den Code neukompoliert habe, reicht dann ein "rehash" um die neue Version zu benutzen?

Ich habe die Abfrage, ob die Dateien geöffnet wurden eingebaut. Wenn ich das Programm dann in einem Ordner öffne, der die Datei nicht enthält, kommt der Fehler. Aber im Ordner in dem die Datei ist, kommt immer noch nur ein Segmentation Fault.

Vielen Dank für die Informationen über || und &&.

DDD gibt folgenden Fehler:
Program received signal SIGSEGV, Segmentation fault.
0xb7e18870 in _IO_vfscanf () from /lib/tls/libc.so.6

D.h. in der Zeile ist was faul?

Code:
 for (j=0;j<npart;j++)
{	fgets(line,100,Quelle);
	sscanf(line,"%f %f %f \n", pos[0], pos[1], pos[2]);
	glon[j] = pos[0];
	glat[j] = pos[1];
	intensitaet[j] = pos[2];
 }

pos[3] von int zu float ändern hat nichts gebracht.
 
Zurück