Speicherzugriffsfehler / Segmentation fault || Ubuntu Linux 11.04 (Natty Narwhal)

L

llf

Hallo, nach dem ich heute endlich C++ mit MySQL zum Laufen brachte, kam mir eine Idee. Da ich ein Spiel programmiere (in SDL), will ich dies zu einem Onlinegame umbauen. Dafür will ich die MySQL-Datenbank als Login-Server verwenden. Was bedeutet, der Nutzer gibt Seine Email-Adresse und sein Passwort ein und das Skript überprüft dann den Rest. Als erstes wollte ich mit der MySQL-Funktion beginnen. Damit aber alles Ordentlich bleibt will ich SDL und MySQL klar von einander trennen. Jetzt habe ich eine Anwendung geschrieben, zum Testen ob das mit einer zweiten .cpp Datei und einer Header überhaupt geht. Compilen lässt es sich auch aber ausführen nicht. Wenn ich versuche es auszuführen, dann kommt folgende Fehler Meldung: Speicherzugriffsfehler. Ich hab' mir ein Build-Skript geschrieben (Shell). Wenn ich das ausführe kommt Segmentation fault. Was kann ich machen?

Hier der Quelltext von allen Dateien:

mysql.cpp
Code:
#include <mysql/mysql.h>
#include <stdio.h>
#include <stdlib.h>
#include "mysql.h"

THE_MYSQL::THE_MYSQL()
{
    conn = mysql_init(NULL);
}

THE_MYSQL::~THE_MYSQL()
{
}

void THE_MYSQL::connect()
{
    if(!mysql_real_connect(conn, server, user, password, database, 0, NULL, 0)) {
        fprintf(stderr, "%s\n", mysql_error(conn));
        exit(1);
    }
}

void THE_MYSQL::disconnect()
{
    mysql_free_result(res);
    mysql_close(conn);
}

MYSQL_RES *THE_MYSQL::send_query(char *query)
{
    if(mysql_query(conn, query)) {
        fprintf(stderr, "%s\n", mysql_error(conn));
        exit(1);
    }

    return mysql_use_result(conn);
}

mysql.h
Code:
#ifndef MYSQL_H
#define MYSQL_H

#include <mysql/mysql.h>

class THE_MYSQL
{
public:
    char *server;
    char *user;
    char *password;
    char *database;

    THE_MYSQL();
    ~THE_MYSQL();
    void connect();
    void disconnect();
    MYSQL_RES *send_query(char *query);

private:
    MYSQL     *conn;
    MYSQL_RES *res;
};

#endif

main.cpp
Code:
#include <mysql/mysql.h>
#include <stdio.h>
#include <stdlib.h>
#include "mysql.h"

int main() {
    MYSQL_RES *resource;
    MYSQL_ROW  row;

    THE_MYSQL *connection;
    connection->server   = "localhost";
    connection->user     = "root";
    connection->password = "imkampe";
    connection->database = "game";
    connection->connect();

    resource = connection->send_query("show tables");

    connection->disconnect();
}

compile.sh
Code:
g++ -c main.cpp -o main.o
g++ -c mysql.cpp -o mysql.o
g++ -o output-file $(mysql_config --cflags) main.cpp mysql.cpp $(mysql_config --libs)
./output-file

Danke für alle Antworten.

PS: Bitte sagt jetzt nicht das es doch viel praktischer ist ein Makefile zu benutzen. Ich finde Makefiles zu umständlich und hab' oft schlechte Erfahrungen gesammelt mit ihnen.
 
Hi

Wie, das Buildskript (compile.sh) macht Segmentation Faults? :suspekt:
Nicht eher der Aufruf des Programms am Schluss?

Zum Fehler:
Dieser Teil im main:
C++:
THE_MYSQL *connection;
connection->server   = "localhost";
connection->user     = "root";
connection->password = "imkampe";
connection->database = "game";
connection->connect();
 
resource = connection->send_query("show tables");
 
connection->disconnect();
Da machst du mi connection einen Pointer.
Dieser Pointer kann auf ein THE_MYSQL zeigen.
Tut er aber nicht. Du lässt ihn leer und willst dann das THE_MYSQL drinnen, das es noch gar nicht gibt, verwenden.

Entweder du vergisst den Pointer und legst einfach ein wirkliches Objekt an:
C++:
THE_MYSQL connection;
connection.server   = "localhost";
connection.user     = "root";
connection.password = "imkampe";
connection.database = "game";
connection.connect();
 
resource = connection.send_query("show tables");
 
connection.disconnect();
(Stern beim Anlegen weg und statt -> immer . nehmen)

