String als Rückgabewert einer int Funktion



  • Hallo,

    ich habe ein Programm mit SQLite Anbindung.
    Dieses nutzt für Werte schreiben und lesen die Funktion callback(ein wenig von mir modifiziert). Die Funktion ist kein Teil der Memberklasse messen, sondern steht als normale Funktion in der messen.cpp

    static int callback(void *NotUsed, int argc, char **argv, char **azColName)
    {
        int i;
        for(i=0; i<argc; i++)
        {
            ostringstream buffer;
            buffer << ("%s", argv[i] ? argv[i] : "NULL");
            string s = buffer.str();
            cout << s << "lautet der name"<<endl;
        }
        return (0);
    }
    

    Diese Funktion werkelt in einer messen.cpp Datei.
    Nun möchte ich in der main.cpp Werte aus der Datenbank einlesen und in einen String speichern.

    Der Aufruf in der main.cpp schaut folgendermaßen aus:

    messen m; // Instanziert die Klasse messen
    
    int main()
    {
    ostringstream oss;
    oss << m.sql_auslesen(1); //öffenet die Funktion sql_auslesen mit Parameter 1
    string s = oss.str();
    cout << s << endl;
    
        return 0;
    }
    

    Jedoch erhalte ich immer nur eine 0 zurück und entsprechend im cout ausgegeben. Da die vorgegebene Funktion callback als Datentyp ein int hat, kann ich schlecht als Rückgabedatentyp einen string definieren.

    Gibt es einen kniff wie ich dennoch aus der Funktion callback meine Datenbankinhalte in die main.cpp erhalte?

    Danke und Gruß



  • Dann zeig mal "messen". Das ist komplett wirr was du hier postest.



  • Das grundsätzliche Problem ist die Kommunikation zwischen einer Klassenfunktion und einer Nicht-Klassenfunktion innerhalb einer .cpp Datei.
    Ich versuche aktuell mit einer string getter Funktion den String aus der Callback Funktion zu erhalten. Dies habe ich in dem untenstehenden Quellcode noch nicht eingebaut.

    messen.h

    #ifndef MESSEN_H
    #define MESSEN_H
    #include <stdio.h>
    #include <iostream>
    #include <string>
    #include <sstream>
    #include <string>
    #include <iomanip>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fstream>
    
    using namespace std;
    
    //***************************************************************
    //                   Deklaration der Klasse 'messen'
    //****************************************************************
    
    class messen
    {
    
    public:
    
        messen (); //Konstruktor
        string datum ();
        string zeit ();
        string datetime();
        double tempout (); // Ansteuerung Außentemperatur
        double tempin ();  // Ansteuerung Innentemperatur
        double humidity ();  // Ansteuerung Luftfeuchtigkeit
        void speichern (double p_id, double p_tempout, double p_tempin, double p_humidity,string p_time, string p_date, string p_datetime); 
        int sql_auslesen(int auswahl);
    
    };
    
    #endif // MESSEN_H
    

    messen.cpp

    #include "messen.h"
    #include <stdlib.h>
    #include <sqlite3.h>
    #include <fstream>
    #include <iostream>
    #include <iostream>
    #include <unistd.h>
    #include <limits>
    #include <sstream>
    #include <string>
    #include <stdint.h>
    #include <ctime>        // Für Uhrzeit
    #include <time.h>       // Für Random Zahlen
    #define MAXTIMINGS	85  // Für DHT11 Ansteierung
    #define DHTPIN		7   // Für DHT11 Ansteuerung
    #define DELAY 10
    
    using namespace std;
    
    messen::messen ()
    {
    
    // Leerer Konstruktor
    
    }
    
    string messen::zeit()
    {
    // Generiert aktuelle Zeit
    
    }
    
    string messen::datum()
    {
    // Generiert aktuelles Datum
    
    }
    
    string messen::datetime()
    {
    
        // Generiert aktuelles Datum String im Format YYYY-MM-DD HH:MM:SS
    
    }
    
    void messen::messung()
    {
    
        // Klasse die Messwerte ausliest und abspeichert
    
        }
    
    }
    double messen::tempin()
    {
    
    // Ansteuerung der Sensoren
    
    }
    
    double messen::tempout()
    {
    
    // Ansteuerung der Sensoren
    
    }
    
    double messen::humidity()
    {
    
    // Ansteuerung der Sensoren
    
    }
    
    static int callback(void *NotUsed, int argc, char **argv, char **azColName)
    {
        int i;
        messen n;
        for(i=0; i<argc; i++)
        {
            ostringstream buffer;
            buffer << ("%s", argv[i] ? argv[i] : "NULL");
            string s = buffer.str();
    	// cout << s << " lautet der Inhalt der Datenbankabfrage "<<endl;
    
        }
        printf("\n");
        return (0);
    }
    
    string quotesql( const string& s )
    {
        return string("'") + s + string("'");
    }
    
    void messen::speichern(double p_id, double p_tempout, double p_tempin, double p_humidity,string p_time, string p_date, string p_datetime)
    {
    
    // Übergabeparameter von messung() werden hier in die Datenbank abgespeichert
    
    }
    
    int messen::sql_auslesen(int auswahl)
    {
        sqlite3 *db;
        char *zErrMsg = 0;
        int rc;
    
        int modus = auswahl;
        string befehl;
    
        /* Open database */
        rc = sqlite3_open("messwerte.db", &db);
        if( rc )
        {
            //fprintf(stderr, "Datenbank konnte nicht geöffnet werden %s\n", sqlite3_errmsg(db));
            exit(0);
        }
        else
        {
            //fprintf(stderr, "Datenbank erfolgreich geöffnet.\n");
        }
    
        // Modus Auswahl
    
        switch(modus)
        {
    
    //    1= Name 2= Email 3=Mindesttemperatur 4=MinHumidity 5=MaxHumidity 6=Intervall
    
        case 1:
            befehl = "NAME";
            break;
        case 2:
            befehl = "EMAIL";
            break;
        case 3:
            befehl = "TEMP";
            break;
        case 4:
            befehl = "INTERVALL";
            break;
        case 5:
            befehl = "MIN_HUMIDITY";
            break;
        case 6:
            befehl = "MAX_HUMIDITY";
            break;
        default:
            break;
        }
    
        string sqlstatement = "SELECT " + befehl + " FROM einstellungen WHERE ID=1;";
    
        /* Wandelt string sqlstatement in char um */
        char * buffer = new char[sqlstatement.length()];
        strcpy(buffer,sqlstatement.c_str());
    
        /* Execute SQL statement */
        rc = sqlite3_exec(db, buffer, callback, 0, &zErrMsg);
        if( rc != SQLITE_OK )
        {
            //fprintf(stderr, "SQL error: %s\n", zErrMsg);
            sqlite3_free(zErrMsg);
        }
        else
        {
            //fprintf(stdout, "Einstellungen gespeichert\n");
        }
        sqlite3_close(db);
    
        delete [] buffer;
        return 0;
    }
    

    und die main.cpp

    using namespace std;
    
    // Legt Instanz der Klasse messen an
    messen m;
    
    int main()
    {
    ostringstream oss;
    oss << m.sql_auslesen(1);
    string s = oss.str();
    cout << s << "lautet der Name"<<endl;
    //m.messung();
    
        return 0;
    }
    


  • ostringstream buffer; 
            buffer << ("%s", argv[i] ? argv[i] : "NULL");
    

    Was erwartest du dir von dem "%s" ?

    ---

    Zu deinem Callback: Sqlite ruft den Callback für jede Zeile auf, die zum Ergebnis gehört. Du kannst da natürlich keinen String zurückgeben denn laut Doku wird der Rückgabewert intern verwendet um die Query abzubrechen zu können:

    If an sqlite3_exec() callback returns non-zero, the sqlite3_exec() routine returns SQLITE_ABORT without invoking the callback again and without running any subsequent SQL statements.

    Das heißt du musst es anders machen. Nahgeliegend wären globale Variablen und bei jedem Aufruf des Callbacks sicherst du das Ergebnis in einem globalen Container - zb std::vector.

    Globale Variablen sind aber hässlich. Deswegen bietet dir sqlite eine tolle Möglichkeit:

    [code="cpp"]int sqlite3_exec(
    sqlite3*, /* An open database /
    const char *sql, /* SQL to be evaluated /
    int (*callback)(void*,int,char
    ,char**), /* Callback function */
    *void , / 1st argument to callback /
    char **errmsg /* Error msg written here */
    );[/code]

    Der vierte Parameter wird dem Callback als ersten Parameter übergeben! Lösung für dein Problem: Du übergibst da einen Zeiger auf eine Datenstruktur, in der du deine Ergebnisse speichern möchtest. Im Callback speicherst du dann da, wo der Zeiger hinzeigt, deine Ergebnisse.

    ---

    Aber Allgemein:
    - Verbessere deine C++ Kenntnisse.
    - Lerne die Sqlite-API.



  • Ethon schrieb:

    ostringstream buffer; 
            buffer << ("%s", argv[i] ? argv[i] : "NULL");
    

    Was erwartest du dir von dem "%s" ?

    "%s" ist bereits als Beispiel seitens SQLite gegeben. Ich habe die Ausgabe lediglich in einen ostringstream umgeleitet/gespeichert.

    Der vierte Parameter wird dem Callback als ersten Parameter übergeben! Lösung für dein Problem: Du übergibst da einen Zeiger auf eine Datenstruktur, in der du deine Ergebnisse speichern möchtest. Im Callback speicherst du dann da, wo der Zeiger hinzeigt, deine Ergebnisse.

    Das bedeutet jetzt in meinem aktuellen Fall genau was?
    Welchen Zeiger muss ich jetzt in welcher Funktion definieren?
    Ich befürchte jetzt bin ich komplett verwirrt 😕

    Aber Allgemein:
    - Verbessere deine C++ Kenntnisse.
    - Lerne die Sqlite-API.

    Aye, aye! Bin Student und versuche mehr oder weniger den Funktionsumfang von C++ abzuarbeiten.

    Besten dank bisher schon mal.
    Bin dennoch über deine Antwort wie ich das nun im konkreten Fall besser machen kann gespannt.

    Gruß


  • Mod

    julianpe schrieb:

    Ethon schrieb:

    ostringstream buffer; 
            buffer << ("%s", argv[i] ? argv[i] : "NULL");
    

    Was erwartest du dir von dem "%s" ?

    "%s" ist bereits als Beispiel seitens SQLite gegeben. Ich habe die Ausgabe lediglich in einen ostringstream umgeleitet/gespeichert.

    In dem Beispiel stand aber doch sicher so etwas wie

    printf("%s", argv[i] ? argv[i] : "NULL");
    

    , oder? printf (oder eine seiner Varianten) ist eine C-Funktion, die zwar auch was mit Ausgabe zu tun hat, aber ganz anders funktioniert als du denkst. Das "%s" gehört nicht zur Ausgabe, das dient der Formatierung. Die die Streams mit dem Operator<< automatisch formatieren, wäre hier wohl eher folgendes gefragt:

    buffer << argv[i] ? argv[i] : "NULL";
    


  • SeppJ schrieb:

    julianpe schrieb:

    Ethon schrieb:

    ostringstream buffer; 
            buffer << ("%s", argv[i] ? argv[i] : "NULL");
    

    Was erwartest du dir von dem "%s" ?

    "%s" ist bereits als Beispiel seitens SQLite gegeben. Ich habe die Ausgabe lediglich in einen ostringstream umgeleitet/gespeichert.

    In dem Beispiel stand aber doch sicher so etwas wie

    printf("%s", argv[i] ? argv[i] : "NULL");
    

    , oder? printf (oder eine seiner Varianten) ist eine C-Funktion, die zwar auch was mit Ausgabe zu tun hat, aber ganz anders funktioniert als du denkst. Das "%s" gehört nicht zur Ausgabe, das dient der Formatierung. Die die Streams mit dem Operator<< automatisch formatieren, wäre hier wohl eher folgendes gefragt:

    buffer << argv[i] ? argv[i] : "NULL";
    

    Ja das stimmt. Es war vorher mit einem printf Befehl. Ich dachte das wäre eine einfache Ausgabe, daher habe ich auch den Befehl gegen cout bzw. gegen eine Umleitung in einen Stream genutzt.

    Nicht desto trotz bleibt die Problematik, wie ich möglichst einfach den Rückgabewert in einen string bekomme.



  • Wie würde die Funktion callback aussehen wenn ich die Rückgabewerte in einem Vector gespeichert werden?


  • Mod

    julianpe schrieb:

    Wie würde die Funktion callback aussehen wenn ich die Rückgabewerte in einem Vector gespeichert werden?

    Du schreibst einen Funktion

    int callback (void* foo, int, char**, char**)
    {
      vector<int> &vec = *reinterpret_cast<vector<int>*>(foo);
      // Schreib deine  Ergebnisse in vec
    }
    

    Dann machst du deinen sql-Aufruf:

    vector<int> results;
    sqlite3_exec(/*wasauchimmer*/, /*wasauchimmer*/, callback, reinterpret_cast<void*>(&results), /*wasauchimmer*/);
    

    Oder halt mit dem Datentyp, den du fuer angemessen haeltst. Das ist nicht nur fuer Ergebnisse gut, sondern kann auch genutzt werden, um zusaetzliche Parameter an den callback zu uebergeben,



  • Vielen Dank für deine Antwort und die Mühe,

    jedoch habe ich Probleme den Quellcode zu interpretieren, was der genau nun macht, und wie ich den Inhalt des Vektors später in der main.cpp ausgeben kann.

    Ich hätte gedacht, dass die Implementierung der SQlite3 Datenbank nicht so schwierig wird wie gedacht.

    Wie würde die Quellcodeimplementierung anhand meines o.g. Programms aussehen?

    Gruß
    Julian



  • julianpe schrieb:

    Ich hätte gedacht, dass die Implementierung der SQlite3 Datenbank nicht so schwierig wird wie gedacht.

    Davon abgesehen, daß du die Bedeutung des Wortes "Implementierung" nicht verstanden hast: Es wäre garnicht schwierig, wenn du nur die Sprache C++ in Grundzügen verstanden hättest.



  • Swordfish schrieb:

    julianpe schrieb:

    Ich hätte gedacht, dass die Implementierung der SQlite3 Datenbank nicht so schwierig wird wie gedacht.

    Davon abgesehen, daß du die Bedeutung des Wortes "Implementierung" nicht verstanden hast: Es wäre garnicht schwierig, wenn du nur die Sprache C++ in Grundzügen verstanden hättest.

    In Zukunft bitte ich hier um konstruktive Beiträge, die mir dem Threadersteller hilfreiche Lösungen beinhalten.
    Da ich mit C++ noch nicht sehr intensiv programmiert habe, kann man wohl davon ausgehen, dass nicht jeder der programmieren möchte 100% versiert ist.

    // Edit:
    Ich würde echt kein Thread erstellen und hier rumtippen aus lauter langerweile.
    Ich habe wirklich ein Problem das zu verstehen und diese Funktion zu nutzen. Jedoch sieht die Aufgabe es vor eine Datenbank in ein Programm einzubinden und dort Werte ein und auszulesen.



  • Dir wurde schon alles nötige gesagt. Solltest Du weitere Fragen haben empfehle ich davor Smart Questions zu lesen.


  • Mod

    Autoren externen Bibliothekn gehen normalerweise davon aus, dass man die Sprache beherrscht. Hier kommt verschaerfend hinzu, dass du eine C-Bibliothek benutzt. Du musst zur Benutzung also 3 Sprachen beherrschen:
    -C (und zwar objektorientiertes C, nicht das C wie im typischen Anfaengerlehrbuch!)
    -C++
    -SQL
    Sowie noch das wichtige Thema "Zusammenspiel von C und C++". Derzeit scheint dir davon alles zu fehlen (ausser vielleicht SQL, das kann ich nicht beurteilen), was erwartest du da? Da gibt es kein einfaches Kochrezept, das man einfach abschreiben kann. Wir koennen nur die Konzepte erklaeren, die hier wichtig sind, um die Sprachen richtig anzuwenden. Das haben wir versucht, aber du hast es nicht verstanden, weil du mit den Sprachen an sich noch Schwierigkeiten hast. Was sollen wir da noch tun? Dir das ganze Programm schreiben? Dir 99% des Programms schreiben und du ergaenzt noch "int main", damit du sagen kannst, du haettest es nicht komplett abgeschrieben? Die Antwort ist doch, dass du eben erst die Sprachen besser lernen musst, bevor du dieses Vorhaben angehen kannst. Denn auch wenn du es anders erwartest hast, ist es doch letztlich ein Fakt, dass die Benutzung einer externen C-Bibliothek keine einfache Sache ist.



  • Ich würde daher auch empfehlen gleich eine auf C++ portierte Version von SQLite zu benutzen, s.a. meinen Beitrag zu SQL unter C++ anwenden


Anmelden zum Antworten