Können Rückgabewert und Parameter bei Funktion gleich sein?



  • Hallo,

    ich habe eine kurze Frage: Kann in einer selbstgeschriebenen Funktion der Rückgabewert (also die Variable, wo das Ergebnis abgespeichert wird, s.u.) und einer der Parameter gleich sein? In unten angegebenem Beispiel möchte ich die Funktionen so allgemein wie möglich halten und mir ist nur diese Möglichkeit eingefallen.
    Ich nutze das Kopieren in Verbindung mit einem anderen Programm (das in C aufgerufen und wieder geschlossen wird). Leider ruft das Schließen dieses Programms eine Speicherverletzung hervor: "runtime error R6016 - not enough space for thread data". Dies geschieht allerdings nur, wenn ich die Kopieren-Funktion in dieser Form aufrufe. Bei der Alternative passiert es schon nicht mehr und bei der Speicherallokation auch nicht...

    Also nochmal meine Fragen:
    1. Ist es in irgendeiner Hinsicht problematisch, die gleiche Variable als Rückgabewert und Parameter zu verwenden?
    2. Fällt jemandem ein, warum die Speicherverletzung auftreten könnte? Warum tritt sie bei Verwendung der Kopieren-Funktion auf, aber nicht bei der Speicher-Funktion?

    Vielen Dank für die Hilfe!

    #include <stdio.h>
    #include <stdlib.h>
    
    double *feld1;
    double *feld2;
    
    double* kopieren ( double *alt, double *neu, int dim );
    double* speicher ( double *zeiger, int dim );
    
    int main (void) {
    
      int i;
    
      feld1 = speicher ( feld1, 5 );
      feld2 = speicher ( feld2, 5 );
    
      for ( i = 0; i < 5; i++ )
        feld1[i] = i;
    
      feld2 = kopieren ( feld1, feld2, 5 );
    
      for ( i = 0; i < 5; i++ )
        printf ( "%.1f ", feld2[i] );
    
      return 0;
    }
    
    double* kopieren ( double *alt, double *neu, int dim ) {
    
      int i;
    
      for ( i = 0; i < dim; i++ )
        neu[i] = alt[i];
    
      return neu;
    }
    
    double* speicher ( double *zeiger, int dim ) {
    
      zeiger = ( double * ) malloc ( dim * sizeof ( double ) );
    
      return zeiger;
    }
    

    Alternative mit zusätzlichem Array:

    double* kopieren ( double *alt, double *neu, int dim ) {
    
      int i;
      double *neu2;
    
      neu2 = speicher ( neu2, dim );
      for ( i = 0; i < dim; i++ )
        neu2[i] = alt[i];
    
      return neu2;
    }
    


  • double* speicher ( double *zeiger, int dim ) {

    zeiger = ( double * ) malloc ( dim * sizeof ( double ) );

    return zeiger;
    }

    Die Variable zeiger macht hier keinen Sinn als Parameter, daher
    umschreiben in

    double* speicher ( int dim ) {
    
      zeiger =  malloc ( dim * sizeof ( double ) );
    if ( !zeiger )
    {
    // Fehlerbehandlung !
    }
      return zeiger;
    }
    

    double* kopieren ( double *alt, double *neu, int dim ) {

    int i;

    for ( i = 0; i < dim; i++ )
    neu[i] = alt[i];

    return neu;
    }

    Hier macht es keinen Sinn, den Zeiger neu zurückzugeben, also
    umschreiben in

    void kopieren ( double *alt, double *neu, int dim ) {
      int i;
      for ( i = 0; i < dim; i++ )
        neu[i] = alt[i];
    }
    

    Oder cooler:

    void kopieren ( double *alt, double *neu, int dim ) {
      memcpy ( alt, neu, dim * sizeof ( double ) );
    }
    


  • Bei dem Code handelt es sich natürlich normales C, kein C# - sorry!



  • Es ist kein guter Stil, speicher dynamisch in einer Funktion zu allokieren. Man weiss nicht, was passiert, und vergisst so u.U. den Speicher wieder freizugeben.
    Der Gewinn gegenüber calloc ist praktisch nicht vorhanden:

    /*ein cast zu double* ist NICHT notwendig!!!!111elf*/
    double* zeiger = calloc(5, sizeof(double));
    

    Wozu den Wert zurückgeben?

    void kopieren(double* quelle, double* ziel);
    
    zeiger1 = calloc(5, sizeof(double));
    zeiger2 = calloc(5, sizeof(double));
    kopieren(zeiger1, zeiger2);
    
    void kopieren(double* quelle, double* ziel)
    {...}
    

    Quelle und ziel zeigen ja in der Funktion bereits auf die zu Kopieren zu benutzenden Speicherbereiche.



  • Big Bam Bubie schrieb:

    Oder cooler:

    void kopieren ( double *alt, double *neu, int dim ) {
      memcpy ( alt, neu, dim * sizeof ( double ) );
    }
    

    Hi Bruder!
    Andersrum:

    memcpy ( neu, alt, dim * sizeof ( double ) );
    

  • Mod

    @Tachyon:

    /*die mehrfache explizite Angabe des Typs ist NICHT notwendig!!!!111elf*/
    double* zeiger = calloc(5, sizeof(*zeiger));
    


  • camper schrieb:

    @Tachyon:

    /*die mehrfache explizite Angabe des Typs ist NICHT notwendig!!!!111elf*/
    double* zeiger = calloc(5, sizeof(*zeiger));
    

    Jo. Ist besser.



  • Tachyon schrieb:

    Es ist kein guter Stil, speicher dynamisch in einer Funktion zu allokieren.

    ... das ist doch Käse.
    Ein Programm, das aus mehreren tausend Zeilen ( plus/minus ) Code besteht.
    Wohin willst du die Speicherreservierung auslagern wenn nicht in Funktionen, auf den Mond?



  • ach komm... schrieb:

    Tachyon schrieb:

    Es ist kein guter Stil, speicher dynamisch in einer Funktion zu allokieren.

    ... das ist doch Käse.
    Ein Programm, das aus mehreren tausend Zeilen ( plus/minus ) Code besteht.
    Wohin willst du die Speicherreservierung auslagern wenn nicht in Funktionen, auf den Mond?

    Ja. 😃 Da ist noch viel Platz.

    Ne, im Ernst. Bei großen Programmen würde ich mit Handles arbeiten - oder noch besser, es in Strukuturen verpacken - und zu Funktionen die irgendwie Resourcen anfordern auch passende freigabe Funktionen als Gegenstück liefern.
    Allerdings ist Deine Aussage etwas aus dem Kontext gerissen, weil ich mich auf das konkrete, einfache Beispiel bezog.



  • Danke für die Antworten. Ihr habt natürlich Recht - es macht wenig Sinn das doppelt zu machen...
    Allerdngs muss ich dann nochmal den Zeiger definieren, oder?

    double* speicher ( int dim ) {
    
      double *zeiger;
    
      zeiger = ( double * ) malloc ( dim * sizeof ( double ) );
    
      return zeiger;
    }
    

    Das mit dem memcpy funktioniert gut, das mit der Reihenfolge hatte ich auch schon bemerkt.

    Was spricht denn gegen malloc? Wo liegt der große Unterschied zu calloc? Ich muss mehrere Arrays erzeugen, auch mehrdimensionale. Und da erschien es mir einfacher, eine Funktion zu schreiben, die auch gleich errorchecking enthält (hab ich zur Vereinfachung im Bsp weggelassen)...

    Leider tritt trotz der besseren Kopiererei immer noch meine Speicherverletzung auf - es muss also doch irgendwas anderes sein. So wie ich es bisher gelöst hatte, muss es auch nicht zwangsläufig zu einem Problem führen, oder?

    So oder so vielen Dank!



  • Der Fehler muss an anderer Stelle liegen.
    Greifst du auf den Speicherplatz von einem anderen Programm aus zu?
    Wohlmöglich, nachdem das allokierende Programm beendet ist?



  • Also, der Ablauf ist grob so:
    1. zwei Arrays (A und 😎 anlegen
    2. externes Programm starten
    3. dieses schreibt Werte in das eine Array (A)
    4. die Werte von A nach B übertragen
    5. das externe Programm beenden
    6. B ausgeben

    die Schritte 3 und 4 können u.U. mehrfach hintereinander ausgeführt werden, je nach Ergebnis von 3 wird 4 ausgeführt oder auch nicht. Der Fehler tritt immer bei 5 (und nicht bei 6) auf. Wenn ich 4 weglasse läuft alles einwandfrei... Ich seh da den Zusammenhang nicht so richtig 😕



  • wie übergibst du die adresse des arrays A an das externe programm?



  • versuch mal ein funktionierendes minimalbeispiel zu programmieren.



  • Über eine Funktion von dessen Funktionenbibliothek:

    XPRSgetlpsol ( prob, A, NULL, NULL, NULL );
    

    Das Programm löst ein Optimierungsproblem (prob) und schreibt die Lösungswerte der Variablen in das Array A.



  • ja, dann würde ich auch erstmal ein minimalprogramm schreiben, das nur das beschreiben des arrays macht. an dem von dir geposteten code liegt es in der form jedenfalls nicht.



  • Das Minimalprogramm läuft - was mich nicht grade glücklicher macht 😞
    Danke trotzdem für eure Hilfe und die Bestätigung, dass mein Code richtig ist. Ich werde einfach mal den ganzen Rest durchleuchten ächz


Anmelden zum Antworten