Zum Inhalt springen

Laufzeitfehler beim verwenden der funktion strlen()


Empfohlene Beiträge

Geschrieben

Hi Leute. Bin beim programmieren auf nen fehler gestoßen , eigentlich wollte ich nur nen Chararray in nen String umwandeln aber da bekomm ich bei egal welcher methode nen Laufzeitfehler. Also er compiliert aber gleich dannach bekomm ich ein fehler von ******* ausgespuckt ... Bissel oll ... z.b. beim verwenden der funktion strlen hat wer ne ahnung von euch ?

Geschrieben

ifstream file("dictlst.csv");

string line    

if(file.is_open())

    {

                        while(!file.eof())

                        {

                                            getline(file, line);

                                            char* wort=stringtoarray(line);

                                            cuts = tokenizer(wort, ';');

                                            cout << strlen(cuts) << endl;  

Cuts ist nen zeiger (char*) mit der letzten zeile hat er dann seine Probleme. habe die beiden folgenden funktionen verwendet: String to array:
#include <string>

using namespace std;

char* stringtoarray(string line)

{

char* charline=new char[line.length()];

for(int i=0; i<line.length();i++)

        charline[i]=line[i];

return(charline);

}
und den geschriebenen Tokenizer (hatte ich als ne art vorlage im netz gefunden , glaube hier is das Prob mit der Terminierung-->
#include <stdio.h>

#include <string.h>


char* tokenizer(char* lines, char seperator)

{

      char* curr = NULL;

      char* ret = NULL;

      static char* buffer = NULL;

      if(lines)

      {

                buffer = lines;

      }

      curr = buffer;          


      if(curr)

      {

              while(*curr != seperator && (*(curr++)) != '\0');

              if(*curr == '\0')

              {

                       return NULL;                        

              }

              *curr = '\0';

              ret = buffer;

              buffer = curr +1;        

      }

      return ret;

}

Geschrieben

Was mir spontan auffällt:

char* charline=new char[line.length()];
length() gibt meines Wissens die Anzahl der Zeichen des Strings zurück. Bei einem String mit n Elementen würde ein n-elementiges Array erzeugt. Für das Nullbyte, welches Du bei diesem Vorgehen selbst setzen müsstest, wird jedoch ein n+1-elementiges Array benötigt.

while(*curr != seperator && (*(curr++)) != '\0');

if(*curr == '\0')

{

           return NULL;                        

}

Abgesehen davon, dass hier auch strtok verwendet werden könnte: wird das Nullbyte erreicht, wird ein Nullzeiger zurückgegeben (siehe Post von Klotzkopp).

Insgesamt erscheint mir diese Funktion etwas merkwürdig: Die Zeile wird einmal durchlaufen, bis entweder der Seperator oder ein Nullbyte gefunden wird. Bei Nullbyte erfolgt Rückgabe des Nullzeigers und dies wird nicht abgefangen. Wird der Seperator gefunden, wird dieser durch das Nullbyte ausgetauscht und das daraus entstehende Array zurückgegeben. Ob das wirklich das gewünschte Resultat erzeugt, wage ich zu bezweifeln.

Baue doch ein paar Debug-Ausgaben ein und schaue Dir einmal an, was dort überhaupt geschieht. Oder schmeiß die Funktion gleich weg und schau Dir das Beispiel bei strtok an ;)

Geschrieben

danke für die schnelle antwort! Ich probier das mal ! Das war nach einer nich allzulanger recherche wohl ne akzeptable lösung ... wie gesagt das war auch nur nen abtippen. Ich versuch halt beides mal =)

Geschrieben

Du kannst dir eigentlich beide Funktionen sparen. Der Tokenizer ist offensichtlich in C geschrieben. In C++ versucht man, sich möglichst nicht mit rohen Zeigern und char-Arrays herumzuärgern. Damit hättest du auch nicht mehr das Problem, das jemand den in stringtoarray angeforderten Speicher wieder freigeben muss, weil es sonst ein Speicherleck gibt.

Das Ganze könnte auch so aussehen:

    ifstream file("dictlst.csv");
string line;
while(getline(file, line) )
{
istringstream iss(line);
string cuts;
getline(iss, cuts, ';');
}[/code]

Keine Zeiger, keine char-Arrays, keine aufwändigen zusätzlichen Funktionen, kein Speicherleck.

Geschrieben

Danke für deine antwort! Ist wahrscheinlich noch einfacher, aber kannst du mir den Teil in der while schleife erklären ? wo kommen die 3 oder mehr teile aus dem line string dann genau hin ? bzw. wann legt er was auf cuts?

Geschrieben
wo kommen die 3 oder mehr teile aus dem line string dann genau hin ?
Keine "3 oder mehr" Teile. Der Code liest aus jeder Zeile nur bis zum ersten Semikolon, genau wie dein ursprünglicher Code. Wenn du alle Teile auslesen willst, kannst du getline wieder in eine Schleife stecken.

Getline funktioniert mit Stringstreams genauso wie mit Filestreams.

Geschrieben (bearbeitet)

Sorry 4 Doppelpost aber ich hab nen neues Prob , hab es mich der Alten methode zum funzen gebracht (strtok).... jetzt hab ich das prob dass bei einigen wörtern manchmal "der" "er" oder sowas angehängt ist ... o.O in der datei Dictlst stehts aber richtig drin ... ich poste mal den text der aktuellen umsetzung:


int l,i;

    int index=0;

    string line;

    ifstream myfile("dictlst.csv");

    if(myfile.is_open())

    {

                        while(!myfile.eof())

                        {

                                            getline(myfile, line);

                                            index += 1;

                        }

                        index -=1;

                        myfile.close();                    

                        cout << index << endl;

    }

    else cout << "Unable to open File" << endl;


    string vergl;

    char* verglwort=NULL;

    char* ger=NULL;

    char* engl=NULL;

    char* engl2=NULL;

    char* engl3=NULL;

    string gerstr,englstr,engl2str,engl3str;

    //index = listenlaenge

    l=randomlang();

    i=randompos(index);

    char* cuts;

    string wortliste[5];

    int indexnummer;

    cout << i << endl;

    ifstream file("dictlst.csv");

    if(file.is_open())

    {

                        while(!file.eof())

                        {

                                            getline(file, line);

                                            char* wort=stringtoarray(line);

                                            int x = 1;

                                            int n = 0;

                                            bool y = true;

                                            char *str1;

                                            //cout << "String: " << wort << endl;

                                            str1 = strtok(wort, ";");                                           /* extract first string from string sequence */

                                            indexnummer = atoi(str1);  

                                            if (indexnummer == i)

                                               {                                 

                                            //cout <<indexnummer<<endl << l <<endl;

                                            //cout << "i: " << x << str1 << endl;

                                            while (y == true)                                                   /* loop until finishied */

                                            {

                                                  str1 = strtok(NULL, ";"); 

                                                  printf("%i: %s\n", x, str1);                                  /* extract string from string sequence */

                                                  switch(n)

                                                  {

                                                           case 0:

                                                                ger=str1;

                                                                break;

                                                           case 1:

                                                                engl=str1;

                                                                break;

                                                           case 2:

                                                                engl2=str1;

                                                                break;

                                                           case 3:

                                                                engl3=str1;

                                                                break;

                                                           default:

                                                                   cout << n << endl;

                                                                   break;

                                                                   }                             

                                                  if (str1 == NULL)                                     /* check if there is nothing else to extract */

                                                  {

                                                     cout << "Tokenizing complete" << endl;             

                                                     y = false;

                                                  }

                                                  //cout << str1 << endl;

                                                  x++; 

                                                  n++;

                                             }

                                             cout << "Indexnummer: " << indexnummer << " Deutsches Wort: " << ger  << " 1. Englisches Wort: " << engl  << endl;

                                                 }


                        }

                        file.close();                    

    }

    else cout << "Unable to open File" << endl;

    gerstr=arraytostring(ger);

    englstr=arraytostring(engl);

Habe ne ausgabe gleich bei der tokenbestimmung eingesetzt und da kommt es schon vor ... csv datei ist wie gesagt sauber ... irgendwo kommen reste oder weiß ich was her die er anhängt ...

und noch ein problem: wenn ich wörter mit leerzeichen eingebe erkennt er diese als 2 wörter o.O

Bearbeitet von morytox
Geschrieben

Habe die Funktion jetzt wie folgt bearbeitet:

#include <string>

using namespace std;

char* stringtoarray(string line)

{

char* charline=new char[line.length()+1];

for(int i=0; i<line.length();i++)

        charline[i]=line[i];

charline[line.length()]='\0';

return(charline);

}

Hab auch erstmal den Fehler mit falschem auslesen nicht enddecken können ... jedoch nur weil ich nicht ausfühlich testen kann da er keine strings mit leerzeichen annimt ... sobald eins drin is (eingabe) sieht er diese als 2 wörter ... kann man das umgehen ?

Geschrieben

Fehlerquellen eliminieren:

char* stringtoarray(string line)
{
char* charline=new char[line.length()+1];
strcpy(charline, line.c_str());
return charline;
}[/code]

Ein Speicherleck haben wir dann zwar immer noch, aber sonst sollte das so funktionieren.

und noch ein problem: wenn ich wörter mit leerzeichen eingebe erkennt er diese als 2 wörter o.O
Ich sehe im Code keine Eingabeverarbeitung.
Geschrieben

das war weiter unten ... habe ich aber lösen können da cin >> xyz ja bekanntermaßen kein leerzeichen nimmt habe ich es dann über cin.getline gelöst

Und die Probleme bei der fehlerkennun konnte ich auch allein irgendwie fixen...

wenn ich mein programm ma optimieren will werd ich die ganzen zeilen hier einbaun . aber noch bin ich so in der lernphase dass ich möglichst viel selber schreiben möchte und wenig vorgefertigte funktionen nutzen möchte ... wenn ich weiß wies alles funzt nehm ich dann auch gern den sicheren kürzeren weg!

Trotzdem danke für die hilfe !

Geschrieben

Neues Problem!

Ich möchte nun eine Auswahl erstellen bei der Verschiedene Datein eingelesen werden können (versch. Vokabellisten)

Wenn ich diese nun anwähle Legt er nen String auf ne Variable... ich zeigs einfach mal:

so isses Ursprünglich gewesen:

ifstream myfile("dictlst.csv");

    if(myfile.is_open())

    {

                        while(!myfile.eof())

                        {

                                            getline(myfile, line);

                                            index += 1;

                        }

                        index -=1;

                        myfile.close();

                        if(debug==true){                    

                        cout << "Indexgroesse betraegt: " << index << endl << endl;

                        }

    }

    else cout << "Unable to open File" << endl;
Jetzt wollte ich nen string unitifile machen auf dem dieser wert: "dictlst.csv" liegt und diesen anstelle des Strings verwenden. Das hat er nicht gemacht da er dafür keine Funktion kannte also so :
ifstream myfile(unitifile);
Der Folgende Code ist dann ne variante unter der es zu Kompilieren ging , aber das File kann er dann trotzdem nicht öffnen ... Wie kann ich an das Problem rangehn ?
ifstream unitifile;

    if(unitifile.is_open())

    {

                        while(!unitifile.eof())

                        {

                                            getline(unitifile, line);

                                            index += 1;

                        }

                        index -=1;

                        unitifile.close();

                        if(debug==true){                    

                        cout << "Indexgroesse betraegt: " << index << endl << endl;

                        }

    }

    else cout << "Unable to open File" << endl;

Geschrieben (bearbeitet)

Hat sich schon erledigt! index von pw war zu klein!

und wieder nen Prob wo ich kp hab wo das herkommen soll -.-:

char pw1,pw2,pw3,pw4,pw5,pw6,pw7,pw8;

char pw[8];


system("cls");

               cout << " Passworteingabe fuer den Debugmodus: ";

               pw1 = getch();                                                               


               cout << "*";

               pw2 = getch();                                                     

               cout << "*";

               pw3 = getch();

               cout << "*";

               pw4 = getch();

               cout << "*";

               pw5 = getch();                                                             

               cout << "*";

               pw6 = getch();                                                     

               cout << "*";

               pw7 = getch();

               cout << "*";

               pw8 = getch();

               cout << "*";

               cout << endl;

               system("cls");


for (int i=0; i<8 ; i++)

                {

                switch(i)

                {

                case 0:

                     pw[i]=pw1;

                     break;

                case 1:

                     pw[i]=pw2;

                     break;

                case 2:

                     pw[i]=pw3;

                     break;

                case 3:

                     pw[i]=pw4;

                     break;

                case 4:

                     pw[i]=pw5;

                     break;

                case 5:

                     pw[i]=pw6;

                     break;

                case 6:

                     pw[i]=pw7;

                     break;

                case 7:

                     pw[i]=pw8;

                     break;

                default:

                     break;

                     }

                }

                cout << pw[0] << pw[1] << pw[2] << pw[3] << pw[4] << pw[5] << pw[6] << pw[7] << endl;

                pass=arraytostring(pw);

                cout << pass << endl;

Als laenge gibt mir strlen(pw) 24 aus obwohl sich doch nur 8 von 8 definierten darin befinden ... Die Ausgabe sieht auch komisch aus : erst das wort , dann nen paar sonderzeichen und dann das ganze wort nur umgekehrt o.O Funktion Arraytostring :
#include <string>

#include <iostream>

using namespace std;


string arraytostring(char* tempdat)

{

int lenge=strlen(tempdat);

std::string tempstring(tempdat);

return(tempstring);       

}

Bearbeitet von morytox
Geschrieben

Als laenge gibt mir strlen(pw) 24 aus obwohl sich doch nur 8 von 8 definierten darin befinden ...

Weil (schon wieder) die Nullterminierung fehlt.

In C gibt es keine Strings. Darum benutzt man Arrays von char dafür. Arrays haben aber ein paar Eigenheiten. So geht beispielsweise die Größeninformation verloren, wenn man ein Array als Funktionsparameter übergibt. Darum hat man die Vereinbarung getroffen, dass das Ende eines Strings durch ein spezielles Zeichen markiert wird. Ansonsten weiß keine C-Funktion, wo dein String aufhört, weder strlen noch printf noch sonst irgendeine.

Da du offenbar unbedingt mit rohen char-Arrays hantieren willst, musst du dich an diese Konvention halten.

Funktion Arraytostring :

Die ist komplett überflüssig. Die Variable "lenge" benutzt du nirgends. Und ansonsten rufst du nur den std::string-Konstruktor für char* auf. Das geht aber auch, ohne da noch eine Funktion drumherum zu stricken:

// statt
std::string s = arraytostring(einchararrayoderzeiger);

// besser
std::string s(einchararrayoderzeiger);
[/code]

Geschrieben

Okay ... Prob again ...

Jetzt bemerk ich dass ich nen Speicherleck habe wie ihr es mir gesagt habt ...

Das is die Auslastung von meinem letzten Programmdurchlauf:

attachment.php?attachmentid=3229&stc=1&d=1269609691

Oben das ist noch ein unausgereifter algorithmus zur indexbestimmung um keine doppelten zu haben ...

Kann mir das jemand mit dem Speicherleck erklären ? Es bringt mir nich viel wenn es mir wer sagt und ne andere Zeile code hinknallt ... lieber hab ich eine kleine Erklärung warum und dann kann ich es guten gewissens abändern.

Schnmal Danke im voraus.

post-68491-14430448642066_thumb.jpg

Geschrieben

Du hast mindestens eine Stelle im Code, an der wiederholt ein malloc/new stattfindet, ohne dass der reservierte Speicher mit free/delete wieder freigegeben wird. So wird nach und nach immer mehr Speicher verbraucht.

Geschrieben
wahrscheinlich isses dieses stringtoarray von der letzten seite ,
Keine Ahnung, ich kenne den Rest deines Codes nicht. Vielleicht ist da irgendwo noch ein delete[]. Es ist auch nicht sicher, dass das das einzige Leck ist. Dein Programmiersteil zeigt eine gewisse Sorglosigkeit im Umgang mit dynamischem Speicher. Ich könnte mir vorstellen, dass es noch andere Stellen gibt.

hast du nen beispiel wie ich das dann wieder freigebe ?

Zum Beispiel so:

delete[] wort;

Das kommt dann dahin, wo du den dynamisch reservierten Speicher nicht mehr brauchst.

Ich rede vermutlich gegen die Wand, aber wenn du das gleich mit den Klassen der Standardbibliothek statt mit rohen Zeigern gemacht hättest, hättest du dieses Problem jetzt nicht ;)

