"Christmas - the time to fix the computers of your loved ones" « Lord Wyrm

ICH HASSE ZEIGER (in C)

Armax 15.02.2007 - 09:05 2923 20
Posts

Armax

OC Addicted
Registered: Apr 2004
Location: .
Posts: 1058
Moin!
Intro
Ich entschuldige mich erstmal für den threadtitel, aber nachdem ich gestern fast den ganzen tag mit den problem verschissen habe, ist halt doch noch genug wut übrig. Wollt mein problem gestern schon posten, aba i war so heiß, dass des prob. nit amal formuliern hab können... hoffentlich gehts heut besser... ;)
Grundsätzlich bin ich amal ein Anfänger im C-Programmieren und hab mich vorher nur mit Java beschäftigt. Deshalb auch die großen Schwierigkeiten mit Zeiger.

Das Problem
Wenn ich von ner Funktion einen Zeiger auf ein Datenobjekt zurückbekomme, wie les ich dann von diesem die eigentlichen Daten aus?
Prinzipiell is die Funktion die ich verwende laut Doku so definiert:
Code:
 size_t bufferFunction_read(... , char *dest, size_t cnt) 
wobei 'dest ... a pointer to a buffer where data read from the buffer will go', 'cnt ... the number of bytes to read' und der return Wert 'the number of bytes read, which may range from 0 to cnt.' is.
Da ich die Daten von dest als float-werte auf den Bildschirm ausgeben will hab ich schon mal folgendes probiert:
Code:
void *tempBuffer = malloc(sizeof(float));
bufferFunction(...,tempBuffer,sizeof(float));
printf("%2.1f ",tempBuf);
-> Funkt aba nit! Die ausgelesenen float-Werte sind allesamt '0.0'
Dann hab ich probiert den ausgelesenen tempBuf einen Grundtyp zu zuweisen
Code:
//same as above
printf("%2.1f ",(float *)(tempBuf));
-> wieder nur 0.0-Werte! *hmpf*

Vielleicht hab ich auch nen Fehler schon beim Schreiben auf den Buffer. Das funktioniert laut doku folgendermaßen
Code:
size_t bufferFunction_write(...,char *src, size_t cnt)
wobei wiederum 'src ... a pointer to the data to be written to the buffer', 'cnt...the number of bytes to write' is und als return Wert 'the number of bytes write, which may range from 0 to cnt' zurückgegeben wird.
Da hab ich folgendes probiert:
Code:
float *val = malloc(100*sizeof(float));
for(int i=0; i < 100; i++) {
    val[i] = 1.0;
}
...
c= bufferFunction_write(...,(void *)(&val[i]),sizeof(float));
Da der return Wert immer 4 bytes sind schätz i amal dass die Werte richtig eingelesen wurden, oda? Außerdem hab ich mir mit
Code:
while(val[i] !=0)  { 
      printf("%2.1f ", val[i]);
      i++;
}
schon die werte angschaut -> passt!

sodala... mit meinem Latein bin ich auf jeden Fall vollkommen am Ende... bitte vielmals um Rat! :(

beaucoup tia, armax
Bearbeitet von Armax am 16.02.2007, 14:39

that

Moderator
Hoffnungsloser Optimist
Avatar
Registered: Mar 2000
Location: MeidLing
Posts: 11338
Zitat von Armax
Wenn ich von ner Funktion einen Zeiger auf ein Datenobjekt zurückbekomme, wie les ich dann von diesem die eigentlichen Daten aus?

int i = 42; // i ist ein int auf dem Stack, mit dem Wert 42
int *p = &i; // *p ist ein int, und zwar ein Alias für i

int *p2 = malloc(sizeof(int)); // *p2 ist ein int auf dem Heap
int *p3 = malloc(10*sizeof(int)); // *p3 ist ein int auf dem Heap, dem noch 9 weitere folgen
// p3[0] entspricht *p3, p3[1] entspricht *(p3+1), usw...


Bei deiner Funktion bekommst du gar keinen Zeiger zurück, du gibst einen Zeiger hinein, wo die Funktion dann die Daten ablegt. Sowas ist üblich in C. Daher geht sowas z.B. auch ohne malloc:

char buffer[100];
bufferFunction_read(... , buffer, sizeof(buffer));

Das Array kann man hier so wie den Pointer auf das erste Element behandeln, also entspricht es &(buffer[0]).

C ist es völlig egal, welche Datentypen du dann wirklich in den Speicher schreibst, ähnlich wie bei Assembler glaubt dir der Compiler blind:

char buffer[100];
bufferFunction_read(... , buffer, sizeof(buffer)); // wir lesen 100 chars...
float *pf = (float*) buffer; // ...und behaupten jetzt, am Anfang im buffer steht ein float

Hier wirst du mit *pf wirklich ein float bekommen, dessen Wert sich aus den ersten 2 Bytes im buffer zusammensetzt. Wenn du den Wert nicht auch als float vorher in den Buffer hineingeschrieben hast, kommt da Unsinn heraus.


Zitat von Armax
Da hab ich folgendes probiert:
Code:
float *val = malloc(100*sizeof(float));
for(int i=0; i < 100; i++) {
    val[i] = 1.0;
}
...
c= bufferFunction_write(...,(void *)(&val[i]),sizeof(float));

Woher nimmst du hier i außerhalb der Schleife, und warum übergibst du nicht gleich alle 100 Werte auf einmal?

Armax

OC Addicted
Registered: Apr 2004
Location: .
Posts: 1058
Zitat von that
Woher nimmst du hier i außerhalb der Schleife, und warum übergibst du nicht gleich alle 100 Werte auf einmal?
stimmt natürlich! :bash:
ich depp hab das mit der for-schleife eingebaut, weil ich überprüfen wollt ob er eh imma brav 4 bytes (für float) einliest. Habs jetzt folgendermaßen umgebaut und jetzt funktioniert :cool: *shake* *shake*

Code:
float *val = malloc(100*sizeof(float));
void *tempBuffer = malloc(100*sizeof(float));
// Einlesen in val wie vorher
bufferFunction_write(...(void *)(val),100*sizeof(float));
bufferFunction_read(tempBuffer,100*sizeof(float));
float *pf = (float *)tempBuffer;
printf("%2.1f ",pf[i]);

so einfach wärs gangen: :fresserettich:
Anscheinend hab ich gestern den wald vor lauter bäumen nimma gsehen

anyway: vielen dank that! :)

