Forum: PC-Programmierung Fehler in Programm, evtl Zeiger, äußert sich erst wenn das Programm beendet ist.


von Programmierer - Lerner (Gast)


Lesenswert?

Hallo,

Als Übungsaufgabe soll ein Programm geschrieben werden, welches auf bsis 
von Klassen 2 Strings erstellt.

Diese 2 Strings sollen nun zusammengesetzt und gesperrt werden.
(Gesperrt bedeutet, nach jedem zeichen kommt ein ' ')

Es gibt keine Fehlermeldungen/Warnungen von Compiler/Linker.

Wird nun ein Kurzer String (<10Zeichen) gesperrt läuft alles prima.
Wird er länger, bricht das Programm ab, nachdem es bereits vollständig 
abgelaufen ist. Dann wenn ich es beeenden möchte.

Dieses Problem verfolgt mich seit über 10 Tagen, fast täglich.

Ich möchte endlich weiterkommen, es wäre schön wenn jemand eine Antwort 
wüsste.

KlasseText.cpp:
1
/*
2
Aufgabe 1 (Klasse Text)
3
-----------------------
4
Schreiben Sie eine Klasse "Text", die wie folgt aufgebaut ist:
5
6
Attribute:
7
-  das Textfeld (dynamisch aufgebaut - genau passend!)
8
-  ein Attribut, das die Laenge enthaelt
9
10
Methoden:
11
- Standard-Konstuktor,     der einen leeren Text erzeugt
12
- Konstruktor mit String-Parameter,
13
        der genau diesen Text enthaelt
14
- void ausgeben(),     die diesen Text ausgibt
15
- void rueckwaertsAusgeben(),   die diesen Text rueckwaerts ausgibt
16
- void anhaengen(Text t),   die an diesen Text den Text t anhaengt (der
17
          "text" enthaelt also danach den 'alten'
18
        Text und dahinter den Text von t
19
- void gesperrt(int n),   die diesen Text in einen gesperrten Text umwandelt,
20
          wobei zwischen je zwei Buchstaben des ursprüng-
21
        lichen Textes n Leerzeichen eingefuegt werden
22
- int gibLaenge(),     die die Anzahl der Buchstaben dieses
23
        Textes zuruekliefert.
24
25
Schreiben Sie eine Testumbgebung fuer diese Klasse.
26
27
28
HINWEIS:
29
-  Das Programm soll modular aufgebaut sein, d.h.
30
   *  Klassen-Definition von Text in Text.hpp (nur mit Methoden-Signaturen)
31
   *  Methoden-Implementierungen in Text.cpp
32
   *  Testumgebung mit main in TextTest.cpp
33
   *  Sie dürfen Funktionen aus string.h verwenden, z.B. strlen, strcpy
34
*/
35
36
#include <cstdlib>
37
#include <iostream>
38
#include <conio.h>
39
#include "Text.hpp"
40
using namespace std;
41
42
int main(int argc, char *argv[])
43
{
44
    Text meintext("01234567890123");
45
    Text anhang("");
46
47
    cout<<".ausgeben"<<endl;
48
    meintext.ausgeben();
49
    cout<<endl;
50
    cout<<".rueckwaertsausgeben"<<endl;
51
    meintext.rueckwaertsAusgeben();
52
    cout<<endl;
53
    //meintext.anhaengen(anhang);
54
    meintext.ausgeben();
55
56
    meintext.gesperrt(1);
57
    cout<<"Ausgabe:"<<endl;
58
    meintext.ausgeben();
59
    cout<<"textr"<<endl;
60
    system("PAUSE");
61
    return EXIT_SUCCESS;
62
}
Text.hpp:
1
class Text
2
{
3
private:
4
    char* Textfeld;
5
    int lg;
6
7
public:
8
    Text();
9
    Text(char zkette[]);
10
    void rueckwaertsAusgeben();
11
    void ausgeben();
12
    void anhaengen(Text t);
13
    void gesperrt(int n);
14
};
Text.cpp:
1
using namespace std;
2
#include <iostream>
3
#include "text.hpp"
4
5
void Text::gesperrt(int n)
6
{
7
    int gesplg=(lg)*n+lg;     //Anzahl der Leerzeichen + Stringlänge
8
    char* Textfeld2;
9
    Textfeld2 = new char(lg);
10
    for(int i=0;i<lg;i++)      //Kopieren des Original-Texts
11
        Textfeld2[i]=Textfeld[i];
12
    Textfeld2[lg]='\0';
13
    cout<<"Textfeld 2 = "<<Textfeld2<<endl;
14
    cout<<"Gesplg     = "<<gesplg<<endl;
15
    cout<<"lg         = "<<lg<<endl;
16
    cout<<"n          = "<<n<<endl;
17
    lg=gesplg;
18
    Textfeld = new char(lg);    //Zeiger auf neues verlängertes Feld
19
    for(int i=0;i<(lg-1);i++)
20
    {
21
        if(i%2)                 //jedes 2. mal Angefangen von pos 0
22
        {
23
           Textfeld[i]='@';
24
            cout<<"Textfeld["<<i<<"]='"<<Textfeld[i]<<"';"<<endl;
25
        }
26
        else
27
        {
28
            Textfeld[i]=Textfeld2[(i/2)];
29
            cout<<"textfeld2["<<(i/2)<<"] = "<<Textfeld2[(i/2)]<<endl;
30
            cout<<"textfeld["<<i<<"] = "<<Textfeld[i]<<endl;
31
        }
32
33
    }
34
    Textfeld[(lg-1)]='\0';
35
}
36
37
void Text::anhaengen(Text t)
38
{
39
    int lgt=t.lg;
40
    int lgges=lgt+lg;
41
    char* Textfeld2;
42
    Textfeld2 = new char((lgges));
43
    for(int i=0;i<lg;i++)
44
    {
45
        Textfeld2[i]=Textfeld[i];
46
        //cout<<"textfeld["<<i<<"] = "<<Textfeld[i]<<endl;
47
        //cout<<"Textfeld2["<<i<<"] = "<<Textfeld2[i]<<endl;
48
    }
49
    for(int i=0;i<lgt;i++)
50
    {
51
        Textfeld2[i+lg]=t.Textfeld[i];
52
        //cout<<"t.textfeld["<<i<<"] = "<<t.Textfeld[i]<<endl;
53
        //cout<<"t.Textfeld2["<<i<<"+"<<lg<<"] = "<<Textfeld2[i+lg]<<endl;
54
    }
55
    Textfeld2[lgges]='\0';
56
    //cout<<"Textfeld2 = "<<Textfeld2<<endl;
57
    //cout<<"Textfeld  = "<<Textfeld<<endl;
58
    //cout<<"lgt       = "<<lgt<<endl;
59
    lg=lgges;
60
    Textfeld = new char((lg));
61
    for(int i=0;i<lg;i++)
62
        Textfeld[i]=Textfeld2[i];
63
    Textfeld[(lg)]='\0';        //Nullbyte Anhängen
64
    //cout<<"Textfeld = "<<Textfeld<<endl;
65
}
66
67
Text::Text()
68
{
69
    lg=1;
70
    Textfeld = new char(lg);
71
    Textfeld[0]='\0';
72
}
73
74
Text::Text(char zkette[])
75
{
76
    lg=0;
77
    for(int i=0;zkette[i]!='\0';i++)
78
        lg++;
79
    Textfeld = new char(lg);
80
    for(int i=0;i<lg;i++)
81
        Textfeld[i]=zkette[i];
82
    Textfeld[lg]='\0';
83
}
84
85
void Text::ausgeben()
86
{
87
88
        cout<<Textfeld;
89
    cout<<endl;
90
}
91
92
void Text::rueckwaertsAusgeben()
93
{
94
    for(int i=(lg-1);i>=0;i--)
95
        cout<<Textfeld[i];
96
}
Danke für Eure Antworten.

