Verständnisproblem bei Memory Allocation

Hi,

ich komme eigentlich aus dem Java-Bereich (unter dem gleichen Nick bis zum GAU unter www.java-forum.org aktiv gewesen), muss mich aber gerade mit gegebenem C-Code auseinandersetzen.
Die folgende Methode bereitet mir Schwierigkeiten (man übergibt ihr zwei Zeilen-Indizes einer 2D-Matrix, um nachher gewünschte Spaltenwerte innerhalb dieses Zeilen-Bereiches im allokierten Vektor abzuspeichern):

{
	FLT *v;

	v=(FLT *)malloc((unsigned) (nh-nl+1)*sizeof(FLT));
	if (!v) {
	    printf("allocation failure in vector()
");
		exit(1);
    }		
	return v-nl;
}```

Fragen:
1.) Hat das einen besonderen Grund, warum man die Datentypen groß schreibt?
2.) Prinzipiell ist mir Zeile 5 klar. Aber warum schreibt man nicht einfach so etwas wie `float v[nh-nl+1];`?
3.) Bei Zeile 10 setzt es bei mir leider aus. Mit v verweist man doch auf die Adresse des 1. Arrayelements; wieso zieht man davon nl ab?

Vielen Dank für Eure Hilfe und sorry für die vielen Fragen!

Gruß,
Wang

[quote=Wang]1.) Hat das einen besonderen Grund, warum man die Datentypen groß schreibt?[/quote] In C sind Namen Case-Sensitive Also muss der Datentyp FLT irgndwo anders definiert sein. Ich denke mal dass das eine Konvention ist (ähnlich wie bei den Generics-Typen in Java).

[quote=Wang;83800]2.) Prinzipiell ist mir Zeile 5 klar. Aber warum schreibt man nicht einfach so etwas wie float v[nh-nl+1];?[/quote] Womöglich ist FLT gar kein primitiver Datentyp sondern ein struct, die Implementierung lässt jedenfalls zu das später zu ändern. (YAGNI?)

[quote=Wang;83800]3.) Bei Zeile 10 setzt es bei mir leider aus. Mit v verweist man doch auf die Adresse des 1. Arrayelements; wieso zieht man davon nl ab?[/quote]Das ist natürlich nur geraten aber womöglich möchte jemand mit Index 1 anfangend auf das Array zugreifen anstatt mit Index 0:if(index){ vFLT = vectFLT[index*nl];}

bye
TT

Vermutlich steht irgendwo oben (oder in einem Header, unfindbar versteckt) ein
#define FLT float
oder (besser) vielleicht ein entsprechendes typedef. Sowas macht man manchmal, um z.B. schnell zwischen der Verwendung von ‚float‘ und ‚double‘ hin- und her schalten zu können.

2.) Prinzipiell ist mir Zeile 5 klar. Aber warum schreibt man nicht einfach so etwas wie float v[nh-nl+1];?

Weil es nicht geht :slight_smile: (Mehr ist dazu eigentlich nicht zu sagen - außer vielleicht noch, dass Arraygrößen in C zur compilezeit feststehen müssen - andernfalls muss man den Speicher mit malloc/free selbst verwalten. (Abgesehen davon, dass ein lokal deklarierter array nach dem Verlassen der funktion ja schon nicht mehr gültig wäre)).

3.) Bei Zeile 10 setzt es bei mir leider aus. Mit v verweist man doch auf die Adresse des 1. Arrayelements; wieso zieht man davon nl ab?

Ja, die Funktion finde ich gelinde gesagt etwas fragwürdig. Angenommen, man ruft sie mit den Parametern nl=10 und nh=15 auf. Dann wird dort platz für 6 float-Werte allokiert. Durch das ‚v-nl‘ am Ende wird aber nicht der Pointer auf diesen allokierten Speicher zurückgegeben, sondern ein Pointer, der um ‚nl‘ Stellen „nach links“ verschoben ist.



                               | Hierhin wird der Speicher ge'alloct
                               | 
|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|

    
                               | Das sieht dann so aus
                               | 
                               v
|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|_|_|_|_|_|_|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|


           
           | Aber ein Pointer an DIESE Stelle wird zurückgegeben!
           | 
           v-nl
           |
|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|_|_|_|_|_|_|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|

Was damit erreicht wird, ist eigentlich klar: Bei einem Aufruf wie
FLT *p = vector(10, 15);
wird ein Pointer zurückgegeben, der auf einen ungültigen Speicherbereich zeigt. Aaaber man kann mit diesem Pointer dann trotzdem arbeiten: Wenn man dort mit sowas wie
p[10] = 123;
daten reinschreibt, dann landen diese Daten ja tatsächlich in dem Bereich, wo wirklich Speicher allokiert wurde!

(Der Grund dafür ist, dass für Array-Zugriffe in C gilt
array** = *(array + i)
und damit durch das [10] dieses ‚-nl‘ aus der Funktion quasi wieder „ausgeglichen“ wird)

Ich persönlich halte das aber für ziemlich gewagt. Damit kann man sich IMHO schon SEHR leicht Bugs reinhauen, wenn man den Pointer doch mal mit p[0] = 123; verwendet und man damit in ungültigen Speicher reinschreibt…

BTW: Es gilt übrigens tatsächlich
array** = *(array + i) = *(i + array) = i[array]
und man kann wirklich sowas schreiben wie

float *array = allocateIt();
for (int i=0; i<10; i++)
{
    i[array] = 123; // <- geht!
}

aber… nur weil man etwas KANN, sollte man das nicht auch gleich TUN :wink: )

Danke an Euch beide, jetzt ist mir alles klar!

Schön, dass man hier auch auf bekannte User trifft, Marco! :wink:

Ja, ich hatte tatsächlich übersehen, dass am Dateianfang #define FLT double steht (das nötige Feeling für C fehlt mir noch)…

Gruß,
Wang

jain - das Problem ist eher das die Zahlen float/double bzw. char/int/long je nach Compiler unterschiedlich definiert sind. Es ist nur eine Reihenfolge definiert. sizeof() char >= short >= int >= long. Auf einem SHARC ist selbst ein char mit 32 Bit definiert (das ist Lustig wenn man ein char Array an einen Prozesser übermittelt der char nur mit 8 Bits kennt :twisted:). Daraus ergibt sich eben das auch int 32 Bit sein muss. Long kann schon wieder 64 Bit sein, ist es aber nicht.

Durch solche Aktionen mit dem typedef wird versucht einen Programmcode immer mit den entsprechenden Bit-Breiten zu erzeugen. Dazu gibt der Standard den Header „typedefs.h“ vor. Einfach da mal reinschauen wie das funktioniert. D.h. INT != int

na komm, ein bischen mehr geht schon - das geht nicht, weil das Array auf dem Stack landet (Sichtbarkeit). Man kann zwar einen Pointer drauf zurück reichen. Der wird aber bei return sofort ungültig.

nö - müssen sie auch nicht


void foo(int len) {
        char data[len];
        for(int i = 0; i < len; i++) data** = '\0';
}
int main() {
        foo(20);
        int blub; // irgend welchen wilden Müll aus dem Speicher holen
        foo(blub);
        return 0;
}

zu Punkt 3 muss ich mich gnadenlos an Marco anschließen - das ist irgendwie komischer Murks.

hand, mogel

Das hatte ich ja auch erwähnt, aber… zugegeben, das

nö - müssen sie auch nicht

hatte mich jetzt schon irritiert, aber … das schlaue Internet sagt auf eine schnelle Suche hin, dass Variable Arraylängen von ISO C 89 zwar NICHT unterstützt sind, von ISO C 99 aber DOCH, daher: Ich bezog mich auf ersteres :stuck_out_tongue:

Ist aber schon erstaunlich, wie schnell man bei so einer Sprache „raus“ kommt: Vor kurzem hab’ ich mal versucht, zum testen was in reinem ANSI-C zu schreiben. Nachdem ich eine Zeile
// Auskommentiert
hatte, hagelte es auf einmal unerklärliche Fehlermeldungen.

Tja…

Die //-Kommentare GAB es in ANSI-C nicht! Dort musste man IMMER /* die */ verwenden!

Kraft meiner nicht vorhanden Servermacht, sei Dir dies genehmigt. :smiley:

:twisted: jap - bei allen Sprachen die man verwendet immer Up-To-Date zu bleiben ist verdammt schwierig. Bei mir sind es hauptsächlich C/C++, Java, C#. Die neuen Sprachfeatures von Java und C# habe ich noch nicht so richtig verinnerlicht - aber den Sinn verstanden. Die neuen C++ Features - ja es gibt sie :slight_smile:

Du meinst die von http://en.wikipedia.org/wiki/C%2B%2B11 und http://en.wikipedia.org/wiki/C%2B%2B14 ? Joa, da ist es mit einem Durchlesen der Wiki-Artikel sicher nicht getan… -_- Als ich die mal in einer Präsentation aufgelistet gesehen habe, dachte ich mir aber sowas wie „Super, noch ein paar Jahre, dann wird in C++2x endlich all das enthalten sein, was es in Java schon seit Version 1.0 gibt“ :smiley: