Hallo!
Ich habe schon wieder in kleines Problem. Ausgangspunkt stellt diese
Page dar:
http://pronix.linuxdelta.de/C/standard_C/c_programmierung_17_1.shtml#8
Dort wird sehr schön erklärt wie man dynamisch 2 dimensionale Arrays
erstellt. Ich habe ihn auch so weit verstanden (glaube ich zumindest,
diese Pointer auf Pointer geschichte ist schon
Hirnschmalzbeanspruchend). Ich möchte diesen Code aber nicht einfach so
verwenden, sondern ihn in einzelne Funktionen unterteilen, damit ich in
einem Programm diese verwenden kann. Dies funktioniert allerdings nicht.
Ich gehe davon aus, dass es ein ähnliches Problem ist wie bei der
klassischen swap-funktion: werden nicht pointer auf die Variablen
übergeben ist nach beenden der Funktion nicht vertauscht. Ich hoffe ihr
wisst was ich meine...
Auf jeden Fall habe ich eine Funktion gebastelt, die eigentlich
lediglich ein paar neue Zeiger auf Zeiger erstellen soll (eigentlich ist
es (bis auf die Namensgebung) aus dem Beispielprogramm geraubt:
1
intnew_zeilen(intn,int**matrix){
2
/* reserviert den Speicher für n neue zeilen-zeiger */
3
matrix=(int**)malloc(n*sizeof(int*));
4
if(matrix==NULL)return1;
5
return0;
6
}
Hier funktioniert der Code auch noch, aber wenn danach eine Spalte
erzeugt werden soll, dann gibt es einen Fehler der darauf hindeuten
lässt, dass im vorhergehenden Schritt (in meiner Funktion) was schief
gegangen ist.
Unhandled exception at 0x00412085 in DynMem.exe: 0xC0000005: Access
violation writing location 0x00000000.
Ich hoffe jemand kann mir helfen...
> Hier funktioniert der Code auch noch, aber wenn danach eine Spalte> erzeugt werden soll, dann gibt es einen Fehler der darauf hindeuten> lässt, dass im vorhergehenden Schritt (in meiner Funktion) was> schief gegangen ist.
Wieso deutet die Fehlermeldung darauf hin, dass der Fehler in der
geposteten Funktion liegt? Ich sehe da keinen Zusammenhang. Warum
postest du den Spaltenteil nicht ebenfalls?
Was mir allerdings auffällt: Was passiert mit dem Parameter Matrix? Er
wird nicht benutzt, sondern einfach überschrieben. Der neue Wert wird
ebenfalls nicht genutzt. Wolltest du über den Parameter matrix einen
Pointer an den Aufrufer zurückgeben? Wenn ja, sollte das eher so
aussehen:
1
intnew_zeilen(intn,int***matrix){
2
/* reserviert den Speicher für n neue zeilen-zeiger */
Hallo!
Vielen Dank für deine Hilfe, mit der Änderung komme ich immerhin schon
einen Schritt weiter. Da es aber schwierig zum beschreiben ist, wie ich
wo was meine, habe ich in Minimalprogramm geschrieben, das eigentlich
alle funktionalität enthält, aber die Fehlerquellen zeigen kann so dass
ich evtl daran weiter arbeiten kann.
Hier der Code:
1
#include"stdlib.h"
2
3
4
intnr_of_packets(int**buffer){
5
/* Gibt die Anzahl allozierte Speicherplätze für Paket-Pointer zurück */
Der fehler der Accessviolation tritt an der Stelle, die mit <-- markiert
ist auf. Ich hoffe es wird einigermassen klar was das Ding tun soll.
Eigentlich habe ich das Ding mit den Pointern schon verstanden, aber bei
2 Dimensionalen Geschichten wirds einfach nochmals eine Stufe
schwieriger und dann noch das ganze als Pointer übergeben... Also bei
*** wirds dann nicht mehr sehr anschaulich. Wenn mir jemand helfen kann,
DANKE!
Mfg
Hallo!
Auch wenn das das eigentliche Problem nicht löst: Danke. Weshalb sollte
ich realloc nicht nehmen? Wenn ichs mit (m)alloc und free löse, dann
muss ich den ganzen Inhalt zuerst zwischen speichern, das ist dann aber
ziemlich speicherintensiv...
Die Funktion von realloc ist nicht überall gleich. Manchaml wird so
verfahren, dass der Speicher nur verkleinert werden kann.
Speicheroperationen free und alloc sind meist sehr effizient. Ein
Engpass entsteht nur in unglücklichen Situationen wenn die
Fragmentierung zum Tragen kommt. In Sprachen wie Java oder Lisp gibt es
dafür die GC=Garbage Collection.
--> **buffer in realloc ist NULL soweit ich das jetzt überblicke
dem realloc den **buffer vorwerfen?
realloc möchte einfach nur die Speicheradresse, an der sich der
Speicher momentan befindet. Das wäre in deinem Fall *buffer
PS: Vergiss die Aussage, das man realloc nicht macht. realloc
ist perfekt für C und ganz im Gegenteil, wenn man dynamische
Strukturen hat benutzt man realloc aus Performancegründen, da
einem ein realloc unter Umständen das Umkopieren von Daten
ersparen kann.
> Die Funktion von realloc ist nicht überall gleich.
Unsinn. realloc ist eine Standard-C Funktion. Wenn die nicht
überall gleich funktioniert, dann ist die betreffende Library
fehlerhaft und sollte ausgetauscht werden.
> aber bei> 2 Dimensionalen Geschichten wirds einfach nochmals eine Stufe> schwieriger und dann noch das ganze als Pointer übergeben... Also bei> *** wirds dann nicht mehr sehr anschaulich.
Dann definier dir einen typedef für einen 2-fach Pointer und arbeite
damit weiter
1
typedefintArrayType;
2
typedefArrayType*Array_1;
3
typedefArray_1*Array_2;
4
5
intnr_of_packets(Array_2buffer){
6
/* Gibt die Anzahl allozierte Speicherplätze für Paket-Pointer zurück */
PS: den Return Wert von malloc oder realloc in C niemals casten!
Das kann Fehler verstecken. Wenn du casten musst, dann programmierst
du in C++ und dort wäre new/delete anstelle von malloc das Werkzeug
der Wahl, wenn es denn unbedingt selbst programmiert sein soll.
In C++ wäre allerdings std::vector die absolut beste Lösung.
wieso machst du so umständlich?
was spricht hier gegen eine linked list?
verwalte head und tail, und wenn ein packet ankommt
fügst du es am tail an.
dann kannst du eine art konstruktor machen,
der auch nach malloc nach != NULL prüft.
wenn du an 1000 stellen malloc/realloc aufrufst,
ist es oft schwer konsequent zu prüfen.
sollte später sich rausstellen, dass die liste
heterogen sein sollte, kannst du einen tag in
die node stuct nehmen, und entweder einen generischen void*
oder union benutzen.
meine 2 cent
daniel
>> Die Funktion von realloc ist nicht überall gleich.>Unsinn. realloc ist eine Standard-C Funktion. Wenn die nicht>überall gleich funktioniert, dann ist die betreffende Library>fehlerhaft und sollte ausgetauscht werden.
:-) Mach es.
Es gibt Unterschiede in der Strategie auch in Abhängigkeit vom
Betriebssystem. Probleme treten bei starker Fragmentierung und im
Fehlerfall zutage. Eigentlich sieht es ja überschaubar aus, aber AFAIK
kann man jede Speicherverwaltung an die Wand fahren.
>http://de.wikipedia.org/wiki/Dynamischer_Speicher
Also realloc zu verwenden bedeutet dem System absolut zu vertrauen und
die Existenz von Bugs zu verleugnen. Beispielsweise gibt einige gut
ausgebildete Leute, die von sich geben ein C Compiler könnte "denken".
Das ist das Gottvertrauen in das System, dem möchte ich hier
entgegentreten.
Ist natürlich ein Todschlagargument :-)
Hallo!
Vielen Dank für die Hilfe. Eine verkettete Liste möchte ich nicht
verwenden, weil die zu speichernden Daten nicht in einer vorteilhaften
Reihenfolge ankommen.
Es ist nun so, dass mit dem Simulator eine Stufe weiter komme, aber
irgendwie scheint das ganze mit dem allozieren immer noch nicht zu
funktionieren, folgendes habe ich beobachtet:
Wenn ich ein Packet mit nr. 0 (also gleich die erste Stelle) abspeichern
möchte, dann gibts keine AccessViolation bei <---1. Es geht dann gut bis
die For-Schleife einmal durchlaufen worden ist und i = 1 ist, dann gibts
bei <---2 eine AccessViolation. Dies deutet für mich darauf hin, dass
die Allozierung nicht wirklich funktioniert hat.
Ganz ähnlich verhält es sich wenn die Paketnr. > 0 ist, dann gibts
bereits bei <---1 eine AccessViolation...
1
#include"stdlib.h"
2
3
4
intnr_of_packets(int**buffer){
5
/* Gibt die Anzahl allozierte Speicherplätze für Paket-Pointer zurück */
Jorge wrote:
>>> Die Funktion von realloc ist nicht überall gleich.>>Unsinn. realloc ist eine Standard-C Funktion. Wenn die nicht>>überall gleich funktioniert, dann ist die betreffende Library>>fehlerhaft und sollte ausgetauscht werden.>> :-) Mach es.
Brauch ich nicht.
Mein realloc funktioniert und ich gehe auch eine Wette ein
dass das realloc vom OP auch funktioniert.
Zumal ein 'simpled' realloc in der Minimalversion absolut
trivial zu implementieren ist.
> Betriebssystem. Probleme treten bei starker Fragmentierung und im> Fehlerfall zutage.
Wenn du mit realloc Probleme hast, dann hast du die auch mit malloc.
Wenn realloc den Speicher nicht in place vergrößern kann, dann greift
es auf einen normalen malloc (oder auf die darunter liegende
Allokierungsschicht) zurück und macht ein memcpy. Was anderes
kannst du auch nicht machen.
> Also realloc zu verwenden bedeutet dem System absolut zu vertrauen und> die Existenz von Bugs zu verleugnen.
Mit Verlaub. Aber so einen Unsinn hab ich in 25 Jahren überhaupt
noch nie gehört. In einer Hochsprache zu programmieren heist generell
dem Compiler und dem Runtime System zu vertrauen. Es heist auch
damit leben zu lernen, dass sowohl in Compilern als auch in den
Standard Libraries Fehler vorhanden sind. Das hat aber nichts mit
dem Verleugnen von Bugs zu tun.
Demnächst willst du uns auch noch weiß machen, daß die str...
Funktionen Teufelswerk sind.
COMPILIERENli wrote:
> möchte, dann gibts keine AccessViolation bei <---1. Es geht dann gut bis> die For-Schleife einmal durchlaufen worden ist und i = 1 ist, dann gibts> bei <---2 eine AccessViolation. Dies deutet für mich darauf hin, dass> die Allozierung nicht wirklich funktioniert hat.> Ganz ähnlich verhält es sich wenn die Paketnr. > 0 ist, dann gibts> bereits bei <---1 eine AccessViolation...
Na ja.
Deine nr_of_packets Funktion ist darauf angewiesen, dass du immer
einen Pointer mehr als benötigt allozierst, damit ganz zum Schluss
am Ende des Arrays ein NULL Pointer steht. Diesen NULL Pointer
benutzt nr_of_packets um das Ende des Arrays zu finden.
Blöd ist nur, dass du diesen NULL Pointer niemals im Array setzt.
Hinweis: Mit deiner Abzählstrategie musst du immer einen Pointer
mehr allokieren als du eigentlich Pointer im Array speicherst.
Wenn du den ersten Pointer ins Array legst, musst du Platz für
2 Pointer allokieren. Den ersten für den tatsächlichen Datenpointer,
den zweiten für den NULL Pointer nach dem nr_of_packets sucht.
Mein Tip an dich lautet:
Papier und Bleistift raus und einfach mal mitzeichnen, welcher
Pointer wann und wo gesetzt wird und dann einfach mal Computer
spielen und das ganze am Papier durcharbeiten. Dann sollte es klarer
werden.
Und immer dran denken: Wenn du Speicher allokierst, dann ist
(mit Ausnahme von calloc) nicht vorherbestimmt, welche Werte
bereits in diesem Speicher stehen. malloc(), realloc() setzen
den Speicher nicht auf 0!
Hallo Karl heinz,
ich möchte dir keinesfalls zu nahe treten.
>Mit Verlaub. Aber so einen Unsinn hab ich in 25 Jahren überhaupt>noch nie gehört. In einer Hochsprache zu programmieren heist generell>dem Compiler und dem Runtime System zu vertrauen.
Du hast ja auch recht mit deinen Aussagen. Es gibt aber eine Sichtweise
unabhängig von Bit und Byte und das hat wie du es auch schon
angesprochen hast etwas mit der Persönlichkeit des Programmierers zu
tun. Jeder hat natürlich seinen individuellen Stil und kommt damit
zurecht.
Im Team habe ich Leute kennengelernt, die sich früher oder später einen
anderen Traumjob suchen. Genau wie du bin ich aber meiner Linie treu
geblieben, egal ob mir jemand etwas dafür zahlt oder nicht.
Ein Punkt beim realloc ist, daß es etwas komplizierter ist, sich in die
Gedankengänge eines fremden Programmierers einzufinden. Es sind halt ein
paar Parameter mehr und man weiss nicht sofort was hat der/die sich
dabei gedacht.
Ich dachte mir spontan, der Fragesteller benutzt eine Vorlage, mit einem
Repertoire welches er nicht beherrscht - und ist daran gescheitert.
Analog zu new und delete benutze ich spartanisch die Heapfunktionen wie
Compund-statements in einem Block. Ich möchte völlig klar wissen welches
Fragment wann erzeugt und freigegeben ist. In einem 2-dimensionalen
Array werden bei mir erst sämtliche Pointer für die 1-te Dimension
erzeugt und in einer zweiten Schleife die Pointer für die 2-te
Dimension. Selbstverständlich kann man auch alles in einer Schleife und
innerhalb einer Zeile erledigen. Manchmal gehe ich aus garantierten
Performancegründen sogar soweit, dass ich einen grossen Block anfordere
und die Fragmente via Pointerarithmetik selbst verwalte, am Schluss wird
nur noch mit einem free bzw delete aufgeräumt. Gerade innerhalb von
Klassen mach ich es so. Jedermann weiss warum Java irgendwann so langsam
wird. Auch das Argument der hängenden Pointer, welches vor allem von
ungeschickten Programmierern immer wieder ins Feld geführt wird verliert
seinen Gehalt.
Wenn jemand den Umgang mit realloc aus dem ff beherrscht darf er das
gerne verwenden, mir ist es unsympathisch weil es eine Funktion mehr ist
und gegen die Kreativität nach dem Legoprinzip funktioniert, also immer
der gleiche simple Baustein in kreativer Weise eingesetzt. Weiterhin
sind ein paar mehr Fehlerbedingungen beim realloc zu berücksichtigen.
Die errno Variable gibt zurück, ob die Anforderung erfolgreich war. Bei
new oder alloc muss ich nur gucken, ob das Ergebnis ungleich NULL ist.
Leider kann man sich im Windoof und heutzutage auch im
Distributionslindoof auf gar nix mehr verlassen. Die Heapfunktionen
werden mehr oder minder ans Betriebssystem weitergereicht, schon aus der
Win311 Ära ist es mir gründlich verleidet.
Besonders aufschlussreich war mir die Zeit als Programmierer im Team mit
Leuten, die deutlich weniger Erfahrung und erfolgreiche Projekte haben.
Dafür hatten die aber bessere Noten. Ich habe mich niemals eingemischt,
es ist durchaus möglich, dass ich für deren Konstruktion schlicht zu
blöd bin.
Der Grundfehler an dem solche Leute letztlich an psychischer
Überbelastung scheitern ist es Strukturen azulegen die komplizierter
sind als sie es selbst durchschauen.
Deswegen mein Nein zu realloc & Co.
Das eigentliche Problem ist die ursprünglichen Frage, da die wichtigsten
Angaben fehlen, um entscheiden zu können welcher Ansatz verwendet werden
sollte.
Wie oft wird das Anlegen benötigt, wie viele Objekte, wie müssen die
Objekte danach weiterverarbeitet werden etc.? Steht das fest, kann man
entscheiden wie man's implementiert: mit einfachen Arrays, Listen oder
z.B. Heaps. Ist dann die Speicherallokation das limitierende Element,
kann man diese anpassen.
p.s. Ein "kleiner" Test für Speicherverwaltungsalgorithmen war die
grundlegende VM des ICFPCs 2006, die man auch für einen
Performance-Vergleich nehmen könnte...
http://www.boundvariable.org/um-spec.txt
Hallo!
Also eigentlich würde ich schon gerne auf eine Hochsprache mit ihren
Vorzügen vertrauen...
Zu den Anforderungen: Es geht darum, dass einzelne Pakete ankommen, in
der Grösse von max. einigen Kb, jedoch in einer beliebigen Reihenfolge.
Diese sollen abgelegt werden, und zwar so, dass man weiss, welche Pakete
noch fehlen. Am Schluss sollen dann alle Pakete aneinander gehängt
werden.
Ich kenne nicht alle Möglichkeiten wie man so etwas realisieren könnte,
aber Heap und Linked List scheinen mir nicht die richtigen Mittel zu
sein (lehrt mich was besseres, wenn dies nicht stimmt).
Wenn ich jetzt meinen Code betrachte, dann müsste ich die Pointer nach
dem erstellen jeweils mit NULL initialisieren, so dass ich nachher
überprüfen kann ob an einer Stelle schon ein Paket abgelegt ist oder
nicht?!
Wenn ich die Funktion nr_of_packets so abändere, dass immer 0 zurück
gegeben wird, und eigentlich jedes Mal so quasi zur Sicherheit neue
Paket-Pointer erstellt werden (was sicher nicht sehr gut ist, aber mal
zum Testen woran es liegt) dann werden zwar sehr brav immer neue
Pakete-Pointer erstellt, aber bei <---1 gibt es trotzdem eine Access
Violation, wenn ich das Paket nr 1 erstellen will. Deshalb glaube ich
immer noch, dass vorher (beim realloc) was schief gehen muss, denn
aufgerufen wird dies zwar aber irgendwie macht es nicht das was es
soll?!
Danke für Eure Geduld!
Jorge wrote:
> Du hast ja auch recht mit deinen Aussagen. Es gibt aber eine Sichtweise> unabhängig von Bit und Byte und das hat wie du es auch schon> angesprochen hast etwas mit der Persönlichkeit des Programmierers zu> tun. Jeder hat natürlich seinen individuellen Stil und kommt damit> zurecht.
Du philosophierst mir hier zuviel.
Daher möchte ich meinen Standpunkt wie folgt zusammenfassen:
Ich glaub dir schon, dass du auf dem einen oder anderen System
mal in Schwierigkeiten mit der Library Implementierung für
realloc gestossen bist.
Daraus aber die generelle Empfehlung abzuleiten, realloc nicht
zu benutzen, ist weit, weit, weit über das Ziel hinausgeschossen.
> Wenn jemand den Umgang mit realloc aus dem ff beherrscht darf er das> gerne verwenden,
Wenn jemand mit malloc und free klar kommt, gibt es keinen Grund
auf realloc zu verzichten. Kommt er mit realloc nicht klar, dann
kommt er auch nicht mit malloc/free bzw. dynamischer Speicher-
verwaltung nicht klar. Da es aber in C keine Alternative dazu gibt
(Alles am Stack statisch zu allokieren ist keine Alternative),
muss er den Umgang mit dynamischen Strukturen lernen. Das hat aber
nichts mit realloc an sich zu tun.
COMPILIERENli wrote:
> Ich kenne nicht alle Möglichkeiten wie man so etwas realisieren könnte,> aber Heap und Linked List scheinen mir nicht die richtigen Mittel zu> sein (lehrt mich was besseres, wenn dies nicht stimmt).
Linked List wäre nicht schlecht. Aber deine gewählte Systematik
geht auch.
> Wenn ich jetzt meinen Code betrachte, dann müsste ich die Pointer nach> dem erstellen jeweils mit NULL initialisieren,
Nein.
Es geht um die Funktion nr_of_packets. Die hast doch du
geschreiben, oder nicht?
Was macht die?
Sie geht das Pointer Array durch um rauszufinden wie gross das
Array ist. Soweit so gut. Aber woran erkennt sie denn das Ende
des Arrays? Indem dort ein NULL Pointer stehen muss.
zb. so was
+---------+
| o-------------------> Daten
+---------+
| NULL |
+---------+
Merkst du was?
Du hast einen Nutzpointer, der auf Daten zeigt. Und zusätzlich
benötigst du noch einen NULL Pointer im Array, der das Ende
markiert. Bei 1 Nutzpointer, muss das Pointerarray also für
2 Pointer allokiert werden.
Das macht deine Allokierungsfunktion aber nicht. Und daher kann
nr_of_packets die Arraygröße nicht richtig bestimmen und daher
kommt dann in weiterer Folge alles durcheinander.