von Karl H. (kbuchegg)


Lesenswert?

Du allokierst konsequent, zum Beispiel hier

>     Textfeld = new char(lg);

immer einen char zu wenig.

Zumindest ist das die Idee. Tatsächlich machst du hier etwas ganz 
anderes. Das was du geschrieben hast, ist die Allokierung eines einzigen 
char, welcher mit lg initialisiert wird.

      Textfeld = new char [lg];

und dabei hast du einen char zu wenig allokiert

    Textfeld = new char [lg+1];


Um einen String der Länge 5, zb. "Hallo", abzuspeichern, benötigst du 
ein Array der Länge 6, weil ja das abschliessende '\0' auch Speicher 
braucht.

Und dieser Fehler (eigentlich beide) zieht sich quer durch dein ganzes 
Programm.


Edit:
Du kannst auch zb das als Faustregel-Test benutzen

   Textfeld = new char [lg];
   ...
   Textfeld[lg]='\0';

das kann nicht sein, dass du hier mit dem Index lg zugreifst, wenn du 
ein Array mit der Länge lg allokierst.
Ein Array der Länge 4 sieht so aus

      0   1   2   3
    +---+---+---+---+
    |   |   |   |   |
    +---+---+---+---+

über die Felder hab ich dir den jeweiligen Index geschrieben. Der 
höchste benutzbare Index in einem Array ist immer um 1 kleiner als die 
Arraylänge. In einem Array der Länge 4 gibt es daher nur die Elemente 0, 
1, 2, 3. Und das sind 4 Stück.
In einem Array der Länge lg, und genau so eines hast du ja hier
   Textfeld = new char [lg];
allokiert, ist der höchste benutzbare Index daher lg-1.
Eine Zusweisung an ein Arrayelement mit dem Index lg ist daher illegal.

Aber: allokierst du um 1 Element mehr
   Textfeld = new char [lg+1];
dann wird
   Textfeld[lg]='\0';