oder du verwendest new und delete:
C++:
THE_MYSQL *connection;
connection = new THE_MYSQL(); //neu
connection->server   = "localhost";
connection->user     = "root";
connection->password = "imkampe";
connection->database = "game";
connection->connect();
 
resource = connection->send_query("show tables");
 
connection->disconnect();
delete connection; //neu

Die Logindaten solltest du übrigens nicht im Klartext im Programm speichern.
Das kann jeder auslesen.

Gruß
 
Also das mit den Login-Daten will ich später noch mit MD5 verschlüsseln.
Ich hab jetzt mal ein paar Änderungen vorgenommen.
Ich hab jetzt folgendes Skript:

mysql.cpp
Code:
#include <mysql/mysql.h>
#include <stdio.h>
#include <stdlib.h>
#include "mysql.h"

THE_MYSQL::THE_MYSQL()
{
    conn = mysql_init(NULL);
}

THE_MYSQL::~THE_MYSQL()
{
}

void THE_MYSQL::connect()
{
    if(!mysql_real_connect(conn, server, user, password, database, 0, NULL, 0)) {
        fprintf(stderr, "%s\n", mysql_error(conn));
        exit(1);
    }
}

void THE_MYSQL::disconnect()
{
    mysql_free_result(res);
    mysql_close(conn);
}

MYSQL_RES *THE_MYSQL::send_query(char *query)
{
    if(mysql_query(conn, query)) {
        fprintf(stderr, "%s\n", mysql_error(conn));
        exit(1);
    }

    return mysql_use_result(conn);
}

mysql.h
Code:
#ifndef MYSQL_H
#define MYSQL_H

#include <mysql/mysql.h>
#include <string>

class THE_MYSQL
{
public:
    char *server;
    char *user;
    char *password;
    char *database;

    THE_MYSQL();
    ~THE_MYSQL();
    void connect();
    void disconnect();
    MYSQL_RES *send_query(char *query);

private:
    MYSQL     *conn;
    MYSQL_RES *res;
};

#endif

main.cpp
Code:
#include <mysql/mysql.h>
#include <stdio.h>
#include <stdlib.h>
#include "mysql.h"

int main() {
    MYSQL_RES *resource;
    MYSQL_ROW  row;

    THE_MYSQL connection;
    connection.server   = "localhost";
    connection.user     = "root";
    connection.password = "imkampe";
    connection.database = "game";
    connection.connect();

    resource = connection.send_query("show tables");

    connection.disconnect();
    return 0;
}

Das mit dem Speicherzugriffsfehler / Segmentation fault ist jetzt beim Compilen weg. Jetzt kommt allerdings folgendes: Bus error / Bus Speicherzugriffsfehler.
Ich hab es jetzt debugt und fest gestellt, dass der Bus error daran liegt:
Code:
mysql_free_result(res);

Wenn ich das weg lasse, dann funktioniert es. Aber ich finde dass das eine nicht so tolle Methode ist, weil das Skript dann nicht sauber beendet wird.

Gibt's da vielleicht eine Lösung?

MFG llf

PS:
Ich hab auch mein compile-Skript umgebaut, das keine Warnungen mehr erscheinen.
compile.sh
Code:
g++ -c main.cpp -o main.o -Wno-write-strings
g++ -c mysql.cpp -o mysql.o
g++ -o output-file $(mysql_config --cflags) main.cpp mysql.cpp $(mysql_config --libs) -Wno-write-strings
./output-file
 
Okay,
ich hab mal wieder den Wald vor lauter Bäumen nicht gesehen.
Noch schöne Woche
 
Hi.
Ich hab auch mein compile-Skript umgebaut, das keine Warnungen mehr erscheinen.
Warnungen sind in der Regel aber sehr nützlich. Sie weisen meistens auf einen Fehler hin.

Die Warnungen einfach zu unterdrücken ist keine gute Idee. Versuche die Warnungen zu verstehen und ändere die Fehler im Code ab die zu den Warnungen führen.

Stringliterale sind nunmal konstant und es führt letztendlich zu einem Absturz wenn man versucht diese zu ändern.

Du müßtest einfach nur "const char*" statt "char*" verwenden:
C++:
class THE_MYSQL
{
public:
    const char *server;
    const char *user;
    const char *password;
    const char *database;
 ...
};
Wobei Attribute einer Klasse nie public sein sollten. OOP, data hiding. Warum übergibst du die Werte nicht im Konstruktor? So wie es jetzt ist, kann man einfach eine THE_MYSQL Instanz erzeugen die unbenutzbar ist, da sie nicht vollständig initialisiert ist.

Gruß
 

Neue Beiträge

Zurück