Forum: PC-Programmierung C Speicherzugriffsfehler


von M. M. (karlkappe)


Lesenswert?

Hallo,
ich habe ein kleines Problem mit folgendem Code:
1
int main(int n, char *params[])
2
{
3
if (!(n==2))
4
{   printf("ERROR.  Usage ./array input_file\n");
5
}
6
else
7
{
8
FILE *fi = fopen(params[1],"rb+");
9
10
if(!fi) printf("not opened");
11
12
13
int xdim=getparameter(fi, "Grid dim=\"");
14
int ydim=getparameter(fi, " x ");
15
int numparam=getparameter(fi, "Parameters (4 byte)=");
16
int expsize=getparameter(fi, "Experiment size (bytes)=");
17
int points=getparameter(fi, "Points=");
18
fpos_t fpos=getstreampos(fi, ":HEADER_END:");
19
int numofexp=expsize/4/points;
20
unsigned char b[4*numparam+expsize];
21
unsigned char a[4*numparam+expsize];
22
fsetpos (fi, &fpos);
23
fseek (fi,2,SEEK_CUR);
24
fgetpos(fi, &fpos);
25
fseek (fi, 0, SEEK_END);
26
long size=ftell(fi);
27
fsetpos (fi, &fpos);
28
float biasdiff;
29
float bias[points-1];
30
float *out = (float *)a;
31
int end;
32
int i;
33
int j;
34
int k;
35
36
float ****value = (float ****)malloc(xdim * sizeof(float ***));
37
  for(i = 0; i < xdim; i++) {
38
    value[i] = (float ***)malloc(ydim * sizeof(float **));
39
    for(j = 0; j < ydim; j++){
40
      value[i][j] = (float **)malloc(numparam * sizeof(float *));
41
      for(k = 0; k < numparam; k++)
42
        value[i][j][k] = (float *)malloc(points+numparam * sizeof(float ));
43
      }
44
  }
45
46
fread(b,4,2,fi);
47
for (j=0;j<=7;j=j+4) {
48
49
for (i = 0; i < 4; i++) {
50
                a[i+j] = b[3-i+j];
51
         }
52
}
53
54
biasdiff=(out[1]>out[0])? (out[1]-out[0]): (out[0]-out[1]);
55
56
if (out[1]>out[0]){
57
for (i=0;i<points;i++){
58
bias[i]=out[0]+i*biasdiff/(points-1);
59
}
60
}
61
else{
62
for (i=0;i<points;i++){
63
bias[i]=out[1]+i*biasdiff/(points-1);
64
}
65
}
66
67
68
fsetpos (fi, &fpos);
69
70
int n=1;
71
int x=1; 
72
int y=1;
73
74
do {
75
do {
76
  do {
77
    
78
      fsetpos (fi, &fpos);    
79
      fread(b,4,points,fi);
80
      fgetpos(fi, &fpos);
81
      end=ftell(fi);
82
      for (j=0; j<=(expsize/numofexp+4*numparam);j=j+4)
83
      {
84
      for (i = 0; i < 4; i++) {
85
                a[i+j] = b[3-i+j];
86
         }
87
      }
88
      for (k=1; k<(points+numparam); k++){
89
      value[x][y][n][k]=out[k];
90
      }
91
      
92
    
93
  n++;} while (n<=numofexp&&end<size);n=1;
94
x++;} while (x<=xdim&&end<size);x=1;
95
y++;} while (y<=ydim&&end<size);
96
97
printf("Value is %e\n", value[1][1][1][1]);
98
99
100
fclose(fi);
101
return 0;
102
103
}
104
}
Compilieren tut er Problemlos aber sobald ich es dann ausführe gibt es 
einen Speicherzugriffsfehler. Hat jemand eine Idee warum?
Wenn ich den Code ein wenig ändere und die Werte nicht in ein Array 
schreibe sondern in ein paar hundert Dateien klappt alles prima. Ich 
will aber mit den Werte noch rechnen alse wäre ein Array ziemlich 
wichtig für mich. Achja und es wäre nett wenn wir noch jmd. sagen könnte 
wie ich den Speicher hinterher wieder ordentlich frei mache.
Vielen Dank für eure Hilfe.

von rups (Gast)


Lesenswert?