natürlich legal, denn jetzt gibt es ja ein Element mit diesem Index, 
weil du ja entsprechend viele Arrayelemente allokiert hast.


Die zweite Faustregel lautet: Bei der Allokierung von Arrays für Strings 
hat man meistens im arithmetischen Ausdruck für die zu allokierende 
Größe ein +1 drinnen. Fehlt das, dann sollte man sich die Sache gut 
ansehen ob das so richtig ist. Meistens hat man einen Fehler gemacht.

von Sven P. (Gast)


Lesenswert?

Hats außerdem nen triftigen Grund, weshalb du nicht std::string benutzt?

von Sven B. (scummos)


Lesenswert?

Hi!

Valgrind findet solche Fehler i.d.R. sofort, ein manuelles Suchen lohnt 
sich kaum.

valgrind --tool=memcheck --track-origins=yes ./programm

Grüße,
Sven

P.S.: Hier:
1
sven@localhost » /tmp » valgrind ./test --tool=memcheck --track-origins=yes
2
==9636== Memcheck, a memory error detector
3
==9636== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
4
==9636== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
5
==9636== Command: ./test --tool=memcheck --track-origins=yes
6
==9636== 
7
==9636== Invalid write of size 1
8
==9636==    at 0x4010D2: Text::Text(char*) (text.cpp:81)
9
==9636==    by 0x400A5B: main (KlasseText.cpp:43)
10
==9636==  Address 0x59ec041 is 0 bytes after a block of size 1 alloc'd
11
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
12
==9636==    by 0x401099: Text::Text(char*) (text.cpp:79)
13
==9636==    by 0x400A5B: main (KlasseText.cpp:43)
14
==9636== 
15
==9636== Invalid write of size 1
16
==9636==    at 0x4010FC: Text::Text(char*) (text.cpp:82)
17
==9636==    by 0x400A5B: main (KlasseText.cpp:43)
18
==9636==  Address 0x59ec04e is 13 bytes after a block of size 1 alloc'd
19
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
20
==9636==    by 0x401099: Text::Text(char*) (text.cpp:79)
21
==9636==    by 0x400A5B: main (KlasseText.cpp:43)
22
==9636== 
23
.ausgeben
24
==9636== Invalid read of size 1
25
==9636==    at 0x4C2CA84: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
26
==9636==    by 0x4EC8E60: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (in /usr/lib/libstdc++.so.6.0.17)
27
==9636==    by 0x401121: Text::ausgeben() (text.cpp:88)
28
==9636==    by 0x400A94: main (KlasseText.cpp:47)
29
==9636==  Address 0x59ec041 is 0 bytes after a block of size 1 alloc'd
30
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
31
==9636==    by 0x401099: Text::Text(char*) (text.cpp:79)
32
==9636==    by 0x400A5B: main (KlasseText.cpp:43)
33
==9636== 
34
==9636== Invalid read of size 1
35
==9636==    at 0x56BA70D: _IO_file_xsputn@@GLIBC_2.2.5 (in /usr/lib/libc-2.16.so)
36
==9636==    by 0x56B05EC: fwrite (in /usr/lib/libc-2.16.so)
37
==9636==    by 0x4EC8BE3: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/libstdc++.so.6.0.17)
38
==9636==    by 0x4EC8E6E: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (in /usr/lib/libstdc++.so.6.0.17)
39
==9636==    by 0x401121: Text::ausgeben() (text.cpp:88)
40
==9636==    by 0x400A94: main (KlasseText.cpp:47)
41
==9636==  Address 0x59ec04d is 12 bytes after a block of size 1 alloc'd
42
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
43
==9636==    by 0x401099: Text::Text(char*) (text.cpp:79)
44
==9636==    by 0x400A5B: main (KlasseText.cpp:43)
45
==9636== 
46
==9636== Invalid read of size 1
47
==9636==    at 0x56BA729: _IO_file_xsputn@@GLIBC_2.2.5 (in /usr/lib/libc-2.16.so)
48
==9636==    by 0x56B05EC: fwrite (in /usr/lib/libc-2.16.so)
49
==9636==    by 0x4EC8BE3: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/libstdc++.so.6.0.17)
50
==9636==    by 0x4EC8E6E: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (in /usr/lib/libstdc++.so.6.0.17)
51
==9636==    by 0x401121: Text::ausgeben() (text.cpp:88)
52
==9636==    by 0x400A94: main (KlasseText.cpp:47)
53
==9636==  Address 0x59ec04c is 11 bytes after a block of size 1 alloc'd
54
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
55
==9636==    by 0x401099: Text::Text(char*) (text.cpp:79)
56
==9636==    by 0x400A5B: main (KlasseText.cpp:43)
57
==9636== 
58
==9636== Invalid read of size 2
59
==9636==    at 0x56CB92B: __GI_mempcpy (in /usr/lib/libc-2.16.so)
60
==9636==    by 0x56BA641: _IO_file_xsputn@@GLIBC_2.2.5 (in /usr/lib/libc-2.16.so)
61
==9636==    by 0x56B05EC: fwrite (in /usr/lib/libc-2.16.so)
62
==9636==    by 0x4EC8BE3: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/libstdc++.so.6.0.17)
63
==9636==    by 0x4EC8E6E: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (in /usr/lib/libstdc++.so.6.0.17)
64
==9636==    by 0x401121: Text::ausgeben() (text.cpp:88)
65
==9636==    by 0x400A94: main (KlasseText.cpp:47)
66
==9636==  Address 0x59ec040 is 0 bytes inside a block of size 1 alloc'd
67
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
68
==9636==    by 0x401099: Text::Text(char*) (text.cpp:79)
69
==9636==    by 0x400A5B: main (KlasseText.cpp:43)
70
==9636== 
71
==9636== Invalid read of size 4
72
==9636==    at 0x56CB93E: __GI_mempcpy (in /usr/lib/libc-2.16.so)
73
==9636==    by 0x56BA641: _IO_file_xsputn@@GLIBC_2.2.5 (in /usr/lib/libc-2.16.so)
74
==9636==    by 0x56B05EC: fwrite (in /usr/lib/libc-2.16.so)
75
==9636==    by 0x4EC8BE3: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/libstdc++.so.6.0.17)
76
==9636==    by 0x4EC8E6E: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (in /usr/lib/libstdc++.so.6.0.17)
77
==9636==    by 0x401121: Text::ausgeben() (text.cpp:88)
78
==9636==    by 0x400A94: main (KlasseText.cpp:47)
79
==9636==  Address 0x59ec042 is 1 bytes after a block of size 1 alloc'd
80
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
81
==9636==    by 0x401099: Text::Text(char*) (text.cpp:79)
82
==9636==    by 0x400A5B: main (KlasseText.cpp:43)
83
==9636== 
84
==9636== Invalid read of size 8
85
==9636==    at 0x56CB94F: __GI_mempcpy (in /usr/lib/libc-2.16.so)
86
==9636==    by 0x56BA641: _IO_file_xsputn@@GLIBC_2.2.5 (in /usr/lib/libc-2.16.so)
87
==9636==    by 0x56B05EC: fwrite (in /usr/lib/libc-2.16.so)
88
==9636==    by 0x4EC8BE3: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/libstdc++.so.6.0.17)
89
==9636==    by 0x4EC8E6E: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (in /usr/lib/libstdc++.so.6.0.17)
90
==9636==    by 0x401121: Text::ausgeben() (text.cpp:88)
91
==9636==    by 0x400A94: main (KlasseText.cpp:47)
92
==9636==  Address 0x59ec046 is 5 bytes after a block of size 1 alloc'd
93
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
94
==9636==    by 0x401099: Text::Text(char*) (text.cpp:79)
95
==9636==    by 0x400A5B: main (KlasseText.cpp:43)
96
==9636== 
97
01234567890123
98
99
.rueckwaertsausgeben
100
==9636== Invalid read of size 1
101
==9636==    at 0x40115E: Text::rueckwaertsAusgeben() (text.cpp:95)
102
==9636==    by 0x400ACB: main (KlasseText.cpp:50)
103
==9636==  Address 0x59ec04d is 12 bytes after a block of size 1 alloc'd
104
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
105
==9636==    by 0x401099: Text::Text(char*) (text.cpp:79)
106
==9636==    by 0x400A5B: main (KlasseText.cpp:43)
107
==9636== 
108
32109876543210
109
==9636== Invalid read of size 1
110
==9636==    at 0x4C2CA84: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
111
==9636==    by 0x4EC8E60: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (in /usr/lib/libstdc++.so.6.0.17)
112
==9636==    by 0x401121: Text::ausgeben() (text.cpp:88)
113
==9636==    by 0x400AE6: main (KlasseText.cpp:53)
114
==9636==  Address 0x59ec041 is 0 bytes after a block of size 1 alloc'd
115
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
116
==9636==    by 0x401099: Text::Text(char*) (text.cpp:79)
117
==9636==    by 0x400A5B: main (KlasseText.cpp:43)
118
==9636== 
119
01234567890123
120
==9636== Invalid read of size 1
121
==9636==    at 0x400C01: Text::gesperrt(int) (text.cpp:11)
122
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
123
==9636==  Address 0x59ec041 is 0 bytes after a block of size 1 alloc'd
124
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
125
==9636==    by 0x401099: Text::Text(char*) (text.cpp:79)
126
==9636==    by 0x400A5B: main (KlasseText.cpp:43)
127
==9636== 
128
==9636== Invalid write of size 1
129
==9636==    at 0x400C04: Text::gesperrt(int) (text.cpp:11)
130
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
131
==9636==  Address 0x59ec0e1 is 0 bytes after a block of size 1 alloc'd
132
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
133
==9636==    by 0x400BCE: Text::gesperrt(int) (text.cpp:9)
134
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
135
==9636== 
136
==9636== Invalid write of size 1
137
==9636==    at 0x400C2C: Text::gesperrt(int) (text.cpp:12)
138
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
139
==9636==  Address 0x59ec0ee is 13 bytes after a block of size 1 alloc'd
140
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
141
==9636==    by 0x400BCE: Text::gesperrt(int) (text.cpp:9)
142
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
143
==9636== 
144
==9636== Invalid read of size 1
145
==9636==    at 0x4C2CA84: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
146
==9636==    by 0x4EC8E60: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (in /usr/lib/libstdc++.so.6.0.17)
147
==9636==    by 0x400C4C: Text::gesperrt(int) (text.cpp:13)
148
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
149
==9636==  Address 0x59ec0e1 is 0 bytes after a block of size 1 alloc'd
150
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
151
==9636==    by 0x400BCE: Text::gesperrt(int) (text.cpp:9)
152
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
153
==9636== 
154
Textfeld 2 = 01234567890123
155
Gesplg     = 28
156
lg         = 14
157
n          = 1
158
textfeld2[0] = 0
159
textfeld[0] = 0
160
==9636== Invalid write of size 1
161
==9636==    at 0x400D22: Text::gesperrt(int) (text.cpp:23)
162
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
163
==9636==  Address 0x59ec131 is 0 bytes after a block of size 1 alloc'd
164
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
165
==9636==    by 0x400CEC: Text::gesperrt(int) (text.cpp:18)
166
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
167
==9636== 
168
==9636== Invalid read of size 1
169
==9636==    at 0x400D34: Text::gesperrt(int) (text.cpp:24)
170
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
171
==9636==  Address 0x59ec131 is 0 bytes after a block of size 1 alloc'd
172
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
173
==9636==    by 0x400CEC: Text::gesperrt(int) (text.cpp:18)
174
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
175
==9636== 
176
Textfeld[1]='@';
177
==9636== Invalid read of size 1
178
==9636==    at 0x400DB1: Text::gesperrt(int) (text.cpp:28)
179
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
180
==9636==  Address 0x59ec0e1 is 0 bytes after a block of size 1 alloc'd
181
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
182
==9636==    by 0x400BCE: Text::gesperrt(int) (text.cpp:9)
183
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
184
==9636== 
185
==9636== Invalid write of size 1
186
==9636==    at 0x400DB4: Text::gesperrt(int) (text.cpp:28)
187
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
188
==9636==  Address 0x59ec132 is 1 bytes after a block of size 1 alloc'd
189
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
190
==9636==    by 0x400CEC: Text::gesperrt(int) (text.cpp:18)
191
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
192
==9636== 
193
==9636== Invalid read of size 1
194
==9636==    at 0x400DCC: Text::gesperrt(int) (text.cpp:29)
195
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
196
==9636==  Address 0x59ec0e1 is 0 bytes after a block of size 1 alloc'd
197
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
198
==9636==    by 0x400BCE: Text::gesperrt(int) (text.cpp:9)
199
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
200
==9636== 
201
textfeld2[1] = 1
202
==9636== Invalid read of size 1
203
==9636==    at 0x400E2E: Text::gesperrt(int) (text.cpp:30)
204
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
205
==9636==  Address 0x59ec132 is 1 bytes after a block of size 1 alloc'd
206
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
207
==9636==    by 0x400CEC: Text::gesperrt(int) (text.cpp:18)
208
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
209
==9636== 
210
textfeld[2] = 1
211
Textfeld[3]='@';
212
textfeld2[2] = 2
213
textfeld[4] = 2
214
Textfeld[5]='@';
215
textfeld2[3] = 3
216
textfeld[6] = 3
217
Textfeld[7]='@';
218
textfeld2[4] = 4
219
textfeld[8] = 4
220
Textfeld[9]='@';
221
textfeld2[5] = 5
222
textfeld[10] = 5
223
Textfeld[11]='@';
224
textfeld2[6] = 6
225
textfeld[12] = 6
226
Textfeld[13]='@';
227
textfeld2[7] = 7
228
textfeld[14] = 7
229
Textfeld[15]='@';
230
textfeld2[8] = 8
231
textfeld[16] = 8
232
Textfeld[17]='@';
233
textfeld2[9] = 9
234
textfeld[18] = 9
235
Textfeld[19]='@';
236
textfeld2[10] = 0
237
textfeld[20] = 0
238
Textfeld[21]='@';
239
textfeld2[11] = 1
240
textfeld[22] = 1
241
Textfeld[23]='@';
242
textfeld2[12] = 2
243
textfeld[24] = 2
244
Textfeld[25]='@';
245
textfeld2[13] = 3
246
textfeld[26] = 3
247
==9636== Invalid write of size 1
248
==9636==    at 0x400EA7: Text::gesperrt(int) (text.cpp:34)
249
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
250
==9636==  Address 0x59ec14b is not stack'd, malloc'd or (recently) free'd
251
==9636== 
252
Ausgabe:
253
==9636== Invalid read of size 1
254
==9636==    at 0x4C2CA84: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
255
==9636==    by 0x4EC8E60: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (in /usr/lib/libstdc++.so.6.0.17)
256
==9636==    by 0x401121: Text::ausgeben() (text.cpp:88)
257
==9636==    by 0x400B1F: main (KlasseText.cpp:57)
258
==9636==  Address 0x59ec131 is 0 bytes after a block of size 1 alloc'd
259
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
260
==9636==    by 0x400CEC: Text::gesperrt(int) (text.cpp:18)
261
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
262
==9636== 
263
==9636== Invalid read of size 8
264
==9636==    at 0x56CB970: __GI_mempcpy (in /usr/lib/libc-2.16.so)
265
==9636==    by 0x56BA641: _IO_file_xsputn@@GLIBC_2.2.5 (in /usr/lib/libc-2.16.so)
266
==9636==    by 0x56B05EC: fwrite (in /usr/lib/libc-2.16.so)
267
==9636==    by 0x4EC8BE3: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/libstdc++.so.6.0.17)
268
==9636==    by 0x4EC8E6E: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (in /usr/lib/libstdc++.so.6.0.17)
269
==9636==    by 0x401121: Text::ausgeben() (text.cpp:88)
270
==9636==    by 0x400B1F: main (KlasseText.cpp:57)
271
==9636==  Address 0x59ec13b is 10 bytes after a block of size 1 alloc'd
272
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
273
==9636==    by 0x400CEC: Text::gesperrt(int) (text.cpp:18)
274
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
275
==9636== 
276
==9636== Invalid read of size 8
277
==9636==    at 0x56CB973: __GI_mempcpy (in /usr/lib/libc-2.16.so)
278
==9636==    by 0x56BA641: _IO_file_xsputn@@GLIBC_2.2.5 (in /usr/lib/libc-2.16.so)
279
==9636==    by 0x56B05EC: fwrite (in /usr/lib/libc-2.16.so)
280
==9636==    by 0x4EC8BE3: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) (in /usr/lib/libstdc++.so.6.0.17)
281
==9636==    by 0x4EC8E6E: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (in /usr/lib/libstdc++.so.6.0.17)
282
==9636==    by 0x401121: Text::ausgeben() (text.cpp:88)
283
==9636==    by 0x400B1F: main (KlasseText.cpp:57)
284
==9636==  Address 0x59ec143 is 18 bytes after a block of size 1 alloc'd
285
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
286
==9636==    by 0x400CEC: Text::gesperrt(int) (text.cpp:18)
287
==9636==    by 0x400AF7: main (KlasseText.cpp:55)
288
==9636== 
289
0@1@2@3@4@5@6@7@8@9@0@1@2@3
290
textr
291
==9636== 
292
==9636== HEAP SUMMARY:
293
==9636==     in use at exit: 4 bytes in 4 blocks
294
==9636==   total heap usage: 4 allocs, 0 frees, 4 bytes allocated
295
==9636== 
296
==9636== LEAK SUMMARY:
297
==9636==    definitely lost: 4 bytes in 4 blocks
298
==9636==    indirectly lost: 0 bytes in 0 blocks
299
==9636==      possibly lost: 0 bytes in 0 blocks
300
==9636==    still reachable: 0 bytes in 0 blocks
301
==9636==         suppressed: 0 bytes in 0 blocks
302
==9636== Rerun with --leak-check=full to see details of leaked memory
303
==9636== 
304
==9636== For counts of detected and suppressed errors, rerun with: -v
305
==9636== ERROR SUMMARY: 280 errors from 24 contexts (suppressed: 2 from 2)

