Vinzenz Mai: Anfängerfrage zu Strings in C

Beitrag lesen

Hallo,

*
* Seiteneffekt: Speicher auf dem Heap wird allokiert
*/
int SplitLinesCsv(char* line, char** result) {

warum "char* line" und nicht "char *line"?

Reine Geschmackssache, für den Compiler ergibt sich kein Unterschied.
Meine Variable heißt line und hat den Typ "Zeiger auf char". Sie ist nicht vom Datentyp char und heißt *line. Für *mich* ist meine Notation verständlicher und lesbarer.

auf "char"?

Wie werden denn in "C" Variablen per Referenz übergeben? Müssen sie vorher global definiert sein.

Nein, natürlich nicht, wieso auch? Für globale Variablen gilt (sprachunabhängig): So wenige wie möglich, nur so viele, wie unbedingt notwendig. In vielen Fällen kommt man ohne globale Variablen aus.

C verwendet call by value. Willst Du den Inhalt einer "übergebenen" Variablen ändern, so übergibst Du eben einen Zeiger auf den Speicher, in dem diese Variable steht, d.h. die (Speicher)adresse dieser Variablen.

Typisches Beispiel für so einen Zweck ist eine Tauschfunktion:

  
/**  
 * tausche  
 * tauscht den Inhalt der beiden übergebenen Variablen  
 *  
 * @param a: Zeiger auf die erste Zahl  
 * @param b: Zeiger auf die zweite Zahl  
 * Anmerkung: C kann maximal einen Wert zurückgeben,  
 * es müssen aber zwei Variablen geändert werden. Daher erfolgt der  
 * Aufruf über call by reference, indem Zeiger auf die Variablen übergeben  
 * werden.  
 *  
 * Code ungetestet, vermutlich wie vor etwa 20 Jahren mal in der ersten oder  
 * zweiten Woche der C-Programmierung gelernt ...  
 */  
void tausche(int* a, int* b) {  
    // wir benötigen einen Zwischenspeicher  
    int merker;  
    // schreibe den Inhalt der Variablen a in den Zwischenspeicher  
    merker = *inhalt;   // schreibe in merker das, auf was inhalt zeigt.  
    // schreibe in den Speicher, auf den a zeigt, das was dort steht, worauf  
    // b zeigt  
    *a = *b;  
    // schreibe nun an die Stelle, auf die b zeigt, das Zwischengespeicherte.  
    *b = merker;  
}  
  
// Aufruf:  
  
// auf argc und argv verzichte ich einfach mal ...  
int main(void) {  
    int x = 4;  
    int y = 17;  
  
    // übergebe der Tauschfunktion die Adressen der zu tauschenden Variablen  
    tausche(&x, &y);  
  
    // gebe die beiden aus ...  
    printf("x = %d, y = %d \n", x, y);  
    // Ausgabe:  
    // x = 17, y = 4  
}  

Wenn Du nun bei Deinem CSV-Kram von vornherein einen Puffer anlegst:

// Wir reservieren Platz für maximal 20 Spalten. Jeder Eintrag darf maximal
// 1024 Zeichen Nutzinhalt haben (plus ein Zeichen für das Nullbyte, das die
// Zeichenkette beendet)
char csv[20][1024+1];

Wenn Du so den Speicher vorbereitest, brauchst Du keinen Speicher dynamisch anzufordern (und wieder freizugeben), dafür hast Du etwas mehr als 20 Kilobyte verbraten und bist unflexibel, weil Du nicht mehr als 20 Spalten verarbeiten kannst und kein einziger Eintrag mehr als ein Kilobyte Nutzdaten enthalten darf (sonst kommt es ruckzuck zu einem buffer overflow, wenn Du nicht aufpasst) ...

Dagegen hat die dynamische Speicherverwaltung den Nachteil, dass *nichts und niemand* Dir die Arbeit abnimmt, den von Dir angeforderten Speicher wieder freizugeben. Da kommt es gern einmal zu Speicherlecks, d.h. die Anwendung fordert immer wieder (meist kleine) Speichermengen an, die nicht mehr freigegeben werden, obwohl sie nicht mehr verwendet werden. Viel schlimmer, Du hast wahrscheinlich keinen Zeiger mehr auf diesen Speicher und kannst ihn daher auch nicht mehr freigeben. Das erfolgt erst mit Beendigung des Programmes.

Freundliche Grüße

Vinzenz