Ganz wichtig: Formatier deinen Code vernünftig!!!
1
int main(int n, char *params[])
2
{
3
    if (!(n==2))
4
    {
5
        printf("ERROR.  Usage ./array input_file\n");
6
    }
7
    else
8
    {
9
        FILE *fi = fopen(params[1],"rb+");
10
11
        if (!fi) printf("not opened");
12
13
14
        int xdim=getparameter(fi, "Grid dim=\"");
15
        int ydim=getparameter(fi, " x ");
16
        int numparam=getparameter(fi, "Parameters (4 byte)=");
17
        int expsize=getparameter(fi, "Experiment size (bytes)=");
18
        int points=getparameter(fi, "Points=");
19
        fpos_t fpos=getstreampos(fi, ":HEADER_END:");
20
        int numofexp=expsize/4/points;
21
        unsigned char b[4*numparam+expsize];
22
        unsigned char a[4*numparam+expsize];
23
        fsetpos (fi, &fpos);
24
        fseek (fi,2,SEEK_CUR);
25
        fgetpos(fi, &fpos);
26
        fseek (fi, 0, SEEK_END);
27
        long size=ftell(fi);
28
        fsetpos (fi, &fpos);
29
        float biasdiff;
30
        float bias[points-1];
31
        float *out = (float *)a;
32
        int end;
33
        int i;
34
        int j;
35
        int k;
36
37
        float ****value = (float ****)malloc(xdim * sizeof(float ***));
38
        for (i = 0; i < xdim; i++)
39
        {
40
            value[i] = (float ***)malloc(ydim * sizeof(float **));
41
            for (j = 0; j < ydim; j++)
42
            {
43
                value[i][j] = (float **)malloc(numparam * sizeof(float *));
44
                for (k = 0; k < numparam; k++)
45
                    value[i][j][k] = (float *)malloc(points+numparam * sizeof(float ));
46
            }
47
        }
48
49
        fread(b,4,2,fi);
50
        for (j=0;j<=7;j=j+4)
51
        {
52
53
            for (i = 0; i < 4; i++)
54
            {
55
                a[i+j] = b[3-i+j];
56
            }
57
        }
58
59
        biasdiff=(out[1]>out[0])? (out[1]-out[0]): (out[0]-out[1]);
60
61
        if (out[1]>out[0])
62
        {
63
            for (i=0;i<points;i++)
64
            {
65
                bias[i]=out[0]+i*biasdiff/(points-1);
66
            }
67
        }
68
        else
69
        {
70
            for (i=0;i<points;i++)
71
            {
72
                bias[i]=out[1]+i*biasdiff/(points-1);
73
            }
74
        }
75
76
77
        fsetpos (fi, &fpos);
78
79
        int n=1;
80
        int x=1;
81
        int y=1;
82
83
        do
84
        {
85
            do
86
            {
87
                do
88
                {
89
90
                    fsetpos (fi, &fpos);
91
                    fread(b,4,points,fi);
92
                    fgetpos(fi, &fpos);
93
                    end=ftell(fi);
94
                    for (j=0; j<=(expsize/numofexp+4*numparam);j=j+4)
95
                    {
96
                        for (i = 0; i < 4; i++)
97
                        {
98
                            a[i+j] = b[3-i+j];
99
                        }
100
                    }
101
                    for (k=1; k<(points+numparam); k++)
102
                    {
103
                        value[x][y][n][k]=out[k];
104
                    }
105
106
107
                    n++;
108
                }
109
                while (n<=numofexp&&end<size);
110
                n=1;
111
                x++;
112
            }
113
            while (x<=xdim&&end<size);
114
            x=1;
115
            y++;
116
        }
117
        while (y<=ydim&&end<size);
118
119
        printf("Value is %e\n", value[1][1][1][1]);
120
121
122
        fclose(fi);
123
        return 0;
124
125
    }
126
}
(Danke an Code::Blocks)

Was das eigentliche Problem betrifft:
1
float ****value = (float ****)malloc(xdim * sizeof(float ***));
Wenn ich solche Zeilen sehe verliere ich ganz schnell die Lust mich mit 
dem Code respektive Problem zu beschäftigen, das geht bestimmt deutlich 
einfacher. Und getparameter() kenne ich auch nicht...