Übrigens, dein Code ist schmerzhaft zu übsetzen...
* Windows-Systemaufrufe wo es überhaupt nicht nötig ist (läuft bei mir 
natürlich nicht)
* du includest irgendwelche komischen msdos-libs, die du dann nichtmal 
benutzt
* du beachtest Groß- und Kleinschreibung bei den Dateinamen nicht, was 
bei mir natürlich auch nicht funktioniert
Fix das bitte! ;)

von Karl H. (kbuchegg)


Lesenswert?

PS
Deine Funktion 'gesperrt' kommt mir EXTREMST kompliziert vor. Aus 
welchem Grunde allokierst du da wie ein Wilder Speicher?

Du brauchst EINE (1) neue Speicherfläche in entsprechender Größe. Mehr 
braucht es doch nicht. Und den alten Speicher musst du natürlich auch 
irgendwann mal freigeben, was du nicht tust


(OK. Destruktor hast du auch noch keinen. Aber das sehe ich dir als 
'noch zu implementieren' nach. CCTor und op= lassen wir mal aussen vor, 
auch wenn sie notwendig wären, aber auch Rom ist nicht an einem Tag 
erbaut worden)

: Wiederhergestellt durch User
von Sven B. (scummos)


Lesenswert?

Hm, vielleicht erläutere ich den Valgrind-Output mal noch ;)
1
==9636== Invalid write of size 1
2
==9636==    at 0x4010D2: Text::Text(char*) (text.cpp:81)
3
==9636==    by 0x400A5B: main (KlasseText.cpp:43)
4
==9636==  Address 0x59ec041 is 0 bytes after a block of size 1 alloc'd
5
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
6
==9636==    by 0x401099: Text::Text(char*) (text.cpp:79)
7
==9636==    by 0x400A5B: main (KlasseText.cpp:43)
Dieser Block bezeichnet einen einzelnen Fehler im Zugriff auf den 
Speicher. Du hast in diesem Fall in Speicher geschrieben, den du vorher 
nicht reserviert hattest, und zwar laut
1
==9636== Invalid write of size 1
genau 1 byte.
Dann sagt das Programm, wo das passert ist:
1
==9636==    at 0x4010D2: Text::Text(char*) (text.cpp:81)
2
==9636==    by 0x400A5B: main (KlasseText.cpp:43)
nämlich in Zeile 81 in text.cpp in der Funktion Text::Text(char*). Der 
Aufruf dieser Funktion erfolgte von KlasseText.cpp:43 in der Funktion 
main().