fresserettich

Here to stay
Registered: Jul 2002
Location: hier
Posts: 5377
Zitat von Armax
so einfach wärs gangen: :fresserettich:
Anscheinend hab ich gestern den wald vor lauter bäumen nimma gsehen

anyway: vielen dank that! :)
ist oft so beim programmieren, ist mir auch schon öfters so gegangen
oft ist es einfach mal besser eni bisschen pause zu machen und dann ist es meistens eh sonnenklar

Armax

OC Addicted
Registered: Apr 2004
Location: .
Posts: 1058
UNSOLVE

hab nämlich schon wieder so ein friigin Zeiger-Problem und (wahrscheinlich weil's Fr. nachmittag is) steh ich voll auf der Leitung! :(

Diesmal geht's um 2 dimensionale Zeiger. Warum krieg ich bei nachfolgendem Code immer nen "Segmentation fault" beim Ausführen?
Code:
int main(int argc, char *argv[]) {
     unsigned int i,j;
     float **test;
     test = (float **) malloc( 2 * 100 * sizeof(float));
     for (i=0; i < 2; i++) {
           for (j=0; j < 100; j++) {
                 *(test[i]+j) = 1.0;
           }
     }
}
Wie gsagt schluckt das zwar der Compiler, aber beim Ausführen haut's ihn bei *(test[i]+j) mit dem Segfault auf... :(
plz, help!

tia, armax

mat

Administrator
Legends never die
Avatar
Registered: Aug 2003
Location: nö
Posts: 25422
für ein 2-dimensionales array brauchst du nur einen einfach pointer. der zugriff erfolgt dann per index i. wenn du x und y position, wie bei einer matrix benötigst, dann kannst du per x = i % width und y = i / width (gecastet auf integer natürlich) darauf zugreifen.

einen doppelpointer brauchst du in diesem fall nur wenn du ein array von mehreren arrays hast.

Armax

OC Addicted
Registered: Apr 2004
Location: .
Posts: 1058
Sweeet! Danke mat! funkt...
i werd den thread nit gleich wieder solved-taggn... wer weiß wie oft i mit den zeigern noch auf kriegsfuss steh! ;)

Armax

