Funktion mit Char Array als Rückgabe



  • Hallo zusammen,
    Ich möchte das folgende Programm als Funktion schreiben.
    Es liest aus einer Datei Namen von Messwerten z.B Zac ein und soll diese dann in ein Char array schreiben.
    Leider komme ich nicht weiter und bekomme immer Speicherzugrifsfehler.
    Es funktioniert bis zu dem Punkt wo die Anzahl der Zeilen ausgegeben wird.
    Die Funktion soll als eingangsparameter den Dateinamen haben und als Rückgabewert einen Chararray.

    Danke für eure Hilfe

    [#include <stdio.h>

    char Kanalliste (char *Dateiname)
    {

    int c;
    int nl = 0;
    int z;
    char bezeichner[10];
    char Messbez[30][10]; /*char array für 30 Messwertbezeichnungen anlegen*/

    FILE *pdatei; /* Parameter Datei (kanal.ini) öffnen */
    pdatei = fopen(Dateiname, "r");

    if(pdatei == NULL) /* prüfen ob die Datei vorhanden -> wenn nicht vorhanden dann Rückgabe 0 */
    {
    printf ("Parameterdatei nicht vorhanden !\n");
    }

    if(pdatei != NULL)
    {
    while( (c=fgetc(pdatei)) != EOF)
    if (c == '\n')
    {
    ++nl;

    }
    printf("Anzahl der Zeilen:'%d'\n" ,nl);
    }

    pdatei = fopen(Dateiname, "r");
    for(z = 0; z < nl;z++) /* Schleife Namen der Meßwerte aus kanal.ini auslesen /
    {
    fgets(bezeichner,10,pdatei); /
    Namen der Meßwerte zeilen weise lesen mit fgets /
    chomp(bezeichner); /*Zeilenumbruch nach dem gelesenen Bezeichner aus Kanal.ini löschen*/
    strcpy (Messbez[z],bezeichner); /
    Messwertbezeichnungen in ein Array schreiben /
    }
    //printf("im array steht '%s'\n", Messbez[0]); /
    Test um anzuzeigen was im Struct steht kann später ausgeblendet werden */

    return (Messbez[z]);
    }
    /*Ende der Funktion*/

    int main(void)
    {
    char **ergebniss;
    char Dateiname[20]="kanal.ini";
    printf("im array steht '%s'\n", Dateiname);
    ergebniss = Kanalliste (Dateiname);

    printf("im array steht '%s'\n", ergebniss[0]); /* Test um anzuzeigen was im Array steht kann später ausgeblendet werden */
    return (0);
    }
    ]



  • Das ist in der Form nicht möglich. Eine Funktion kann kein Array zurückgeben, sondern höchstens einen Zeiger auf ein Array. Wenn dieser Zeiger auf ein funktionslokales Array zeigt (wie es hier der Fall wäre), das bei Verlassen der Funktion vom Stack genommen wird, ist der Zeiger danach sofort ungültig.

    Man kann mit structs einen Workaround bauen, beispielsweise

    typedef struct {
      char str[256];
    } string_buffer;
    
    string_buffer my_function(void) {
      string_buffer result;
    
      strcpy(result.str, "foo");
      return result;
    }
    

    Üblicher ist aber, den Speicher entweder vorher selbst anzulegen (wenn man die Länge zur Compilezeit kennt) und als Parameter hereinzureichen:

    int my_function(char *buffer, size_t n) {
      // Rückgabewert dann meistens zur Fehlerbehandlung.
      if(n == 0 || buffer == NULL) {
        return -1;
     }
    
      buffer[n - 1] = '\0';
      strncpy(buffer, "foobar", n - 1);
    
      return 0;
    }
    
    ...
    
    char buf[256];
    
    if(0 == my_function(buf, 256)) {
      puts(buf);
    }
    

    Oder, wenn man die Länge nicht kennt, den Speicher dynamisch anzufordern. In diesem Fall muss der hinterher von Hand freigegeben werden! Das sieht etwa so aus:

    char *my_function(void) {
      size_t ausreichend_platz = sizeof("foobar");
      char *result = malloc(ausreichend_platz);
    
      if(result != NULL) {
        strcpy(result, "foobar");
      }
    
      return result;
    }
    
    ...
    
    char *ptr = my_function();
    puts(ptr);
    free(ptr); /* <-- GANZ WICHTIG! */
    

  • Mod

    Seldon, deine zweite Variante ist weder üblich noch gut. Sie hat noch viel mehr Nachteile (und viel schlimmere) als den, den du nennst. Lieber ganz schnell vergessen.



  • Buffer + Länge findet man andauernd. Fehlercode als Rückgabewert ist in C auch üblich; Exceptions hat man hier ja nicht. Denk an snprintf und dergleichen. Ich bin mir nicht sicher, worauf du hinaus willst.

    Kritik an Ansatz 3 könnte ich eher verstehen, aber wenn man zum Beispiel die benötigte Bufferlänge zur Compilezeit überhaupt nicht abschätzen kann, kommt man da mitunter stumpf nicht herum. Auch hierfür gibt es Präzedenzfälle, beispielsweise strdup. Mit VLAs lässt sich da einiges mehr drehen, aber für alle Zwecke reicht das auch nicht.

    Es gibt sogar manchmal eine Kombination aus Ansätzen 2 und 3, um überflüssige Allokationen zu sparen. GNUs getline() ist dafür ein Beispiel.


  • Mod

    Ähh, ich meine Ansatz 3, nicht 2. 'Tschuldigung, der erste ansatz war so kurz, den habe ich übersehen 🙂 .

    GNU getline würde ich nicht unbedingt als gutes Vorbild zitieren. VLAs auch nicht. Um Ansatz 3 kommt man auch leicht herum, indem man so etwas wie eine Stringklasse baut. Dann findet zwar technisch gesehen das malloc in der Funktion statt, aber der Benutzer braucht das gar nicht zu wissen oder zu kümmern, was da passiert.



  • Das ist eben die Crux von C mit char-arrays. Es sind nur Zeiger auf char ohne klare Länge des arrays (string). Das Ende ist das Nullzeichen '\0'. Wer damit nicht leben will, nimmt einen anderen Compiler, der den 'Datentyp' string kennt. Wäre schon einmal einen Umstieg auf z.B. C++ wert, auch wenn man dort zunächst nur die string-Klasse verwendet.



  • Was heißt "nur"?
    Gut, man könnte sich auch in C so etwas basteln. Aber in C++ ist halt die bessere Syntax und die automatischen Speicherfreigabe.



  • Hallo zusammen,
    ich verstehe das 2. Beispiel von seldon nicht.
    wie muß ich das auf mein Code anwenden ?

    Kann mir jemand mal ein Beispiel geben auf meinen Code bezogen.

    Danke.



  • informiere dich, wie man die funktionen malloc/calloc in verbindung mit der funktion free benutzt.
    dann verstehst du es.
    http://www.cplusplus.com/reference/cstdlib/malloc/
    http://www.cplusplus.com/reference/cstdlib/free/



  • wau alta,
    deinen optimismus hätte ich auch gern 🤡



  • Nathan schrieb:

    Aber in C++ ist halt die bessere Syntax

    Ich lach mich tot.

    Nathan schrieb:

    und die automatischen Speicherfreigabe.

    Ach ja? Du schwätzt Unsinn.



  • Wutz schrieb:

    Nathan schrieb:

    Aber in C++ ist halt die bessere Syntax

    Ich lach mich tot.

    hervorragende idee!

    Wutz schrieb:

    Nathan schrieb:

    und die automatischen Speicherfreigabe.

    Ach ja? Du schwätzt Unsinn.

    es gibt desktruktoren, wohl noch nie was von gehört.


Log in to reply