Dann steht da, was das Problem ist:
1
==9636==  Address 0x59ec041 is 0 bytes after a block of size 1 alloc'd
Du hast auf Adresse 0x59ec041 ein Byte geschrieben, hattest aber nur den 
Speicher vor dieser Adresse reserviert.
Reserviert hattest du den Speicher hier:
1
==9636==    at 0x4C2BA77: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
2
==9636==    by 0x401099: Text::Text(char*) (text.cpp:79)
3
==9636==    by 0x400A5B: main (KlasseText.cpp:43)
Die erste Zeile kannst du ignorieren, das ist intern. Die zweite und 
dritte geben aber wieder den Backtrace an, wo du den Speicher reserviert 
hattest. Das ist die Stelle, wo du nach dem Fehler suchen musst, weil du 
da zu wenig Speicher reserviert hast, nämlich 1 Byte. Wenn du ein Byte 
mehr reservierst, geht die Meldung weg.

Jede dieser Meldungen (jeder solche Block in der Ausgabe) bedeutet einen 
potentiellen Absturz, du musst sie also alle beheben.

Grüße,
Sven

von Programmieren - Lerner (Gast)


Lesenswert?

Danke für die schnellen antworten.
Ihr habt recht,

Ich alokierte zu wenig Speicher,
konnte durch die nutzung von strlen eine Scheife einpsaren.
Dazu waren meine Sprren, Anhängen + der Konstruktor je um eine schleife 
zu kompliziert.
Denn ich muss ja nur die Addresse des 1. Feldelements des neu erzeugten 
feldes zurückgeben, statt es zurück zu kopieren.