Geschrieben

ja ich bin ja auch erst im lernstadium ... will mich an das verhalten von code erstmal rantasten ... mit letzten seite meinte ich die seite 1 hier im thread im forum .. da hast du meine stringtoarray funktion schonmal unter die lupe genommen , is die einzige stelle wo ich ein new verwende.. kanns da liegen ? und wenn ja , muss ich das dann in der Funktion verwenden (das delete) oder kann ich dass auch im mein programmcode dann würde ich es nämlich nach dem parsen wieder freigeben...

Geschrieben
da hast du meine stringtoarray funktion schonmal unter die lupe genommen , is die einzige stelle wo ich ein new verwende.. kanns da liegen ?
Dann wird's das sein.

und wenn ja , muss ich das dann in der Funktion verwenden (das delete) oder kann ich dass auch im mein programmcode dann würde ich es nämlich nach dem parsen wieder freigeben...
Du kannst es nicht in der Funktion machen, weil du den Zeiger auf den reservierten Speicher für die weitere Verarbeitung rausgibst. Wenn du ihn vorher wieder freigibst, gibt die Funktion einen ungültigen Zeiger zurück, und das Programm fliegt dir um die Ohren - wenn du Glück hast.

Du speicherst den zurückgegebenen Zeiger ja in der Variablen wort. Es reicht also, wenn du nach der Verarbeitung das hier einbaust:

delete[] wort;

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...