Das hier
1
if (!fi) printf("not opened");
wäre so
1
if(!fi)
2
{
3
    fprintf(stderr, "...");
4
    exit(1); //Programm beenden, ohne Datei gehts nicht weiter!
5
}
übrigens deutlich besser.

Also: Was genau soll der Code machen? Alle nötigen Informationen angeben 
bitte!

von M. M. (karlkappe)


Lesenswert?

Hi das mit der Formatierung tut mir Leid. Ich gebe zu das das Programm 
vielleicht nicht besonders toll und effektiv ist. Aber es ist auch nur 
für mich gedacht.
Was es machen soll:
Ich habe eine Binär-Datei mit Ascii Header. Die Binärdaten geben jeweils 
eine Reihe von Spannungswerte an die an einem Punkt X/Y aus 
verschiedenen DACs bei verschiedenen Spannungen werden ausgelesen 
werden. Ich will die Daten dann in einem 4-Dim Array haben 
value[X][Y][DACNummer][Spannung]=2.1V. Wenn ich das habe, will ich dann 
Maps bei Fixer Spannung erstellen oder Mittelewerte über verschiedene 
X/Y Punkte berechnen.
Hier die fehlenden Zeilen.
1
int check(char *search, char p[]){ /* */
2
 int l=strlen(search);
3
 int i=0;
4
 int k=0;
5
 for (i=0;i<l;i++){
6
 if (p[i]==search[i] && k==0) k=0; else {k=1;}
7
}
8
return k;  
9
}
10
11
fpos_t getstreampos(FILE *pFile, char *search){
12
  fseek(pFile, 0, SEEK_SET);  
13
  int l=strlen(search);
14
  char p[l-1];  
15
  int n = 0;
16
 
17
  fpos_t spos;
18
19
  do {
20
     for (n=0;n<=l-1;n++)
21
  { p[n] = fgetc (pFile);}
22
  fseek(pFile, -(l-1), SEEK_CUR);      
23
   } while ((check(search, p)!=0)&&(p[l-1]!=EOF)) ;
24
 
25
  
26
   fseek(pFile, l-1, SEEK_CUR);      
27
   fgetpos(pFile,&spos);
28
  
29
  return spos;
30
}
31
32
33
int getparameter(FILE *pFile, char *search){
34
  fseek(pFile, 0, SEEK_SET);
35
  int l=strlen(search);
36
  int c[10];
37
  char p[l-1];  
38
  int n = 0; int i=0;
39
  int num=0;
40
   
41
  
42
   do {
43
     for (n=0;n<=l-1;n++)
44
  { p[n] = fgetc (pFile);}
45
  fseek(pFile, -(l-1), SEEK_CUR);      
46
   } while ((check(search, p)!=0)&&(p[l-1]!=EOF)) ;
47
 
48
  
49
   fseek(pFile, l-1, SEEK_CUR);      
50
   n=0;
51
  do {      
52
    c[n] = fgetc (pFile);
53
        n++;
54
55
      } while(((c[n-1]>='0')&&(c[n-1]<='9'))&&(c[n-1] != EOF));
56
57
for(i=0;i<n-1;i++){
58
num = num+ (c[i]-48)*pow(10,(n-2-i)); 
59
};
60
61
  
62
  return num;
63
}

von M. M. (karlkappe)


Lesenswert?

Und danke für den Tip mit CODE:BLOCKS. Ich habe immer alles mit meinem 
einfachen Editor geschrieben jetzt weiß ich auch warum das bei andern 
immer besser aussieht.

von M. M. (karlkappe)


Lesenswert?