Dies ist nun behoben, jedoch ist die Funktionalität die selbe wie zuvor.
Bei längeren Strings kommt am Ende der Fehler, ich würde auf falsche 
Addressen zufreifen.

Solange die Textlänge 11 Zeichen nicht überschreitet funktioniert es.

Nun sieht es so aus:


Text.cpp:
1
using namespace std;
2
#include <iostream>
3
#include <string.h>
4
#include "text.hpp"
5
6
void Text::gesperrt(int n)
7
{
8
    cout<<"lg = "<<lg<<endl;    //LG beinhaltet Anzahl von Elementen!
9
    lg=(2*(lg-2))+2;     //-1 Wegen Anzahl zu Index, -1 wegen NULL, , 1 NULL Addieren
10
    cout<<"Array-Elemente zur Verfügung "<<lg<<endl;
11
    char* Textfeld2;
12
    Textfeld2 = new char(lg);       //lg=Elementanzahl
13
    for(int i=0;i<(lg-1);i++)
14
    {
15
        if (!(i%2))                    //Bei 0,2,4
16
        {
17
            Textfeld2[i]=Textfeld[(i/2)];
18
        }
19
        else if(Textfeld[((i/2)+1)]=='\0')
20
        {
21
            Textfeld2[i]='\0';
22
            break;
23
        }
24
        else                  //Bei 1,3,5
25
        {
26
            Textfeld2[i]='@';
27
        }
28
29
    }
30
    Textfeld = &Textfeld2[0];    //Zeiger auf neues verlängertes Feld, 1. Element
31
}
32
33
void Text::anhaengen(Text t)
34
{
35
    int lgt=t.lg;
36
    int lgges=lgt+lg-1;
37
    char* Textfeld2;
38
    Textfeld2 = new char(lgges);
39
    for(int i=0;i<lg;i++)
40
    {
41
        Textfeld2[i]=Textfeld[i];
42
        //cout<<"textfeld["<<i<<"] = "<<Textfeld[i]<<endl;
43
        //cout<<"Textfeld2["<<i<<"] = "<<Textfeld2[i]<<endl;
44
    }
45
    for(int i=0;i<lgt;i++)
46
    {
47
        Textfeld2[i+(lg-1)]=t.Textfeld[i];
48
        //cout<<"t.textfeld["<<i<<"] = "<<t.Textfeld[i]<<endl;
49
        //cout<<"t.Textfeld2["<<i<<"+"<<(lg-1)<<"] = "<<Textfeld2[i+(lg-1)]<<endl;
50
    }
51
    Textfeld2[lgges]='\0';
52
    lg=lgges;
53
    Textfeld = &Textfeld2[0];
54
}
55
56
Text::Text()
57
{
58
    lg=1;
59
    Textfeld = new char(lg);
60
    Textfeld[0]='\0';
61
}
62
63
Text::Text(char zkette[])
64
{
65
    lg=(strlen(zkette)+1);
66
    Textfeld = &zkette[0];      //Zeigt auf 1. Element der Zeichenkette
67
}
68
69
void Text::ausgeben()
70
{
71
    cout<<Textfeld;
72
    cout<<endl;
73
}
74
75
void Text::rueckwaertsAusgeben()
76
{
77
    for(int i=(lg-1);i>=0;i--)
78
        cout<<Textfeld[i];
79
}