OC Addicted
Registered: Apr 2004
Location: .
Posts: 1058
Hab schon wieder so nen Zeiger-Krampf... :(

Diesmal geht's um die Verwendung von komplexen Zahlen. Gemäß einer Libary (also kann ich die Dimension diesmal nicht verändern), werden diese folgendermaßen abgespeichert:
Code:
zahl[k][0] //real Teil von zahl[k]
zahl[k][1] //imaginär Teil von zahl[k] 
In meinem Programm möcht ich jetzt mit fwrite _nur_ die Real- (bzw. Imaginär) Teile von einem Array aus komplexen Zahlen abspeichern. Aber wie übergibt man den Zeiger der nur auf die 2.Dimension verweißt?

der prototyp von fwrite:
Code:
int fwrite(void *buf, int size, int n, FILE *fp);
also würds bei mir ca. so ausschauen:
Code:
fwrite(buffer[0]???, sizeof(float), 10, fp);
... sollte von 10 werten den Realteil nehmen und in der datei von fp speichern. sizeof(float) deshalb weil zahl[k][1/0] ein float wert ist.

beaucoup TIA , armax

mat

Administrator
Legends never die
Avatar
Registered: Aug 2003
Location: nö
Posts: 25422
du musst natürlich mit einer for-schleife arbeiten. wie soll fwrite die imaginären teile auslassen?

damit du nicht 100x fwrite benutzt kannst du dir vorher ein float * array mit den realteilen füllen und dann mit einem aufruf alle per fwrite in die datei schreiben.

Armax

OC Addicted
Registered: Apr 2004
Location: .
Posts: 1058
hmm... eigentlich wollt ich mir eben das mit der for-schleife bzw. real-teil rauslesen ersparen. Immerhin handelt es sich dabei um ein laaaaanges array und das würd ordentlich Rechenzeit kosten (und bei meiner anwendung ist "rechenzeit" ein schmutziges wort ;)). Deshalb wollt ich eigentlich fwrite überhaupt verwenden, weil man da schön blockweise die Daten rausschreiben kann.
Mittlerweile hat mich das mit den Zeigern so gnervt, dass ich mal in nem Testprogramm probiert habe "buffer" als Zeiger ganz zu übergeben. Das Resultat: Es wird abwechselnd ein real und imaginär Teil geschrieben... Zur Not muss ich wohl eher damit leben ...

thx anyway mat!

mat

Administrator
Legends never die
Avatar
Registered: Aug 2003
Location: nö
Posts: 25422
da das alles im speicher passiert wäre es im gegensatz zu mehreren fwrite aufrufen um vielfaches schneller. wenn du dir beides sparen willst dann musst du dir eine eigene datenstruktur überlegen. da diese durch die library scheinbar vorgegeben wird und ich dein programm nicht kenne scheint mir mein erster vorschlag noch immer am schnellsten und einfachsten zu sein.

that

Moderator
Hoffnungsloser Optimist
Avatar
Registered: Mar 2000
Location: MeidLing
Posts: 11338
Zitat von Armax
Immerhin handelt es sich dabei um ein laaaaanges array und das würd ordentlich Rechenzeit kosten (und bei meiner anwendung ist "rechenzeit" ein schmutziges wort ;)).

I/O kostet wesentlich mehr Zeit als die paar CPU-Zyklen, um ein paar Bytes zusammenzukopieren.

Armax

OC Addicted
Registered: Apr 2004
Location: .
Posts: 1058
@ mat: nnnjaaargg... du hattest recht! :)
da ich die Daten sowieso noch einzeln dividiern mußte, hab ich jetzt real und imaginär Teil doch in verschiedenen Arrays gespeichert und diese schreibe ich dann mit fwrite raus...

@that: die einzige Alternative die ich zu fwrite kenn, is fprintf. Und weil das (afaik!) die Zahlen vorm Speichern einzeln in nen String verwandelt, dauert dass doch erheblich länger.

Prinzipiell funktionert jetzt mein Programmchen soweit (:dance: :dance: ) nur beim Beenden hab ich noch ein kleines Problem: Da in jedem mir bekannten C-Programm immer drauf hingewiesen wird, allokierte Speicherbereiche mit free() wieder freizugeben wollt ich das bei mir auch einbauen. Nur just dabei bekomm ich am Schluss vom Programm entweder einen Segfault oder einen glibc error. o_0 Wenn ich die betreffenden Zeilen wegkommentier, beendet das Programm anstandslos mit exit(0).
1.Frage: Wie schlimm ist es wenn man das mit free nicht macht? Bleiben dann die Arrays auch nach Beendigung des Programms im Speicher?
2.Frage: Kann es etwa sein, dass wenn ich folgenden Beispiel-Code hab...
Code:
test = (float *) malloc(10 * sizeof(float));
test2 = (int *) malloc(10 * sizeof(int));
for(k=0; k < 10; k++) {
test[k] =1.0;
}
test2 = (int *)(test);
free(test);
...danach auch test2 "ge-free-d" wurde? Wenn ja, bis zu wieviel Verweisschritten (wenn jetzt zb. test2 auch noch wohin kopiert wird) gilt dann ein free-Aufruf?

TIA, armax

mat

Administrator
Legends never die
Avatar
Registered: Aug 2003
Location: nö
Posts: 25422
1. antwort: sehr schlimm, der speicher bleibt belegt. solltest du auf alle fälle vermeiden.

2. antwort: der pointer zu test2 geht verloren, der speicherbereich bleibt allokiert. siehe antwort 1 :)

semteX

begehrt die rostschaufel
Avatar
Registered: Oct 2002
Location: Pre
Posts: 14594
nein, nicht möglich. allerdings zeigt test2 danach ins nichts.. und du hast an ungefreeten speicher herumfliegn...

edit: damn, owned
Kontakt | Unser Forum | Über overclockers.at | Impressum | Datenschutz