So nochmal den Fehlenden Code in hübscher.
1
int check(char *search, char p[])  /* */
2
{
3
    int l=strlen(search);
4
    int i=0;
5
    int k=0;
6
    for (i=0;i<l;i++)
7
    {
8
        if (p[i]==search[i] && k==0) k=0;
9
        else
10
        {
11
            k=1;
12
        }
13
    }
14
    return k;
15
}
16
17
fpos_t getstreampos(FILE *pFile, char *search)
18
{
19
    fseek(pFile, 0, SEEK_SET);
20
    int l=strlen(search);
21
    char p[l-1];
22
    int n = 0;
23
24
    fpos_t spos;
25
26
    do
27
    {
28
        for (n=0;n<=l-1;n++)
29
        {
30
            p[n] = fgetc (pFile);
31
        }
32
        fseek(pFile, -(l-1), SEEK_CUR);
33
    }
34
    while ((check(search, p)!=0)&&(p[l-1]!=EOF)) ;
35
36
37
    fseek(pFile, l-1, SEEK_CUR);
38
    fgetpos(pFile,&spos);
39
40
    return spos;
41
}
42
43
44
int getparameter(FILE *pFile, char *search)
45
{
46
    fseek(pFile, 0, SEEK_SET);
47
    int l=strlen(search);
48
    int c[10];
49
    char p[l-1];
50
    int n = 0;
51
    int i=0;
52
    int num=0;
53
54
55
    do
56
    {
57
        for (n=0;n<=l-1;n++)
58
        {
59
            p[n] = fgetc (pFile);
60
        }
61
        fseek(pFile, -(l-1), SEEK_CUR);
62
    }
63
    while ((check(search, p)!=0)&&(p[l-1]!=EOF)) ;
64
65
66
    fseek(pFile, l-1, SEEK_CUR);
67
    n=0;
68
    do
69
    {
70
        c[n] = fgetc (pFile);
71
        n++;
72
73
    }
74
    while (((c[n-1]>='0')&&(c[n-1]<='9'))&&(c[n-1] != EOF));
75
76
    for (i=0;i<n-1;i++)
77
    {
78
        num = num+ (c[i]-48)*pow(10,(n-2-i));
79
    };
80
81
82
    return num;
83
}

von rups (Gast)


Lesenswert?

Mal etwas OT:
M. M. schrieb:
> So nochmal den Fehlenden Code in hübscher.
Sehr schön. ;-)

Nur um Missverständnisse zu vermeiden: Es gibt verschiedene Arten seinen 
Code zu formatieren, diese Frage dürfte ähnlich wie der Vergleich 
AVR<->PC eine religiöse Angelegenheit sein. Wichtig ist aber: Egal wie 
man es macht, es muss durchgängig so gemacht sein und einigermaßen 
übersichtlich.

Ob man nun
1
void foo(void)
2
{
3
   for() {
4
      ...
5
   }
6
}
oder
1
void foo(void)
2
{
3
   for() 
4
   {
5
      ...
6
   }
7
}
schreibt ist egal (mir gefällt die 2. Version deutlich besser), sowas
1
void foo(void)
2
{
3
for() {
4
      ...
5
}
6
}
ist aber definitiv unbrauchbar. Der Code-Formatter von C::B sollte nur 
ein Behelfswerkzeug sein um fremdem Code überhaupt irgendeine Struktur 
zu verpassen oder seinen persönlichen Vorlieben anzupassen. Seine 
eigenen Programme sollte man bereits beim Tippen vernünftig formatieren, 
in C ist das extrem wichtig und kann einige Fehler aufdecken.

Falls du mit "Editor" notepad.exe meinst, das ist in der Tat nicht 
besonders bequem. C::B ist aber eine komplette IDE, zum Tippen reicht 
Programmer's Notepad o.ä.

BTT:
> Ich habe eine Binär-Datei mit Ascii Header. Die Binärdaten geben jeweils
> eine Reihe von Spannungswerte an die an einem Punkt X/Y aus
> verschiedenen DACs bei verschiedenen Spannungen werden ausgelesen
> werden. Ich will die Daten dann in einem 4-Dim Array haben
> value[X][Y][DACNummer][Spannung]=2.1V. Wenn ich das habe, will ich dann
> Maps bei Fixer Spannung erstellen oder Mittelewerte über verschiedene
> X/Y Punkte berechnen.
Puh, vierdimensionale Arrays und malloc()...
Poste mal ein Beispiel wie die Dateien die du verarbeiten willst 
genau(!) aufgebaut sind und verpasse deinem Code ein paar sinnvolle 
Kommentare (welcher Block macht was, wozu sind die "Magic Numbers" = im 
Quellcode vorhandene Zahlen wie in "...+4" gut usw).
Ich muss zugeben ich bin zu faul aus dem vorhandenen Code die Struktur 
der Daten zu ermittlen um dann zu versuchen den Code zu verstehen.