KlasseText.cpp:
1
#include <cstdlib>
2
#include <iostream>
3
#include <conio.h>
4
#include "Text.hpp"
5
using namespace std;
6
7
int main(int argc, char *argv[])
8
{
9
    Text meintext("0123456789");
10
    Text t2("0123");
11
    cout<<".ausgeben"<<endl;
12
    meintext.ausgeben();
13
    cout<<endl;
14
    meintext.anhaengen(t2);
15
    cout<<"Ausgabe:"<<endl;
16
    meintext.ausgeben();
17
    meintext.gesperrt(1);
18
    cout<<"Ausgabe:"<<endl;
19
    //meintext.ausgeben();
20
    cout<<"textr"<<endl;
21
    system("PAUSE");
22
    return EXIT_SUCCESS;
23
}

Text.hpp:
1
class Text
2
{
3
private:
4
    char* Textfeld;
5
    int lg;
6
7
public:
8
    Text();
9
    Text(char zkette[]);
10
    void rueckwaertsAusgeben();
11
    void ausgeben();
12
    void anhaengen(Text t);
13
    void gesperrt(int n);
14
};

von Karl H. (kbuchegg)


Lesenswert?

Das hier

>     Textfeld2 = new char(lgges);

allokiert KEIN Array.
Es allokiert einen einzelnen char und initialisiert ihn mit lgges.
Schau dir ALLE deine new durch! Da sind noch mehr derartige Fehler!

