Hallo Leute! Ich bin mir nicht ganz sicher, wie man am besten vorgeht, wenn man aus einem unsigned char* ein char* machen möchte. Folgendes Problem: // --- 8< ------------------ // Alle Includes da. typedef unsigned char xmlChar; xmlChar* name; char* n; strcpy(n, name); // Führt zum Absturz mit SIGSEGV // --- 8< ------------------ Meine Frage nun: Wie mache ich aus einem unsigned char (xmlChar) ein char? Danke! Viele Grüße, Christian -- "There was an interesting development in the CBS-Westmoreland trial: both sides agreed that after the trial, Andy Rooney would be allowed to talk to the jury for three minutes about little things that annoyed him during the trial." -- David Letterman
On 2002-10-10 01:53:30, Christian Weickhmann wrote:
Ich bin mir nicht ganz sicher, wie man am besten vorgeht, wenn man aus einem unsigned char* ein char* machen möchte.
Folgendes Problem:
// --- 8< ------------------ // Alle Includes da. typedef unsigned char xmlChar; xmlChar* name; char* n;
Meine Frage nun: Wie mache ich aus einem unsigned char (xmlChar) ein char? Danke!
Hmm, bin ich auf dem Holzweg, oder kannst Du da nicht einfach einen cast verwenden? n = (char)xmlChar; Bin nicht der ganz geübte C-Mensch, aber das sollte eigentlich gehen. V.
Hi, On Thu, 10 Oct 2002, Christian Weickhmann wrote:
Ich bin mir nicht ganz sicher, wie man am besten vorgeht, wenn man aus einem unsigned char* ein char* machen möchte.
Folgendes Problem:
// --- 8< ------------------ // Alle Includes da. typedef unsigned char xmlChar; xmlChar* name; char* n;
strcpy(n, name); // Führt zum Absturz mit SIGSEGV
Keine Wunder, weder n noch name sind initialisiert, bzw., wenn es globale Variablen waren auf 0 initialisiert. und strcpy(0, 0); erzeugt natuerlich ne SEGV.
Meine Frage nun: Wie mache ich aus einem unsigned char (xmlChar) ein char? Danke!
Irgendwie bin ich nicht sicher, ob du weisst, was du willst. Willst du ne Typkonvertierung, z.B. um Funktion mit als 'char *' deklarierten Argumenten, mit 'unsigned char *' Parametern aufzurufen? Dann willst du einen Typecast: void f(char * bla) { ... } voif g() { unsigned char *string = "Hallo"; f ((char*) string); } Oder willst du wirklich einen neuen String anlegen, der den gleichen Inhalt wie ein anderer hat, aber einen anderen Typ? In dem Fall ist strcpy() gar nicht so falsch, aber natuerlich muss schon der Speicher alloziert sein: void g () { unsigned char *string = "Hallo"; char *as_char; as_char = (char*) malloc (strlen (string) + 1); strcpy (as_char, string); ... free (as_char); } Aber das ist hoechstwahrscheinlich _nicht_ was du willst. Um nur den Typen zu aendern ist es nicht erforderlich Speicherbereiche hin- und herzukopieren. Ciao, Micha.
Hallo Michael! Am Donnerstag, 10. Oktober 2002 14:08 schrieb Michael Matz:
Irgendwie bin ich nicht sicher, ob du weisst, was du willst. Willst du ne Typkonvertierung, z.B. um Funktion mit als 'char *' deklarierten Argumenten, mit 'unsigned char *' Parametern aufzurufen? Dann willst du einen Typecast:
Das ist vielleicht nicht so ganz rübergekommen (OK, ich habe es ja nicht richtig hingeschrieben...): Genau dieser Typecast führt zu Müll! Wenn ich unsigned char* irgendwas = "Blablabla"; strcpy(zielString, (const char*)irgendwas); aufrufe steht da Müll! Beim Ausdrucken fällt das erst richtig auf: unsigned char* irgendwas = "Blabla"; printf("%s", irgendwas); // Funktioniert hier interessanterweise ohne & printf("%s", (char*)irgendwas); Ich kann's leider nicht reproduzieren, weil ich die Stelle im Code bereits geändert habe. Jedenfalls kommt bei einem Typecast eben nicht der richtige Inhalt raus... Was ich eben gemerkt habe ist, dass das SIGSEGV nicht an der Typkonvertierung liegt. Der Debugger sagte mir, dass der Fehler in der Zeile liegt, wo strcpy() aufgerufen wird. Ich fürchte aber, dass das Problem in der Klasse liegt, die strcpy aufruft. Sieht folgendermaßen aus: Klasse sm_schueler speichert die Daten einer Person (eines Schülers) und stellt Funktionen zu deren Manipulation bereit. Will ich jetzt ein Array von solchen Objekten erzeugen, kann es dann der Grund für dieses SIGSEGV sein, dass ich folgendes gemacht habe: sm_schueler *s[100]; // um 100 Elemente von sm_schueler zu initialisieren... dann der Aufruf: s[0]->setName("EinName"); Ist das so korrekt oder muss ich s[0] vorher noch initialisieren? Wenn ja, wie? Danke, Christian -- Higgeldy Piggeldy, Hamlet of Elsinore Ruffled the critics by Dropping this bomb: "Phooey on Freud and his Psychoanalysis -- Oedipus, Shmoedipus, I just love Mom."
Hi, On Thu, 10 Oct 2002, Christian Weickhmann wrote:
Das ist vielleicht nicht so ganz rübergekommen (OK, ich habe es ja nicht richtig hingeschrieben...): Genau dieser Typecast führt zu Müll!
Kann nicht sein ;-) Gib einen vollstaendigen Sourcecode (aber bitte < 100 Zeilen), der dies tut.
unsigned char* irgendwas = "Blablabla"; strcpy(zielString, (const char*)irgendwas);
aufrufe steht da Müll!
Ist "zielString" denn nun alloziert oder nicht?
Beim Ausdrucken fällt das erst richtig auf:
unsigned char* irgendwas = "Blabla"; printf("%s", irgendwas); // Funktioniert hier interessanterweise // ohne &
Klar. &irgendwas haette ja Typ "unsigned char **" (die Addresse eines Pointers hat eben Typ Pointer of Pointer), und das wuerde sicherlich, wenn interpretiert als String ("%s"), lustige Hexzeichen ausgeben.
printf("%s", (char*)irgendwas);
Das funktioniert definitiv so. Wenn es das nicht tat, dann war entweder "irgendwas" nicht initialisiert, oder du hattest nicht genau die obige Zeile geschrieben.
Ich kann's leider nicht reproduzieren, weil ich die Stelle im Code bereits geändert habe. Jedenfalls kommt bei einem Typecast eben nicht der richtige Inhalt raus...
Doch.
Klasse sm_schueler speichert die Daten einer Person (eines Schülers) und stellt Funktionen zu deren Manipulation bereit. Will ich jetzt ein Array von solchen Objekten erzeugen, kann es dann der Grund für dieses SIGSEGV sein, dass ich folgendes gemacht habe:
sm_schueler *s[100]; // um 100 Elemente von sm_schueler zu initialisieren...
Ehm. Das initialisiert ueberhaupt nix. Du scheinst verwirrt zu sein bezueglich Objektinstanzen und Pointer auf Objektinstanzen. Obiges reserviert Speicher fuer 100 _Pointer_ auf sm_schueler Instanzen. Wenn es ne globale Var ist, dann sind alle diese Pointer nach Programmstart NULL-initialisert, wenn's ne lokale Variable ist, steht einfach Muell drin (liegt eben auf dem Stack).
dann der Aufruf:
s[0]->setName("EinName");
Hast du jemals s[0] irgendwas zugewiesen, wie z.B. "s[0]=new sm_schueler;" Wenn nicht, dann ist s[0] immer noch 0, womit wir also effektiv den Aufruf 0->setName(...) haben, was natuerlich ebenfalls ne SEGV produziert, da der this pointer dann NULL ist.
Ist das so korrekt oder muss ich s[0] vorher noch initialisieren? Wenn ja, wie?
Naja, du musst eben Instanzen dieser sm_schueler Klasse anlegen, du hast ja explizit bloss pointer darauf reserviert. Wenn du gleich beim Programmstart den Speicher fuer diese Instanzen reservieren willst (im Gegensatz dynamisch zur Laufzeit), so musst du s so schreiben: sm_schueler s[100]; Das reserviert 100 Instanzen von sm_schueler, und 0-initialisiert sie (wenn s file-global ist). Aufrufe von Methoden auf diesen Objekten nutzen dann natuerlich nicht den -> operator, sondern: s[0].setName(...); Man beachte, das dann s[0] eben nicht mehr die _Addresse_ eines Objektes ist, sondern das Objekt selbst. Die Address von ihm ist &s[0]. Ciao, Micha.
Am Don, 2002-10-10 um 14.38 schrieb Christian Weickhmann:
Hallo Michael!
Am Donnerstag, 10. Oktober 2002 14:08 schrieb Michael Matz:
Irgendwie bin ich nicht sicher, ob du weisst, was du willst. Willst du ne Typkonvertierung, z.B. um Funktion mit als 'char *' deklarierten Argumenten, mit 'unsigned char *' Parametern aufzurufen? Dann willst du einen Typecast:
Das ist vielleicht nicht so ganz rübergekommen (OK, ich habe es ja nicht richtig hingeschrieben...): Genau dieser Typecast führt zu Müll!
Wenn ich
unsigned char* irgendwas = "Blablabla"; strcpy(zielString, (const char*)irgendwas);
1. Siehe K'n'R Kapitel "Array vs. Pointer" (Auf Dtsch. Felder und Zeiger) Dann wahrscheinliche Lösung: unsigned char irgendwas[] = "blablabla", 2. Ist zielString alloziert? Wenn nein, suchst Du strdup() oder malloc.
Was ich eben gemerkt habe ist, dass das SIGSEGV nicht an der Typkonvertierung liegt. Der Debugger sagte mir, dass der Fehler in der Zeile liegt, wo strcpy() aufgerufen wird. Ich fürchte aber, dass das Problem in der Klasse liegt, die strcpy aufruft. Klasse? Reden wir hier von C++ oder von C? (C und C++ unterscheiden sich in Zeiger/Felderbehandlung nicht unerheblich im Detail)
Reden wir hier von (es war von xmlChar die Rede) libxml und C++ mit gcc-3.2? (In diesem Fall gäbe es noch ein weiteres Problem, das sich u.U. auswirken könnte)
Sieht folgendermaßen aus:
Klasse sm_schueler speichert die Daten einer Person (eines Schülers) und stellt Funktionen zu deren Manipulation bereit. Will ich jetzt ein Array von solchen Objekten erzeugen, kann es dann der Grund für dieses SIGSEGV sein, dass ich folgendes gemacht habe:
sm_schueler *s[100]; // um 100 Elemente von sm_schueler zu initialisieren... Falls C++, nimm vector<>, map<> oder ähnliches.
dann der Aufruf:
s[0]->setName("EinName");
Ist das so korrekt oder muss ich s[0] vorher noch initialisieren? Jein, Du musst es allozieren.
Dein obiges Array erzeugt lediglich 100 Zeiger auf sm_schueler, jeden einzelnen Schüler musst du noch allozieren und gegebenenfalls initialisieren.
Wenn ja, wie? In C++ mit new, in C mit malloc ;)
Ralf
Hallo Ralf!
Um gleich mal alle Unklarheiten zu beseitigen:
Zum System:
- gcc-2.95
- libxml2 (v 2.4.23)
Mein Code sieht folgendermaßen aus:
// ---------------------
// schueler.h
class sm_schueler {
private:
static int anzahl; // Es steht noch nicht fest, ob ich das brauche, also
// nicht wichtig.
char *name, *vorname;
int schuljahr; // Welche Klasse und welches Halbjahr
public:
sm_schueler();
~sm_schueler();
char* getName();
char* getVorname();
int getSchuljahr();
void setName(const unsigned char*);
void setVorname(const unsigned char*);
void setSchuljahr(int);
};
// ---------------------
// schueler.cpp
#include "schueler.h"
sm_schueler::sm_schueler() {anzahl++;}
sm_schueler::~sm_schueler() {anzahl--;}
char* sm_schueler::getName() {return name;}
char* sm_schueler::getVorname() {return vorname;}
int sm_schueler::getSchuljahr() {return schuljahr;}
void sm_schueler::setName(const unsigned char* n)
{
strcpy(name, (char*)n);
}
void sm_schueler::setVorname(const unsigned char* vn)
{
strcpy(name, (char*)vn);
}
void sm_schueler::setSchuljahr(int s) {schuljahr = s;}
// ----------------------
// dateihandler.h
#include
Moin Moin, Am Donnerstag, 10. Oktober 2002 17:08 schrieb Christian Weickhmann: [...]
Ich brauche ein Array, das insgesamt bis zu 100 Schüler speichern können soll (am besten unbegrenzt viele) und auf dessen Elemente ich dann noch Zugriff haben will.
Schaue Dir mal die STL Komponenten an, der Vector in C++ vergößert sich bei bedarf... z.B.: #include <vector> #include <iostream> int main(){ vector<int> intVec(10); unsigned int i; for (i=0; i < intVec.size(); i++) intVec[i] = i; intVec.insert( intVec.end(), 11); /* Ohne Probleme ein elftes Element, macht STL automatisch */ return 0; } Bye Andre
Hi, On Thu, 10 Oct 2002, Christian Weickhmann wrote:
void sm_schueler::setName(const unsigned char* n) { strcpy(name, (char*)n); }
name wird nirgends initialisiert.
void sm_schueler::setVorname(const unsigned char* vn) { strcpy(name, (char*)vn); }
Wahrscheinlich vorname, wird aber auch nirgends initialisiert. Also gibt's natuerlich SEGVs. Du musst erst Speicher allozieren, wenn du auf ihn schreiben willst.
void dateihandler::getXMLschueler(char* dateiname, sm_schueler* s){
... char *name = s->getName(); char *vorname = s->getVorname(); int schuljahr = s->getSchuljahr();
fprintf(stderr, "%d %s, %s [.] : %d\n", nummer, *name, *vorname, schuljahr);
*name ist das erste Zeichen von name (== name[0]), und das crasht natuerlich gleich nochmal, wenn es als pointer ("%s") interpretiert wird. Du willst 'fprintf (stderr, "... %s ...", ..., name, vorname ...);' Beachte, das selbst damit das Programm noch crashen wird, da wie gesagt die name und vorname member auf keinen Speicher zeigen.
void dateihandler::oeffne(char* dateiname){ doc = xmlParseFile(dateiname); if (doc == NULL) { fprintf(stderr, "Die Datei %s konnte nicht geöffnet werden.", &dateiname);
Nein. Du willst bloss 'fprintf (...., dateiname);' nicht &dateiname. Du solltest dich _ernsthaft_ mit pointern, Addressen und Strings in C beschaeftigen.
Folgendes für "sm_schueler schueler[100]" in main.cpp: Ich brauche ein Array, das insgesamt bis zu 100 Schüler speichern können soll (am besten unbegrenzt viele) und auf dessen Elemente ich dann noch Zugriff haben will.
Wenn du nicht die STL Klassen verwenden willst, dann wuerde ich eine verkettete Liste empfehlen, die du einfach in sm_schueler einbauen kannst. Ala: struct sm_schueler { ... struct sm_schueler *next; }; sm_schueler *erster = 0; sm_schueler * get_new_schueler () { sm_schueler *n = new sm_schueler; n->next = erster; erster = n; } void iterate() { for (sm_schueler *s = erster; s; s = s->next) do_something (s); } void free_them () { sm_schueler *n, *n_next; for (n = erster; n; n = n_next) { n_next = n->next; delete n; } } Ciao, Micha.
Am Donnerstag, 10. Oktober 2002 14:38 schrieb Christian Weickhmann:
Hallo Michael!
[...]
Sieht folgendermaßen aus:
Klasse sm_schueler speichert die Daten einer Person (eines Schülers) und stellt Funktionen zu deren Manipulation bereit. Will ich jetzt ein Array von solchen Objekten erzeugen, kann es dann der Grund für dieses SIGSEGV sein, dass ich folgendes gemacht habe:
sm_schueler *s[100]; // um 100 Elemente von sm_schueler zu initialisieren...
Du initialisiert hier aber nichts, legst vielmehr 100 Zeiger vom Typ sm_schueler an, die irgendwo ins Nirwana zeigen.
dann der Aufruf:
s[0]->setName("EinName");
Ist das so korrekt oder muss ich s[0] vorher noch initialisieren? Wenn ja, wie?
s[0] ist kein Objekt, sondern nur ein Zeiger -> 'new' verwenden und später den 'delete' nicht vergessen, oder direkt 100 Objekte anlegen: sm_schueler s[100]. Zweiteres ist aber sehr unschön.
Danke, Christian
hth holger
Hi! ---- #include <iostream> #include <string> int main() { // char nach unsigned char // *********************** // irgendwas -> irgendwas2 char* irgendwas = "Blahblah"; unsigned char* irgendwas2 = new unsigned char(std::strlen( irgendwas )); // Test-Ausgabe std::cout << irgendwas << std::endl; // Konvertieren for( unsigned int i = 0; i < std::strlen( irgendwas ); i++ ) { irgendwas2[i] = static_cast<unsigned char>( irgendwas[i] ); } // Test-Ausgabe 2 std::cout << irgendwas2 << std::endl; // unsigned char nach char // *********************** // irgendwas2 -> irgendwas3 char* irgendwas3 = new char(8); // Achtung: strlen hier nicht anwendbar for( int i = 0; i < 8; i++ ) { irgendwas3[i] = static_cast<char>( irgendwas2[i] ); } // Test-Ausgabe 3 std::cout << irgendwas3 << std::endl; return 0; } --- Bringt bei mir die Ausgabe Blahblah Blahblah Blahblah Das ist jetzt quick'n'dirty per Hand gehackt, irgendwo gibt's bestimmt eine elegantere Funktion für sowas (gibt's immer :) ). Du musst im Fall unsigned char nach char mit der Größe aufpassen. Da Du die aber in Hochkommas zuweist s[0]->setName("EinName"); kannst Du vorher die Größe ausrechnen. Zu den anderen Sachen gibt's schon genug Antworten ;) CU Martin
participants (7)
-
Andre Heine
-
Christian Weickhmann
-
Holger Mauritz
-
Martin Oehler
-
Michael Matz
-
Ralf Corsepius
-
Volker Kroll