von M. M. (karlkappe)


Lesenswert?

Die Daten kommen aus einem SPM-Controller von Nanonis. Das geben sie als 
Datei Beschreibung an.
header:
Grid dim="24 x 24"
Grid settings=0.000000E+0;0.000000E+0;6.880776E-9;6.880776E-9;-
2.244028E+1
Sweep Signal="Bias (V)"
Fixed parameters="Sweep Start;Sweep End"
Experiment parameters="X (m);Y (m);Z (m);Z Offset (m);Settling time
(s);Integration time (s)"
# Parameters (4 byte)=8
Experiment size (bytes)=2048
Points=256
Channels="Current (A);Current [bwd] (A)"
Experiment="Grid Spectroscopy"
Date="30.08.2006 14:52:45"
User=user1
:HEADER_END:
continued by, in hexadecimal representation:
0d
00
31
79
0a c0 00 00 00 40 00 00 00 b0 f6 18 55 b1 94 18 42 b0 84 7c 66
00 00 00 39 51 b7 17 38 d1 b7 17 ae ca c3 f0 ae c6 60 e3 ae c2
bf ae bf 5a a3 ae c5 af f1 ae be e8 94 ae ba 8e 31 ae b7 d9
...
where 0d 0a is the end of line after the :HEADER_END:. Then, c0 00 00 00 
(= -2) is the first fixed
parameter (Sweep Start) and so on. 38 d1 b7 17 (=1E-4) corresponds to 
the last paramter
(Integration time (s)). After that 256 values of the first data channel 
(Current (A)) will follow,
starting with ae ca c3 f0 (= -9.2207E-11). Next will be 256 values of 
the second data channel
(Current [bwd] (A)). As no more channels were acquired this will 
finalize the first experiment and
the data will continue with the parameters of the 2nd experiment.

Die Sache mit den +4 und umdrehen ist ein Problem von endian floats oder 
halt nicht auf den unterschiedlichen Rechnern. Was ich am Schluß machen 
will ist: ein Rechteck X mal Y auswählen und die Daten mitteln. Dann 
Ableiten und dann Normieren. Details hab ich mir noch nicht überlegt. 
Ich habe das früher alles als bash-script machen können weil die alte 
Hardware alles hübsch in Ascii ausgespuckt hat. Nun ist die Hardware 
modern und auch die Datenmenge ist explodiert. Nachdem ich alles in 
Ascii hab sind die Bash Sachen einfach super langsam und ich dachte das 
müßte mit C viel schneller gehen.

von DirkB (Gast)


Lesenswert?

Hast du mal ein paar printf dazwischen gemacht, damit du siehst WO das 
Proramm aussteigt.

Hast du auch daran gedacht das die Indizes von 0 bis max-1 gehen.

Also wenn dein 'Grid dim="24 x 24" ' gehen die Inizes von 0 bis 23 oder 
von 0 bis 24?

von Rolf Magnus (Gast)


Lesenswert?

M. M. schrieb:
> Compilieren tut er Problemlos aber sobald ich es dann ausführe gibt es
> einen Speicherzugriffsfehler. Hat jemand eine Idee warum?

Der Debugger hat wahrscheinlich eine. Was sagt der denn?

von Vlad T. (vlad_tepesch)


Lesenswert?

Rolf Magnus schrieb:
> Der Debugger hat wahrscheinlich eine. Was sagt der denn?

wenn er mit Notepad coded, wird er wohl kaum einen Debugger kennen.

Tip:
mit c++ kann man sich das um einiges einfacher machen, wenn man zB die 
vector Klasse benutzt, die sich selbst um den Speicher kümmert

von Vlad T. (vlad_tepesch)


Lesenswert?

Achso:
ich würde mir nicht die Mühe machen, 4 dimensionale Arrays zu bauen.
Alloziiere den Speicher en bloc und überlege dir wie du die Indizes auf 
das lineare Array mapst.

Das erspart einem die fehglerträchtigen malloc und free schleifen


Auserdem würde ich das ganze ein wenig besser kapseln
rups schrieb:
> value[X][Y][DACNummer][Spannung]
1
/**
2
 * Structure that holds the data from an measurement file
3
 */
