Problem mit Zeichenketten, brauche Denkanstoß :-)



  • Code-Hacker schrieb:

    Ich war mal so frei und habe Strings und Streams eingebaut.

    danke. der code sieht schon sehr lecker aus.
    mir schwant, wenn man in watchOutput auch mit << die sachen zusammenhängen würde, käme noch was tolleres (und performanteres, aber das ist eh eine folge von einfach und toll) heruas.

    ich bitte um weitere verbesserungen, und seien sie noch so klein. lasst und den perfekten code finden.



  • Hi!

    Habe die Methode strcatNumber entfernt (wurde nur 1x aufgerufen), habe strcatNumber2 zu lower10 umbenannt, da hier nur die Zahl auf kleiner 10 geprüft wirde, damit gegebenenfalls eine 0 davor geschrieben wird. Habe unnötige Header entfernt und das getch am Ende wodurch conio.h rausgeflogen ist.
    Außerdem habe ich wachtOutput ein wenig gekürzt, so das hinter jedem Datumswert das Zeichen mit angefügt wird. Sollte es ein wenig übersichtlicher machen. Die Längenermittlung in main am Anfang war auch überflüssig und habe ich ebenfalls entfernt:

    #include <iostream>
    #include <ctime>
    #include <string>
    #include <sstream>
    #include <fstream>
    
    using namespace std;
    
    string getDayOfWeekName(int dayOfWeek)
    {
        static string names[]={"So","Mo","Di","Mi","Do","Fr","Sa"};
        return names[dayOfWeek];
    }
    
    string getMonthName(int month)
    {
        static string names[]={"Jan","Feb","Mar","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"};
        return names[month];
    }
    
    string lower10(int num)
    {
        ostringstream out;
    	if(num<10) 
    		out << "0";
        out << num;
        return out.str();  
    }
    
    string watchOutput()
    {
        time_t sec_1970=time(0);
        struct tm* date=localtime(&sec_1970);
    
        //strings
        ostringstream str_time_date;
        str_time_date << getDayOfWeekName(date->tm_wday) << ", ";
    
        str_time_date << lower10(date->tm_mday) << ".";
        str_time_date << getMonthName(date->tm_mon) << ".";
        str_time_date << date->tm_year << ", ";
    
        str_time_date << lower10(date->tm_hour) << ":";
        str_time_date << lower10(date->tm_min) << ":";
        str_time_date << lower10(date->tm_sec) << "\n";
    
        return str_time_date.str();
    }
    
    int main()
    {
        const char root[]="d:\\source\\test2\\";
        const char file[]="watch.log";
        unsigned short int max=10; // 0<max<=20
    
        string path(root);
        path += file;
    
        string str_dat[20];
    
        ifstream log_in(path.c_str());
        for(int i=0; i<max && !log_in.eof(); ++i) {
            getline(log_in, str_dat[i]);
        }
    
        for(int j=(max-1);j>0;--j)
            str_dat[j]=str_dat[j-1];
    
        str_dat[0] = watchOutput();
    
        for(int m=0;m<max;++m)
            cout<<str_dat[m];
    
        ofstream log_out(path, ios_base::out|ios_base::trunc);
        for(int k=0;k<max;++k)
            log_out<<str_dat[k];
    
        return 0;
    }
    

    Ich bin der Meinung das man bei Jahr 1900 aufaddieren sollte. Wir leben schließlich nicht im Jahr 104. 🙂

    Code-Hacker



  • du machst mich glücklich.
    irgendwas an

    for(int i=0;i<max;++i) { 
            if(log_int.eof()) break; // Falls Datei am Ende, dann lesen abbrechen 
            getline(log_in, str_dat[i]); 
        }
    

    kotzt mich noch an. aber ich fürchte, man kann es nicht toll verbessern.
    lob an dich, daß du zum einigen kotz-code kommentiert hast.
    (den kommentar unten ignoriere ich mal, denn wie beide wissen, daß die
    file-objekte kürzer leben sollten.)

    hast du zufällig mit meinem c++-kurs angefangen? dann würde ich dich als referenz aufführen.

    noch ein paar ganz unbedeutende tips:

    char const* getDayOfWeekName(int dayOfWeek)
    {
        static string names[]={"So","Mo","Di","Mi","Do","Fr","Sa"};
        return names[dayOfWeek];
    }
    

    ist ja genausosicher, und hier müssen wir die performance ja nicht wegwerfen.
    (std::string ist nicht geeignet für solche spielereien, man könnte leicht für diesen zweck eine sorte string basteln, die genau hier performanter als std::string und performanter als char* ist).

    die änderung in lower10 finde ich sehr gut. mein name war zum kotzen. deiner sagt viel deutlicher, was da los ist.

    besonders schön gefällt mir die zeile

    str_dat[0] = watchOutput();
    

    irgendwie habe ich das gefühl, da kann viel weniger schief gehen, als bei

    watch.output(&str_dat[0][0]);
    

    das addieren von 1900 hatte ich irgendwwie vergessen, im original war es mit

    year=(*date).tm_year+=1900;
    

    dabei.

    es sei gesagt, daß man mit obigem code (viel ::new in string::string(...) relativ langsam ist.
    es sei gesagt, daß man mit oberstem code (mit viel ::strcat) relativ langsam ist.
    es sei gesagt, daß man mit obigem code kaum noch fehler machen kann.
    es sei gesagt, daß man optimale performance erreicht, wenn man den strcpy-code leicht pervertiert zu

    //alt
        str_time_date << lower10(date->tm_mday) << ".";
    
    //neu
        writepos=lower10(writepos,date->tm_mday);
        *writepos++='.';
    

    nebst einer lower10, die den zeiger auf die position gibt, wo die terminierende 0 sein sollte (aber von writepos noch nicht gesetzt wurde).

    übrigens sollten strcat und strcpy auch den zeiger auf das ende zurückgeben, damit man damit weiterarbeiten kann. den anfang hat man eh. wir verbuchen das verhalten mal als designfehler. nicht nur die stl hat fehler, man hat in der tat früher damit angefangen (mein beitrag zum entmystifizieren der stl im august 04).

    coole klassen vorausgesetzt, macht man in der tat char* und std::string in dieser anwendung platt. zu nullkosten auf beiden seiten, null performanceverlust gegen char* in der endzeugerzurücggebeversion und null sicherheitsverlust gegen std::string was die anfügungen und so angeht.
    (leider braucht manb ein paar wochen dafür, was mich wieder sehr traurig macht.)



  • Hi!

    Ich versteh eines nicht. Die Datei wird gelsen. Danach wird die 1. Zeile überschrieben indem alle Elemente nach hinten kopiert werden. Diese wird später überschrieben. Wenn man dann aber schreibt würde die letzte Zeile doppelt geschrieben werden. Deswegen würde ich die Schleife entfernen und das Datum und Uhrzeit einfach nur an den Anfang schreiben. Habe mir mal erlaubt mit dem copy-Alogrithmus die Datei zu beschreiben und vorher die Datei auf dem Bildschirm auszugeben. Außerdem habe ich das String-Array durch einen Vektor erstzt. Der Rest ist kommentiert:

    #include <iostream>
    #include <ctime>
    #include <string>
    #include <sstream>
    #include <fstream>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    string getDayOfWeekName(int dayOfWeek)
    {
        static string names[]={"So","Mo","Di","Mi","Do","Fr","Sa"};
        return names[dayOfWeek];
    }
    
    string getMonthName(int month)
    {
        static string names[]={"Jan","Feb","Mar","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"};
        return names[month];
    }
    
    string lower10(int num)
    {
        ostringstream out;
        if(num<10) out << "0";
        out << num;
        return out.str();  
    }
    
    string watchOutput()
    {
        time_t sec_1970=time(0);
        struct tm* date=localtime(&sec_1970);
    
        ostringstream str_time_date;
        str_time_date << getDayOfWeekName(date->tm_wday) << ", ";
    
        str_time_date << lower10(date->tm_mday) << ".";
        str_time_date << getMonthName(date->tm_mon) << ".";
        str_time_date << (date->tm_year+1900) << ", ";
    
        str_time_date << lower10(date->tm_hour) << ":";
        str_time_date << lower10(date->tm_min) << ":";
        str_time_date << lower10(date->tm_sec) << "\n";
    
        return str_time_date.str();
    }
    
    int main()
    {
        string path("c:\\source\\test2\\watch.log"); // root und file zu filepath zusammengefasst und direkt in String geschrieben
        const unsigned short int MAX=10; // 0<max<=20; Kontant gemacht
        vector<string> str_dat(MAX, ""); // 20 durch MAX ersetzt; es sind nicht mehr Elemente nötig als benötigt
    
       {
        ifstream log_in(path.c_str());
    	for(int i=0; i<MAX && !log_in.eof(); ++i) { // Lesen beenden, wenn Datei i>=max oder log_in zu Ende gelesen ist
    		string tmp;
            getline(log_in, tmp);
    		str_dat.push_back(tmp);
    	}
        }
    
        str_dat[0] = watchOutput();
    	copy(str_dat.begin(), str_dat.end(), ostream_iterator<string>(cout)); 
    
    	ofstream log_out(path.c_str(), ios_base::out|ios_base::trunc);
    	copy(str_dat.begin(), str_dat.end(), ostream_iterator<string>(log_out, "\n"));   
    
        return 0;
    }
    

    Code-Hacker



  • Hi!

    Nein, ich kannte deinen Kurs damals noch nicht, als ich mit C++ begonnen habe.
    Ich guck aber zwischendurch in deinen Kurs rein, zumal ich auf das neue gespannt bin, wo ich die ersten Kapitel auch bereits gelesen habe. Beim alten habe ich das gelesen wo mir noch etwas das Verständis fehlte und es durch mehr lesen und beispiele aufbessern wollte. Momentan lese ich "Die C++ Programmiersprache".

    Darfst mich aber trotzdem als Refernez aufführen 😃

    Code-Hacker



  • copy(str_dat.begin(), str_dat.end(), ostream_iterator<string>(cout));
    

    meldet beim mingw studio: ostream_iterator undeclared.



  • habe mal <iterator> inkludiert, ohne das klappts bei mir nicht.

    und ofstream log_out(path.c_str(), ios_base::out|ios_base::trunc);
    

    verbessert zu

    und ofstream log_out(path.c_str());
    

    außerdem repariert, indem ich

    str_time_date << lower10(date->tm_sec) << "\n";
    

    zu

    str_time_date << lower10(date->tm_sec);
    

    machte.

    Deswegen würde ich die Schleife entfernen und das Datum und Uhrzeit einfach nur an den Anfang schreiben.

    ach, deswegen klaptt es nicht mehr.
    nee, das war schon irgendwie nötig, damit man die letzten 10 einträge hat.

    meine erste idee war es, eine std::queue zu nehmen, weil die ja dazu da ist, schnell
    vorne was reinschieben zu können.

    aber eigentlich doof, weil ja gar keiner sagt, daßman das erste element erst nach dem
    lesen der datei reinschieben darf.

    das testen auf eof muß eigentlich direkt nach getline erfolgen, damit kein string gepuht
    wird, der nicht gelesen werden konnte.

    path wollte natürlich const werden.

    und MAX ist kein unsigned short.

    das zusammenfassen habe ich wieder andeutungsweise aufgebrochen, denn
    irgendwarum hat berd das ja gemacht.

    habe im block wieder eingerückt. und bei der ausgabe nen ähnlichen block gemacht.

    habe oben doch const char* zurückgegeben.

    habe const besser plaziert, weil man sonst sowas dickes wie static char const* names[]
    nicht mehr lesen kann.

    habe lower10 weggemacht, weil es mit setw ja auch einigermaßen angenehmn geht.

    #include <iostream> 
    #include <iomanip>
    #include <iterator>
    #include <ctime> 
    #include <string> 
    #include <sstream> 
    #include <fstream> 
    #include <vector> 
    #include <algorithm> 
    
    using namespace std; 
    
    char const* getDayOfWeekName(int dayOfWeek) 
    { 
        static char const* names[]={"So","Mo","Di","Mi","Do","Fr","Sa"}; 
        return names[dayOfWeek]; 
    } 
    
    char const* getMonthName(int month) 
    { 
        static char const* names[]={"Jan","Feb","Mar","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"}; 
        return names[month]; 
    } 
    
    string watchOutput() 
    { 
        time_t sec_1970=time(0); 
        struct tm* date=localtime(&sec_1970); 
    
        ostringstream str_time_date; 
    
    	str_time_date << setfill('0');
    
        str_time_date << getDayOfWeekName(date->tm_wday) << ", "; 
        str_time_date << setw(2) << date->tm_mday << "."; 
        str_time_date << getMonthName(date->tm_mon) << "."; 
        str_time_date << (date->tm_year+1900) << ", "; 
    
        str_time_date << setw(2) << date->tm_hour << ":"; 
        str_time_date << setw(2) << date->tm_min << ":"; 
        str_time_date << setw(2) << date->tm_sec; 
    
        return str_time_date.str(); 
    } 
    
    int main() 
    { 
        string const path("d:\\source\\test2\\" "watch.log"); // root und file
        size_t const MAX=10; // 0<max<=20;
        vector<string> str_dat;
    
        str_dat.push_back(watchOutput()); 
    
    	{ 
    		ifstream log_in(path.c_str()); 
    		string line;
    		while(str_dat.size()<MAX && getline(log_in, line))
    			str_dat.push_back(line);
    	}
    
        copy(str_dat.begin(), str_dat.end(), ostream_iterator<string>(cout,"\n")); 
    
    	{
    		ofstream log_out(path.c_str()); 
    		copy(str_dat.begin(), str_dat.end(), ostream_iterator<string>(log_out, "\n"));   
    	}
    
        return 0; 
    }
    


  • Danke erst mal für die große Mühe (so einen Aufwand hätte ich nicht erwartet)

    Erst mal habe ich die Vorteile von Strings entdeckt (in meinem C++ Buch wurde sie gar nicht erwähnt), ich habe den Quelltext nun umgeschrieben, die Klasse ist aber geblieben, weil ich sie weiterverwenden will (vielleicht wird sie noch ausgebaut).

    Das Programm arbeitet jetzt ohne Konsole, da man den Programmaufruf nicht merken soll.

    #include <ctime>
    #include <fstream>
    #include <sstream>
    
    using namespace std;
    
    class dt
    {
    private:	
    	//date
    	unsigned short int day_of_month;
    	unsigned short int month_of_year;
    	unsigned long int year;
    	unsigned short int day_of_week;
    
    	char d_o_w[3];
    	char m_o_y[4];
    
    	//time
    	unsigned short int hour;
    	unsigned short int minute;
    	unsigned short int second;
    
    	//string
    	string str_time_date;
    
    	char temp[5];
    
    	//... from <ctime>
    	time_t sec_1970;
    	struct tm *date;
    
    public:
    	dt();
    
    	string output(string *);
    };
    
    dt::dt()
    {	
    	time(&sec_1970);
    	date=localtime(&sec_1970);
    
    	//date
    	day_of_month=(*date).tm_mday;
    	month_of_year=(*date).tm_mon+=1;
    	year=(*date).tm_year+=1900;
    	day_of_week=(*date).tm_wday;
    
    	//time
    	hour=(*date).tm_hour;
    	minute=(*date).tm_min;
    	second=(*date).tm_sec;
    
    	//strings
    	switch(day_of_week)
    	{
    	case 0: strcpy(d_o_w,"So"); break;
    	case 1: strcpy(d_o_w,"Mo"); break;
    	case 2: strcpy(d_o_w,"Di"); break;
    	case 3: strcpy(d_o_w,"Mi"); break;
    	case 4: strcpy(d_o_w,"Do"); break;
    	case 5: strcpy(d_o_w,"Fr"); break;
    	case 6: strcpy(d_o_w,"Sa"); break;
    	default:strcpy(d_o_w,"--"); break;
    	}
    
    	switch(month_of_year)
    	{
    	case 1: strcpy(m_o_y,"Jan"); break;
    	case 2: strcpy(m_o_y,"Feb"); break;
    	case 3: strcpy(m_o_y,"Mar"); break;
    	case 4: strcpy(m_o_y,"Apr"); break;
    	case 5: strcpy(m_o_y,"Mai"); break;
    	case 6: strcpy(m_o_y,"Jun"); break;
    	case 7: strcpy(m_o_y,"Jul"); break;
    	case 8: strcpy(m_o_y,"Aug"); break;
    	case 9: strcpy(m_o_y,"Sep"); break;
    	case 10: strcpy(m_o_y,"Okt"); break;
    	case 11: strcpy(m_o_y,"Nov"); break;
    	case 12: strcpy(m_o_y,"Dez"); break;
    	default: strcpy(m_o_y,"+++"); break;
    	}
    
    	str_time_date=d_o_w;
    	str_time_date+=", ";
    
    	if(day_of_month<10)
    		str_time_date+="0";
    
    	str_time_date+=_itoa(day_of_month,temp,10);
    	str_time_date+=". ";
    	str_time_date+=m_o_y;
    	str_time_date+=". ";
    	str_time_date+=_itoa(year,temp,10);
    
    	str_time_date+=", ";
    
    	if(hour<10)
    		str_time_date+="0";
    
    	str_time_date+=_itoa(hour,temp,10);
    	str_time_date+=":";
    
    	if(minute<10)
    		str_time_date+="0";
    
    	str_time_date+=_itoa(minute,temp,10);
    	str_time_date+=":";
    
    	if(second<10)
    		str_time_date+="0";
    
    	str_time_date+=_itoa(second,temp,10);
    }
    
    string dt::output(string *str)
    {
    	*str=str_time_date;
    
    	return str_time_date;
    }
    
    int main()
    {
    	class dt watch;
    
    	const char root[]="C:\\";
    	const char file[]="watch.log";
    
    	const unsigned short int max=20; // 0<max<=20
    	string str_dat[20];
    
    	unsigned short int length;
    	unsigned short int i, j, k;
    
    	/*
    		Für Visual C++ folgende Linkeroptionen einfügen:
    
    		/entry:"mainCRTStartup" /subsystem:windows
    	*/
    
    	length=strlen(root)+strlen(file);
    
    	char *path=new char[length];
    
    	strcpy(path,root);
    	strcat(path,file);
    
    	//... Datei lesen
    	ifstream log_in(path, ios_base::in);
    
    	if(log_in.good())
    	{
    		for(i=0;i<max;i++)
    		{
    			getline(log_in, str_dat[i]);
    
    			if(str_dat[i]=="end of file")
    				str_dat[i].erase();
    
    			if(log_in.eof())
    				break;
    		}
    
    	}
    	else
    		i=0;
    
    	log_in.close();
    
    	//... Werte tauschem
    	for(j=(max-1);j>0;j--)
    		str_dat[j]=str_dat[j-1];
    
    	//... 0. Element setzen
    	watch.output(&str_dat[0]);
    
    	//.. Datei schreiben
    	ofstream log_out(path,ios_base::out | ios_base::trunc);
    
    	for(k=0;k<max;k++)
    	{
    		log_out<<str_dat[k];
    
    		if(k==(i+1))
    			break;
    
    		log_out<<endl;
    	}
    
    	log_out<<"end of file";
    
    	log_out.close();
    
    	return 0;
    }
    

    Ich habe sogar noch ein paar Verbesserungen eingebaut (es werden keine leeren Zeilen in die Datei geschrieben b.z.w es wird kein enter mehr gepeichert, wenn der string leer ist) und weiterhin wird das Ende der Datei jetzt mit "end of file" gekennzeichnet.

    1. Mir ist aber aufgefallen, das "log_in.getline()" nicht mehr geht? müsste man das mit "str_dat[i].c_str()" nicht beheben können?

    2. Gibt es irgendwo eine hübsche Übersicht über alle stream Klassen, und deren Abhängigkeit von einander? Wenn möglich sogar eine Grafik?

    berd



  • switch(day_of_week)
        {
        case 0: strcpy(d_o_w,"So"); break;
        case 1: strcpy(d_o_w,"Mo"); break;
        case 2: strcpy(d_o_w,"Di"); break;
        case 3: strcpy(d_o_w,"Mi"); break;
        case 4: strcpy(d_o_w,"Do"); break;
        case 5: strcpy(d_o_w,"Fr"); break;
        case 6: strcpy(d_o_w,"Sa"); break;
        default:strcpy(d_o_w,"--"); break;
        }
    
        switch(month_of_year)
        {
        case 1: strcpy(m_o_y,"Jan"); break;
        case 2: strcpy(m_o_y,"Feb"); break;
        case 3: strcpy(m_o_y,"Mar"); break;
        case 4: strcpy(m_o_y,"Apr"); break;
        case 5: strcpy(m_o_y,"Mai"); break;
        case 6: strcpy(m_o_y,"Jun"); break;
        case 7: strcpy(m_o_y,"Jul"); break;
        case 8: strcpy(m_o_y,"Aug"); break;
        case 9: strcpy(m_o_y,"Sep"); break;
        case 10: strcpy(m_o_y,"Okt"); break;
        case 11: strcpy(m_o_y,"Nov"); break;
        case 12: strcpy(m_o_y,"Dez"); break;
        default: strcpy(m_o_y,"+++"); break;
        }
    

    klopf>>wand(ja man muss die richtigen oepratoren nehmen 😃 )
    wir haben hier ne perfekte lösung zu dem wirrwar da oben gepostet, und du nimmst immernoch die switch blöcke 🙄



  • otze schrieb:

    klopf>>wand(ja man muss die richtigen oepratoren nehmen 😃 )
    wir haben hier ne perfekte lösung zu dem wirrwar da oben gepostet, und du nimmst immernoch die switch blöcke 🙄

    Wir müssen berd sofort ausschalten. Mit seinem apokalyptischen Programmierstil, diesem Gekröse des Abseitigen, wird er ghoulische Mutanten heraufbeschwören und sehr, sehr böse Dinge tun.



  • Was ist denn jetzt daran noch unübersichtlich? Man kann doch alles erkennen, und die Klasse und die main() Funktion sind logisch nachvollziehbar.

    Außerdem, was hat das denn mit falschen Operatoren zu tun? Es sind doch alle richtig, und ich gehe mal stark davon aus, das mein Debuger mir das schon berichten wird, wenn ich nen Fehler mache.

    berd


Anmelden zum Antworten