Forum: PC-Programmierung Zugriffsverletzung C-Programm


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Albert (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo
Ich mache in meinem Code irgendwo eine Zugriffsverletzung und weiß aber 
nicht wo.Ich hoffe ihr könnt mir dabei helfen.

H-File:
1
typedef struct {
2
  int temp;
3
  int druck;
4
  int day;
5
  int month;
6
  int year;
7
8
}weatherdata;
9
10
void appendWeatherData(weatherdata * data,int *sizeOfData);

C-File:
1
void appendWeatherData(weatherdata *data, int *sizeOfData)
2
{
3
  static int sizeOfDataSpace = 10;
4
5
  if (sizeOfDataSpace <= *sizeOfData) {
6
7
    if( (realloc(data, sizeof(weatherdata) * 10))!=NULL);
8
    {
9
      sizeOfDataSpace += 10;
10
    }
11
    
12
    
13
14
15
  }
16
17
  //irgendwas reinschreiben
18
  if (*sizeOfData < sizeOfDataSpace) {
19
20
    
21
22
    data[*sizeOfData].day = *sizeOfData;
23
    data[*sizeOfData].druck = *sizeOfData;
24
    data[*sizeOfData].month = *sizeOfData;
25
    data[*sizeOfData].temp = *sizeOfData;
26
    data[*sizeOfData].year = *sizeOfData;
27
    
28
    *sizeOfData = *sizeOfData + 1;
29
    
30
  }
31
32
  
33
  
34
}

Main-File:
1
int main()
2
{
3
  int size = 0;
4
  weatherdata *data;
5
6
  data = (weatherdata*)calloc(10 ,sizeof(weatherdata));
7
8
  for (int i = 0; i < 20; i++)
9
  {
10
    appendWeatherData(data, &size);
11
12
13
  }
14
15
  for (int i = 0; i < size-1; i++)
16
  {
17
    if (data != NULL) {
18
      printf("Daten: %d -->%d %d %d Temp:%d Druck%d \n",i+1 ,data[i].day,data[i].month,data[i].year, data[i].temp, data[i].druck);
19
    }
20
    
21
    
22
    
23
24
  }
25
  
26
  if (data != NULL) {
27
28
    free(data);
29
  }
30
  
31
32
33
    return 0;
34
}

--

Die Tags werden natürlich ohne Leerzeichen geschrieben. Wenn man sie 
aber so in den Text reinschreibt, werden sie ausgewertet und dann sind 
sie für Dich nicht sichtbar ...

Sieh Dir mal den Hinweistext an, der hier oberhalb der Editbox steht.

-rufus

: Bearbeitet durch Moderator
von Dirk B. (dirkb2)


Bewertung
0 lesenswert
nicht lesenswert
Du benutzt realloc falsch.

Du musst die Größe des gesamten benötigten BEreichs angeben, nicht nur 
die vom neuen.

Und es wird die Adresse von diesem Bereich zurück gegeben.
Das kann eine andere Adresse als vorher sein.

PS. Die Code-Tags haben i.A. keine Leerzeichen

: Bearbeitet durch User
von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Albert schrieb:
> if( (realloc(data, sizeof(weatherdata) * 10))!=NULL);

Das geht ganz gewaltig in die Hose, denn Du schmeißt den Rückgabewert 
von realloc weg ...

von Rolf M. (rmagnus)


Bewertung
1 lesenswert
nicht lesenswert
Albert schrieb:
> C-File:
> [ c ]
> void appendWeatherData(weatherdata *data, int *sizeOfData)
> {
>   static int sizeOfDataSpace = 10;
>
>   if (sizeOfDataSpace <= *sizeOfData) {
>
>     if( (realloc(data, sizeof(weatherdata) * 10))!=NULL);

Wie Dirk schon schreibt, musst du den Rückgabewert nicht nur prüfen, 
sondern dir auch merken. Da steht die neue Adresse des reallokierten 
Speichers drin. Die verwirfst du aber und nutzt die alte, möglicherweise 
nicht mehr gültige Adresse weiter.
Abgesehen davon ist das Semikolon am Ende der Zeile falsch.

> Main-File:
> [ c ]
> int main()
> {
>   int size = 0;
>   weatherdata *data;
>
>   data = (weatherdata*)calloc(10 ,sizeof(weatherdata));

Den Cast solltest du weglassen. Der ist überflüssig und kann sogar 
Fehler verdecken.

Ich finde den Code generell recht umständlich und unnötig schwer 
verständlich. Aber das ist denke ich für den Anfang normal.

Dirk B. schrieb:
> PS. Die Code-Tags haben i.A. keine Leerzeichen

Wie man übrigens auch direkt über dem Eingabefeld bei den 
Formatierungsregeln sehen kann. Es schadet auch nicht, vor dem Absenden 
sich mal in der Vorschau anzusehen, ob alles passt.

von Albert (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Sorry für die Tags.
Erstmal danke für die schnelle Hilfe.
Ich hab das nun geändert
1
if (sizeOfDataSpace <= *sizeOfData) {
2
3
    data = realloc(data, sizeof(weatherdata) * (sizeOfDataSpace+10));
4
5
    if (data != NULL) {
6
7
      sizeOfDataSpace += 10;
8
    }

Jetzt läuft es bis zum free(data) durch und da bekomm ich eine 
Zugriffsverletzung. Woran liegt das ?
Wie läuft das eigentlich genau mit realloc?
Werden die vorhanden Daten kopiert und ein neuer Speicher daran gehängt?
Wird der alte Speicher automatisch freigegeben?

von Dirk B. (dirkb2)


Bewertung
0 lesenswert
nicht lesenswert
Albert schrieb:
> Jetzt läuft es bis zum free(data) durch und da bekomm ich eine
> Zugriffsverletzung. Woran liegt das ?

Ich denke, dass du das data nicht richtig aus appendWeatherData an main 
zurück gibst.

Dazu brauchst du einen Doppelzeiger oder einen anderen Rückgabetyp als 
void.

Albert schrieb:
> Wie läuft das eigentlich genau mit realloc?

Woher kennst du denn realloc?
Da muss doch irgendwas erklärt worden sein.

realloc ist eine Funktion aus der C-Standardbibliothek.
Und die sind außerordentlich gut dokumentiert.

Z.B. http://www.cplusplus.com/reference/cstdlib/realloc/?kw=realloc

Da klären sich auch die andeen Fragen.


Aber wenn du beim realloc-Aufruf data gleich wieder überschreibst, dann 
gehen dir im Fehlerfall (NULL) die Daten verloren.

von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Albert schrieb:
> data = realloc(data, sizeof(weatherdata) * (sizeOfDataSpace+10));

Das ist zwar besser, aber immer noch ungeschickt.

Stell' Dir folgende Situation vor:

Vor dem Aufruf von realloc zeigt data auf Speicher, den Du mühsam 
angefordert und gefüllt hast.

Nun willst Du mehr Speicher anfordern als verfügbar ist, was realloc 
mit dem Zurückgeben von NULL quittiert.

Und was ist mit den Daten, auf die vorher data zeigte?

Die sind immer noch da. Aber Du hast mit der Zuweisung des Ergebnisses 
von realloc an data weggeworfen, wo die Daten sind, d.h. Du kannst 
den Speicher auch nicht mehr freigeben ...

Fazit: Niemals den Rückgabewert von realloc unmittelbar dem gleichen 
Pointer zuweisen, der als erstes Argument übergeben wird. Nimm einen 
Hilfspointer, prüfe den und erst wenn er nicht NULL ist, weist Du diesen 
neuen Pointer dem jetz ungültigen Pointer data zu. Ist er aber NULL, 
ist data nach wie vor gültig, und Du hast die Chance, irgendwas 
sinnvolles damit anzufangen.

von size (Gast)


Bewertung
0 lesenswert
nicht lesenswert
lass dir mal in appenddata zu beginn deine datasize vor dem if ausgeben

von Albert (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Das mit den Hilfs-Pointer macht sinn. Hab das geändert. Danke
Das mit dem datasize ausgeben versteh ich nicht. Da steht immer die 
aktuelle Anzahle der Datensätze drin. Versteh nicht was es bringen soll.
Ich hab jetzt die Funktion geändert. Nun gibt Sie einen weatherData 
Pointer zurück. Jetzt funktioniert auch das free.
Find es trotzdem komisch das es vorher nicht funktioniert hat. Immerhin 
kann ich ja vor dem free noch auf alle Daten zugreifen ohne eine 
Zugriffsverletzung.

von Andreas E. (hismastersvoice)


Bewertung
0 lesenswert
nicht lesenswert
Das hat vorher funktioniert, da main noch auf den alten Speicher zeigte, 
den noch nichts überschrieben hat.
Das free ging nicht, weil malloc den Speicher schon zurück genommen hat. 
Die Daten darin existieren aber noch.
Lass mal in Deinem alten Code appendWeatherData irgendein Feld in dem 
reallocierten data ändern und lies das dann in main aus. Dann solltest 
Du es sehen!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.