Problem mit char* bei int-Zuweisung
-
Guten Tag,
Folgendes Problem: Ich lese eine Datei Binär ein (funktioniert) und habe nun eine Funktion die Pixel in dieser PPM-Datei (Portable Pixmap, Bild) ändert... Schön und gut, funktioniert auch, aber nicht mit 0 oder 0x00 oder sonstiges...
Es handelt sich um ein einfaches char *, wenn auch ein sehr großes, doch wenn ich ein Byte/Char = 0 setze, verschwindet der Rest dahinter !!! Das ist nicht nett
Hoffe Ihr könnt helfen, danke im Voraus ! Falls ich Code posten soll einfach sagen, aber vielleicht ist mein Problem so trivial, dass Ihr den nicht braucht

Mit freundlichen Grüßen Daniel
-
Das ist normales Verhalten von C-Strings. (ein char* wird als C-String verwaltet). Sprich um die Länge eines solchen strins zu kennen, wir das ein 0 Zeichen als das Ende betrachtet. Und daher passiert das auch bei dir.
Wie du das am besten umgehst ist halt ein wenig abhängig von den Funktionen, die du benutzt. (Wenn du weisst, wie lange das Array ist, dann kannst du da auch selbst drüber iterieren und ein allfäliges 0 einfach ignorieren).
-
Also ich will ja praktisch die Farbe Schwarz setzen und die ist (0, 0, 0), gibt es irgendeine Art andere 0 ?
doofe frage ich weiß, in java wird ja bsp. zwischen null und 0 unterschieden, aber irgendwie muss ich doch mein schwarz setzen können... irgendne idee?
-
Und wo genau liegt jz dein Problem?
Du willst ne Farbe setzen... wozu brauchst du dann char* ?
Zeig doch mal das Stück, wo du aus der Datei liest und dann die Farbe-Setz-Fkt aufrufst. So versteh zumindest ich nicht, wo genau dein Problem liegt und wieso du überhaupt char* iwo hast...bb
-
Portable Pixmap: http://de.wikipedia.org/wiki/Portable_Pixmap
PPMReader.h
#ifndef __PPMREADER_H__ #define __PPMREADER_H__ #include <iostream> #include <fstream> #include <string> class PPMReader { public: PPMReader(char *filepath); ~PPMReader(); char *GetPixel(int x, int y); void SetPixel(int x, int y, char *rgb); bool SaveFile(char *filename); bool ReadFile(char *filepath); protected: int width, height, bitdepth, pixelbytes; char *image; }; #endifPPMReader.cpp
#include "PPMReader.h" PPMReader::PPMReader(char *filepath) { ReadFile(filepath); } PPMReader::~PPMReader() { } char *PPMReader::GetPixel(int x, int y) { char *rgb = new char[3]; rgb[0] = image[x * 3 + y * width * 3]; rgb[1] = image[x * 3 + 1 + y * width * 3]; rgb[2] = image[x * 3 + 2 + y * width * 3]; return rgb; } void PPMReader::SetPixel(int x, int y, char *rgb) { image[x * 3 + y * width * 3] = rgb[0]; image[x * 3 + 1 + y * width * 3] = rgb[1]; image[x * 3 + 2 + y * width * 3] = rgb[2]; } bool PPMReader::SaveFile(char *filename) { using namespace std; fstream out; out.open(filename, ios::out | ios::binary); if(out.good()) { out << "P6\n"; out << width << " " << height << "\n"; out << bitdepth << "\n"; out << image << "\n"; } else { out.close(); return false; } return true; } bool PPMReader::ReadFile(char *filepath) { using namespace std; const int buffersize = 1024; char *buffer = new char[buffersize]; fstream in; in.open(filepath, ios::in | ios::binary); if(in.good()) { in.getline(buffer, buffersize); string test = buffer; if(test == "P6") { in.getline(buffer, buffersize); while(buffer[0] == '#') in.getline(buffer, buffersize); string size = buffer; for(int i = 0; i < size.size(); i++) { if(size[i] == ' ') { width = atoi(size.substr(0, i).c_str()); height = atoi(size.substr(i + 1, size.size()).c_str()); break; } } in.getline(buffer, buffersize); while(buffer[0] == '#') in.getline(buffer, buffersize); bitdepth = atoi(buffer); int linebytes, imagebytes; if(bitdepth == 255) pixelbytes = 3; else if(bitdepth == 511) pixelbytes = 6; else { in.close(); return false; } linebytes = pixelbytes * width; imagebytes = linebytes * height; image = new char[imagebytes]; /* Vorher leeren, sonst Fehler... */ strcpy(image, ""); in.read(image, imagebytes); } else { in.close(); return false; } } else { in.close(); return false; } return true; }main.cpp
#include "PPMReader.h" int main() { PPMReader *ppm = new PPMReader("bild2-fleck.ppm"); char *pixel = new char[3]; pixel[0] = 0x00; pixel[1] = 0x00; pixel[2] = 0x00; ppm->SetPixel(1, 0, pixel); ppm->SaveFile("neu.ppm"); system("PAUSE"); return 0; }
-
Im Prinzip soll er nur Binär ein Pixel ändern, geht für jeden Wert nur eben bei der 0 nicht... Grund wurd ja genannt, aber wie umgeh ich's?
-
vergiss bloss die delete[]s nicht...
-
sry, wird sofort nachgebaut ^^ trotzdem ist das nicht die lösung des problems :(... ich hätte gern ne zweite 0 ^^
-
Beim speichern solltest du das Bild nicht als C-String ausgeben, sondern z.B als std::string.
bool PPMReader::SaveFile(char *filename) { using namespace std; fstream out; out.open(filename, ios::out | ios::binary); if(out.good()) { out << "P6\n"; out << width << " " << height << "\n"; out << bitdepth << "\n"; out << std::string(image) << "\n"; } else { out.close(); return false; } return true; }So sollte das gehen.
-
So hab das grad mal probiert, scheint sich damit leider nicht erledigt zu haben, der String ist nach dem schwarzen Pixel wech, eingeschlossen dem veränderten Teil...
Habe außerdem grad mal getestet, ob die Pixel dahinter noch existieren ^^, tun sie, und das böse schwarze auch, scheint tatsächlich nur bei der Ausgabe zu meckern, trotz dass ich's auf binary gestellt hab -.- Eigentlich müsste er doch auf mich hören...
-
Auch der std::string-Konstruktor muss irgendwie die Größe der Daten erkennen, da Du selbst keine mitgibst.
Lösung: Benutze die Stream-Methoden um binär zu schreiben und gib die Größe mit an. Gib image nicht auf dem Bildschirm oder im Debugger aus, denn dort wird beim ersten Nullbyte abgeschnitte.
Oder ganz allgemein: Nicht char* schneidet die Daten beim ersten Nullbyte ab, sondern die Art und Weise, wie dieses char* interpretiert wird.
-
paar worte zum codes:
dein fehler ist in zeile 76 der *.cpp korrigiert...Wasabi666 schrieb:
/*PPMReader.h*/ #ifndef __PPMREADER_H__ //alles, was mit unterstrich großbuchstabe und unterstrich unterstrich #define __PPMREADER_H__ //beginnt, ist eigtl für den compiler reserviert... #include <iostream> //alle drei #include <fstream> //includes hier #include <string> //sind nicht notwendig class PPMReader { public: PPMReader(char *filepath); //const char* ~PPMReader(); char *GetPixel(int x, int y); //const - außerdem solltest du den rückgabetypen evtl auch irgendwas RAII-mäßiges ändern (boost::tuple oder schnell selbst was bauen) void SetPixel(int x, int y, char *rgb); //const char* bool SaveFile(char *filename); //const char, const bool ReadFile(char *filepath); //const char* protected: int width, height, bitdepth, pixelbytes; char *image; }; #endif //#ifndef include_guard/*PPMReader.cpp*/ #include "PPMReader.h" #include <fstream> #include <string> PPMReader::PPMReader(char *filepath) { ReadFile(filepath); } PPMReader::~PPMReader() { //sehr sinnvoll + memory-leak } char *PPMReader::GetPixel(int x, int y) { char *rgb = new char[3]; rgb[0] = image[x * 3 + y * width * 3]; rgb[1] = image[x * 3 + 1 + y * width * 3]; rgb[2] = image[x * 3 + 2 + y * width * 3]; return rgb; //gefährlich, da der user hier selbst ein delete aufrufen muss } void PPMReader::SetPixel(int x, int y, char *rgb) { image[x * 3 + y * width * 3] = rgb[0]; image[x * 3 + 1 + y * width * 3] = rgb[1]; image[x * 3 + 2 + y * width * 3] = rgb[2]; } bool PPMReader::SaveFile(char *filename) { using namespace std; fstream out; out.open(filename, ios::out | ios::binary); //fstream hat auch nen schönen konstruktor, der das kann ^^ if(out.good()) { out << "P6\n"; out << width << " " << height << "\n"; out << bitdepth << "\n"; out << image << "\n"; } else { out.close(); //unnötig return false; } return true; //statt mit returnwerten zu arbeiten, würde ich hier eine exception wählen } //sollte ja nicht sooo oft vorkommen, dass er keine datei erstellen kann xD bool PPMReader::ReadFile(char *filepath) { using namespace std; const int buffersize = 1024; char *buffer = new char[buffersize]; //warum nicht stack? fstream in; in.open(filepath, ios::in | ios::binary); if(in.good()) { in.getline(buffer, buffersize); string test = buffer; if(test == "P6") { in.getline(buffer, buffersize); while(buffer[0] == '#') in.getline(buffer, buffersize); string size(buffer, buffer+in.gcount());//siehe http://www.cplusplus.com/reference/iostream/istream/gcount/ for(int i = 0; i < size.size(); i++) { if(size[i] == ' ') { width = atoi(size.substr(0, i).c_str()); height = atoi(size.substr(i + 1, size.size()).c_str()); break; } } //der rest der fkt sieht so grausig aus, dass ich keine lust mehr hab^^ in.getline(buffer, buffersize); while(buffer[0] == '#') in.getline(buffer, buffersize); bitdepth = atoi(buffer); int linebytes, imagebytes; if(bitdepth == 255) pixelbytes = 3; else if(bitdepth == 511) pixelbytes = 6; else { in.close(); return false; } linebytes = pixelbytes * width; imagebytes = linebytes * height; image = new char[imagebytes]; /* Vorher leeren, sonst Fehler... */ strcpy(image, ""); in.read(image, imagebytes); } else { in.close();//nicht notwednig return false; } } else { in.close();//nicht notwendig return false; } return true;//auch hier halte ich returnwerte für den falschen weg... }/*main.cpp*/ #include "PPMReader.h" int main() { PPMReader *ppm = new PPMReader("bild2-fleck.ppm"); //wieso nicht stack? char *pixel = new char[3]; //wieso nicht stack? pixel[0] = 0x00; pixel[1] = 0x00; pixel[2] = 0x00; ppm->SetPixel(1, 0, pixel); ppm->SaveFile("neu.ppm"); system("PAUSE"); //ist an und für sich nen schlechter weg, die konsole offen zu halten return 0; //unnötig }btw:
std::vector<char> ist viel einfacher, als mit char* zu areiten... dann hättest du auch nicht ca. 20 memory-leaks in dem stückchen code... ^^bb
PS: In C++ ist es eher unüblich, so ewig lange Fkt zu schreiben - wenn du mal hinguckst, könnte man da eigtl viele kleine draus machen und dann könnte man so gar durchsehen, wenn man den code nicht geschrieben hat bzw nen weilchen nicht angesehen hat... ^^
-
LordJaxom schrieb:
Auch der std::string-Konstruktor muss irgendwie die Größe der Daten erkennen, da Du selbst keine mitgibst.
*Kopf -> Tisch*
Sowas kommt davon, wenn man zu viele Sachen gleichzeitig macht.. -.-
-
Ok, erstmal Kritik zur Kenntnis genommen

Also, wenn die Funktion so grausig aussieht, wenigstens sagen, was genau daran so böse is ^^, sonst kann ichs nicht verbessern...Und was genau löst mein Problem? Sollte ich vielleicht out.write() verwenden?...
Achso und vector wollte ich mehr oder weniger nicht nehmen, wegen der Geschwindigkeit... Ein std::vector<char> ist um einiges langsamer als char*... korrigiert mich wenn ich falsch liege(aber bitte nicht zu heftig xD)
Und noch eine Frage zur GetPixel methode: wenn ich das irgendwie als int zurückgebe müsst ichs irgendwie wieder auseinanderklamüseln, könnt vllt schnell jemand aufschreiben, wie ichs schön lösen könnte?
und meinst du mit dem "warum stack?" warum ich die ganze zeit zeiger verwende?
puuh, das wars erstmal, :), klärt mich auf
-
Achso und vector wollte ich mehr oder weniger nicht nehmen, wegen der Geschwindigkeit... Ein std::vector<char> ist um einiges langsamer als char*... korrigiert mich wenn ich falsch liege(aber bitte nicht zu heftig xD)Korrigiere: Stimmt nicht.
std::vector ist beinahe so schnell, wie jegliches Array gedöns. Im Debug Mode ist sie klar um einiges langsamer, dafür hat man aber ein Haufen checks usw. Aber im release ist sie in etwa so schnell, wie Arrays.
-
ok, dann werd ichs damit auch versuchen, bloß kann ich irgendwie read, das direkt in den vector kopieren lassen oder muss ich das ganze jetz zeichenweise einlesen?... danke nochmal an alle
-
ich habs jetzt erst in ein char* kopiert und dann den string damit gefüttert, mit gccount un so diesma ;),
ist das sehr unschön gelöst??
wie kann ich mein code jetz möglichst verbessern, dass selbst ihr zufrieden seid?
um zu wissen was richtig un falsch is, muss mans mir schon sagen ^^
-
ich hab keine ahnung, ob das funktioniert - würde mich eigtl sehr wundern, wenn ja^^ ich hatte ein wenig lange weile:
/*PPMReader.h*/ #ifndef H_PPMREADER_200909202000 #define H_PPMREADER_200909202000 #include <vector> #include <utility> struct color_tuple { private: unsigned int RGB[3]; public: unsigned int R() const {return RGB[0];} unsigned int G() const {return RGB[1];} unsigned int B() const {return RGB[2];} color_tuple(const char* RGB, unsigned char bytes_per_color); color_tuple(unsigned int R, unsigned int G, unsigned B); }; class PPMReader { private: std::vector<char> image; std::pair<unsigned int, unsigned int> size; unsigned char color_bytes; public: PPMReader(const char *filepath); color_tuple GetPixel(unsigned int x, unsigned int y) const; unsigned char GetBytesPerColor() const; void SetPixel(unsigned int x, unsigned int y, color_tuple color); void SaveFile(const char *filename) const; void ReadFile(const char *filepath); }; #endif //#ifndef H_PPMREADER_200909202000/*PPMReader.cpp*/ #include "PPMReader.h" #include <fstream> #include <string> #include <sstream> using std::ios; using std::ifstream; using std::ofstream; using std::getline; using std::pair; using std::string; using std::stringstream; const char* header_tag = "P6"; #include <stdexcept> typedef std::runtime_error EXCEPTION_CANNOT_CREATE_FILE; typedef std::runtime_error EXCEPTION_CANNOT_OPEN_FILE; typedef std::invalid_argument EXCEPTION_WRONG_HEADER; typedef std::runtime_error EXCEPTION_NOT_IMPLEMENTED; const char* read_file_exception_text = "Cannot open file for reading an image"; const char* save_file_exception_text = "Cannot create file for saving the image"; const char* wrong_header_text = "Expected other Header-Tag"; const char* not_implementet_colordepth_text = "Sorry, no support for this picture (to high maximum values for each color-value)"; //color_tuple color_tuple::color_tuple(const char* rgb, unsigned char color_depth) { const char *last; for(std::size_t i(0); i != 3; rgb = last, ++i) { last = rgb+color_depth; stringstream ss; ss.write(rgb, last-rgb); ss >> RGB[i]; } } color_tuple::color_tuple(unsigned int R, unsigned int G, unsigned B) { RGB[0] = R; RGB[1] = G; RGB[2] = B; } //helper unsigned int pumuckls_pow(unsigned int b, unsigned int e) //^^ { unsigned int r = 1; while(e != 0) { if(e%2 != 0) r *= b; e /= 2; b *= b; } return r; } unsigned int get_max_from_depth(unsigned int depth) { unsigned int R = 0; for(depth *= 8; depth != 0; --depth) { R += pumuckls_pow(2, depth-1); } return R; } void ignore_trash(ifstream &in) { for(char delemiter; in.get(delemiter) && delemiter == '#'; ) { std::string trash; getline(in, trash); } in.unget(); } std::pair<int/*w*/, int/*h*/> read_size(const std::string &buffer) { std::pair<int, int> R; stringstream ss; ss << buffer; ss >> R.first; ss >> R.second; return R; } unsigned char read_color_bytes(const std::string &buffer) { unsigned int max; stringstream ss; ss << buffer; ss >> max; unsigned char bits(0); for(; max != 0; max >>= 1, ++bits) ; unsigned char bytes = unsigned char(bits/8.f+.5f); return bytes != 3 ? bytes : 4; } //class PPMReader::PPMReader(const char *filepath) { ReadFile(filepath); } color_tuple PPMReader::GetPixel(unsigned int x, unsigned int y) const { return color_tuple( &image[x*3*color_bytes + y*size.first*3*color_bytes], color_bytes ); } unsigned char PPMReader::GetBytesPerColor() const { return color_bytes; } void PPMReader::SetPixel(unsigned int x, unsigned int y, color_tuple color) { //TODO: testen //TODO: staticassert(sizeof(char) == 1), staticassert(sizeof(short) == 2), staticassert(sizeof(int) == 4) std::vector<char>::size_type at1 = x*3*color_bytes + y*size.second*3*color_bytes + 0*color_bytes, at2 = x*3*color_bytes + y*size.second*3*color_bytes + 1*color_bytes, at3 = x*3*color_bytes + y*size.second*3*color_bytes + 2*color_bytes; switch(color_bytes) { case 1: image[at1] = static_cast<char>(color.R()); image[at2] = static_cast<char>(color.G()); image[at3] = static_cast<char>(color.B()); break; case 2: *reinterpret_cast<short*>(&image[at1]) = static_cast<short>(color.R()); *reinterpret_cast<short*>(&image[at2]) = static_cast<short>(color.G()); *reinterpret_cast<short*>(&image[at3]) = static_cast<short>(color.B()); break; case 4: *reinterpret_cast<int*>(&image[at1]) = static_cast<int>(color.R()); *reinterpret_cast<int*>(&image[at2]) = static_cast<int>(color.G()); *reinterpret_cast<int*>(&image[at3]) = static_cast<int>(color.B()); break; default: throw EXCEPTION_NOT_IMPLEMENTED(not_implementet_colordepth_text); } } void PPMReader::SaveFile(const char *filename) const { ofstream out(filename, ios::out | ios::binary); if(out.bad()) throw EXCEPTION_CANNOT_CREATE_FILE(save_file_exception_text); out << "P6\n" << size.first << " " << size.second << "\n" << get_max_from_depth(color_bytes) << "\n"; out.write(&image[0], image.size()); } void PPMReader::ReadFile(const char *filepath) { ifstream in(filepath, ios::in | ios::binary); if(in.bad()) throw EXCEPTION_CANNOT_OPEN_FILE(read_file_exception_text); string buffer; getline(in, buffer); if(buffer != header_tag) throw EXCEPTION_WRONG_HEADER(wrong_header_text); ignore_trash(in); getline(in, buffer); size = read_size(buffer); ignore_trash(in); getline(in, buffer); color_bytes = read_color_bytes(buffer); unsigned int length = color_bytes * size.first * size.second; image.resize(length); in.read(&image[0], length); }so in der richtung würd ichs jedenfalls lösen^^
gefallen tuts mir trotzdem nicht, aber vll hat jmd anderes ja lust, die fehler darin zu beseitigen und das iwie eleganter zu lösen
bb
-
xD ich hab mich jetz an das angeben der größe beim string erstellen gehalten und habe anstatt vector<char> string genommen, was wenn ich mich nich irre sich doch sehr ähnlich ist, ansonsten geht meins jetzt auch...
versuch mich grad bei dir einzulesen, aber so ein paar sachen wie exception handling hab ich noch nich oft gemacht (c++ mach ich auch erst seit geraumen 2 monaten)...was mich jetzt aber richtig interessiert ist:
WARUM GEHT FOLGENDES?: in.read(&image[0], groeße);?? das erscheint mich wegen eig unterschiedlicher datentypen zunächst sinnlos ^^ habs so jetzt für meins auch übernommen, da ich nich ünnötig erneut kopieren möchte, also danke!
-
achso und das mit der pixelklasse werd ich auch noch einbaun, weil stimmt schon, dass man sonst vllt mal ein delete vergisst, danke