4
typedef struct Data{
5
  uint32_t xCount;    /**<  number of x Coordinates           */
6
  uint32_t yCount;    /**<  number of < Coordinates           */
7
  uint32_t dacCount;  /**<  number of used DACs               */
8
  uint32_t vCount;    /**<  number of measurements per DAC    */
9
  float* data;        /**<  array that holds the measurements */
10
}Data;
11
12
13
/** reads a file and creates Data object.
14
 *  @return pointer to initialized Data structure\n
15
 *          Has to be freed witch Data_delete
16
 */
17
Data* Data_readFromFile(const char* i_file)
18
{
19
  Data* data = malloc(sizeof(Data));
20
  uint32_t i;
21
  uint32_t dataCount;
22
  //header lesen und o_data befüllen
23
24
  dataCount = data->xCount 
25
            * data->yCount
26
            * data->dacCount
27
            * data->vCount;
28
                      
29
30
  data->data = malloc( dataCount  * sizeof(*data->data));
31
32
  // Nicht vergessen: bei lesefehler bisher geholten Speicher wieder freigeben!!!  
33
34
  // datenbereich einlesen und in o_data->data schreiben.
35
  //for
36
  //  *Data_getPtr(...) = eingelesener wert
37
  //
38
}
39
40
/** frees the given Data object */
41
void Data_delete(Data** data)
42
{
43
  free((*data)->data);
44
  free(*data);
45
  *data = NULL;
46
}
47
48
49
/** returns a pointer to the data defined by the adress parameters*/
50
float* Data_getPtr(const Data* data, uint32_t x, uint32_t y, uint32_t dac, uint32_t v)
51
{
52
  uint32_t ind =  (y*data->xCount*data->dacCount*data->vCount)
53
                + (x*data->dacCount*data->vCount)
54
                + (dac * data->vCount)
55
                + v;
56
  return &data->data[ind];
57
}
58
59
60
// beispiel
61
62
main
63
{
64
65
  uint32 v;
66
  Data* data = Data_readFromFile("bla.txt");
67
  
68
  for(v = 0; v < data->vCount; ++v)
69
  {
70
    printf("%f\n", *Data_getPtr(data, 0,0,0,v));
71
  }
72
73
  Data_Delete(&data);
74
}

von M. M. (karlkappe)


Lesenswert?

DirkB schrieb:
> Hast du mal ein paar printf dazwischen gemacht, damit du siehst WO das
> Proramm aussteigt.
>
> Hast du auch daran gedacht das die Indizes von 0 bis max-1 gehen.
>
> Also wenn dein 'Grid dim="24 x 24" ' gehen die Inizes von 0 bis 23 oder
> von 0 bis 24?

Man man bin ich doof!
Na klar bekommt man einen Speichzugriffsfehler wenn man das Array von 0 
bis 23 initalisiert und dann auf nummer 24 zugreifen will!
Danke das hat mir sehr geholfen.

Auch an Vlad Tepesch vielen Dank. Leider sind meine Kentnisse in C++ 
noch schlechter als in C. Deinen anderen Vorschlag werde ich mir mal 
annschauen.

von ... (Gast)


Lesenswert?

Bei derart vielen verschachtelten malloc solltest Du auch prüfen ob Dir 
malloc überhaupt noch Speicher liefert, sonst knallts auch irgendwann.

M. M. schrieb:
> Achja und es wäre nett wenn wir noch jmd. sagen könnte
> wie ich den Speicher hinterher wieder ordentlich frei mache.

Ganz einfach in der umgekehrten Reihenfolge, z.B.
1
  for(i = 0; i < xdim; i++) {
2
    for(j = 0; j < ydim; j++) {
3
      for(k = 0; k < numparam; k++) {
4
        free(value[i][j][k]);
5
      }
6
      free(value[i][j]);
7
    }
8
    free(value[i]);
9
  }
10
  free(value);

von M. M. (karlkappe)


Lesenswert?

Danke für den Tip mit dem prüfen vom Speicher hab ich mal so gemacht, 
ich denke das sollte es tun?
1
if ( value==NULL )
2
        {
3
            fprintf(stderr, "Out of Memory\n");
4
            exit(1);
5
        }

Auf der anderen Seite funktioniert das freigeben nicht. Weiss aber nich 
wieso. Mal schauen was ich flasch gemacht habe.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.