Dein Code ist an einigen Stellen problematisch. Da du am ANfang lauter 
Stringliterale hast, könnte das alles im Moment sogar klappen, aber 
sauber ist es nicht. Jetzt hast du zuviel eingespart!

Dein Konstruktor sollte eigentlich so aussehen
1
Text::Text(char zkette[])
2
{
3
    lg = strlen(zkette)+1;
4
    Textfeld = new char [lg];
5
    strcpy( Textfeld, zkette );
6
}
und sich den übergebenen String in die Klasse kopieren. Wie gesagt, da 
du die Objekte mit konstanten String-Literalen intialisierst, kommst du 
damit im Moment damit davon. Auch hast du noch keinen Destruktor. Was 
soll der tun, Soll er den Speicher freigeben (weil mit new 
initialisiert) oder soll er es nicht tun (weil du den Pointer vom 
Aufrufer übernommen hast)? Spätestens dann wirst du ohne Allokierung und 
strcpy in enorme Schwierigkeiten laufen.

Wenn du allerdings auf Allokieren und strcpy gehst, musst du unter allen 
Umständen verhindern, dass Text Objekte kopiert werden. Denn der 
Default-Copy Constructor macht das falsche, wenn er eine memberweise 
Kopie anlegt. Du kopierst aber hier
1
void Text::anhaengen(Text t)

ein Textobjekt, wenn du es übergibst. Und das ist nicht gut. Übergib es 
hier als Referenz, dann löst sich dieses Teilproblem selber
1
void Text::anhaengen(Text& t)


Damit dir keine unbeabsichtigte Objektkopie passiert, füge in deine 
Klasse in Text.hpp am Ende diese 3 Zeilen ein.
1
   ....
2
    void gesperrt(int n);
3
4
private:
5
   Text( const Text& rhs );
6
   Text operator=( const Text& rhs );
7
};
dann passen Compiler und Linker auf dich auf, dass du nicht irgendwo 
irrtümlich ein Text Objekt kopierst. De facto wurden die beiden 
kritischen Operationen dadurch für diese Klasse unbrauchbar gemacht und 
es gibt eine Fehlermeldung vom Compiler/Linker, wenn du sie doch zu 
benutzen versuchst.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.