Forum: PC-Programmierung String löschen mit .clear()


von Michael S. (michaelsmith)


Lesenswert?

Hallo,

bin mit dem String durcheinander gekommen. Idee ist, über Konsole werden 
ganze Zahlen eingetippt, daraus soll eine gerade und ungerade Summe 
gebildet werden, hier ein Ausschnitt;
1
// *ptrToArray - pointer to the data array
2
// arrayLength - length of the array
3
// vector - contains indices of the array with value of space '32'
4
void numberSeparation(char *ptrToArray, int arrayLength, std::vector<int> vector)
5
{
6
    std::string tempString;
7
    int i = 0;  //index for tempBuffer to store number temporarly
8
    int z = 0;  //index of vector, containing the space locations
9
    double evenSum = 0;
10
    double oddSum = 0;
11
12
    for(int y = 0; y < arrayLength;)
13
    {
14
        // copy data only if no space currently read
15
        if(ptrToArray[y] != 32)
16
        {
17
            tempString[i] = ptrToArray[y];
18
            i++;
19
        }
20
        y++;
21
22
        //get last char
23
        if(y == arrayLength)
24
        {
25
            tempString[i] = ptrToArray[y];
26
        }
27
28
        // if case space index present or end of string reached
29
        if((y == vector[z]) || (y == arrayLength))
30
        {
31
            if(stoi(tempString)%2 == 0)
32
            {
33
                 evenSum += stoi(tempString);
34
                 std::cout<<"evenSum : "<<evenSum<<std::endl;
35
            }
36
            else
37
            {
38
                oddSum += stoi(tempString);
39
                std::cout<<"oddSum : "<<oddSum<<std::endl;
40
            }
41
42
            tempString.clear();
43
44
            // increment the vector index only till the last valid entry
45
            if((vector.size()) > z)
46
            {
47
                std::cout<<"z : "<<z<<std::endl;
48
                z++;
49
            }
50
            
51
            i = 0;
52
        }
53
        
54
    }
55
56
    std::cout<<"even sum : "<<evenSum<<std::endl;
57
    std::cout<<"odd sum : "<<oddSum<<std::endl;
58
59
}

Problem was ich habe ist, dass anscheinend mein tempString nicht immer 
komplett gelöscht wird
1
provide set of whole munbers : 
2
2 4 3 88 7 4 65 06
3
evenSum : 2
4
z : 0
5
evenSum : 6
6
z : 1
7
oddSum : 3
8
z : 2
9
evenSum : 94
10
z : 3
11
evenSum : 172 --> hier wird statt mit 7 und oddSum mit 78 und evenSum gearbeitet, d.h. der 88 von vorher wird überschrieben !!
12
z : 4
13
evenSum : 220
14
z : 5
15
oddSum : 68
16
z : 6
17
evenSum : 226
18
19
even sum : 226
20
odd sum : 68
21
22
numbers entered: 2 4 3 88 7 4 65 06

VG
Michael

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Dein tempString hat immer Länge 0, weil du ihn nie vergrößerst bzw. eine 
Größe an den Konstruktor übergibst. Die Zugriffe tempString[i] sind 
somit Out-Of-Bounds-Fehler.

: Bearbeitet durch User
von Michael B. (laberkopp)


Lesenswert?

Michael S. schrieb:
> Problem was ich habe ist, dass anscheinend mein tempString nicht immer
> komplett gelöscht wird

Ja, nicht nur.

Problem ist, dass du völlig am schwimmen bist bei deiner Hausaufgabe.

Nett auch der nutzlos mitgeführte vector.

Da ist das Reingrätschen in tempString ja noch harmlos.

Mach halt den Programmierkurs nochmal, bisher hast du nicht verstanden, 
wie man programmiert.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Du kannst nicht auf das i'te Zeichen eines leeren Strings zugreifen.
1
  tempString.push_back(ptrToArray[y]);

wäre eine gültige Methode. Viele STLs haben eine Möglichkeit, solche 
Fehler zur Laufzeit zu erkennen. Guck mal, welche Möglichkeiten Dein 
Compiler hat. Das würde Dir eine Menge Zeit sparen.

Namen, wie `ptrToArray` haben kaum Informationen, weil nur der Typ im 
Namen kodiert ist, aber nicht der Zweck / Rolle des Parameters.

von Michael S. (michaelsmith)


Lesenswert?

danke für eure Inputs, dass mit dem push_back hat jetzt funktioniert.
Ich dachte eigentlich, da ich die einzelnen String Elemente mit 
string[index] ausgeben kann, dann könnte ich ja auch die Daten genau so 
rein schreiben.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Michael S. schrieb:
> danke für eure Inputs, dass mit dem push_back hat jetzt funktioniert.
> Ich dachte eigentlich, da ich die einzelnen String Elemente mit
> string[index] ausgeben kann, dann könnte ich ja auch die Daten genau so
> rein schreiben.

Du kannst mit dem Index-Operator auf vorhandene Elemente der 
Zeichenkette zugreifen. Wenn die Zeichenkette leer ist, dann geht das 
dem entsprechend nicht: 
https://en.cppreference.com/w/cpp/string/basic_string

von Michael S. (michaelsmith)


Lesenswert?

danke,

ps. ja der Vector mach eigentlich auch keinen Sinn zu verwenden, kann 
man direkt das Array gegen '32' prüfen

:-C

von Michael K. (brutzel)


Lesenswert?

Hallo Michael,

eigentlich wollte ich nach dem Fehler suchen, aber da ist ja einiges 
recht merkwürdig. Irgendwie ein bischen C, ein bischen C++ und viele 
Ungereimtheiten bzw. Dinge, deren Sinn ich nicht ganz verstehe. Unten 
ein Vorschlag (einfaches C++17 ohne Schnickschnack und Fehlerprüfung). 
Die Ausgabe selbst habe ich mal aus der Funktion rausgenommen.
1
#include <iostream>
2
#include <sstream>
3
#include <string>
4
#include <vector>
5
6
std::pair<int, int> calculateSums(const std::string& input_string)
7
{
8
  std::stringstream ss(input_string);
9
  
10
  std::vector<int> numbers (
11
    std::istream_iterator<int>{ ss },
12
    std::istream_iterator<int>{}
13
  );
14
15
  int evenSum = 0;
16
  int oddSum = 0;
17
18
  for(int number : numbers)
19
  {
20
    if(number % 2 == 0)
21
      evenSum += number;
22
    else
23
      oddSum += number;
24
  }
25
26
  return { evenSum, oddSum };  
27
}
28
29
int main()
30
{
31
  auto [even, odd] = calculateSums("2 4 3 88 7 4 65 06");
32
  
33
  std::cout<<"even sum : " << even << '\n';
34
  std::cout<<"odd sum : " << odd << '\n';
35
}

: Bearbeitet durch User
von Michael S. (michaelsmith)


Lesenswert?

Hallo Michael,

was ich nicht ganz verstehe sind die Zeilen hier,
1
  std::vector<int> numbers (
2
3
    std::istream_iterator<int>{ ss },
4
5
    std::istream_iterator<int>{}
6
7
  );

was passiert hier, werden die Zahlen direkt aus dem String im Vector als 
int abgelegt ?

VG

von Εrnst B. (ernst)


Lesenswert?

Michael S. schrieb:
> was passiert hier, werden die Zahlen direkt aus dem String im Vector als
> int abgelegt ?

der Vector hat einen Konstruktor mit zwei Iteratoren, d.h. der Vektor 
wird mit den von den Iteratoren gelieferten Werten aufgebaut.
der begin-Iterator ist ein istream-iterator, der integer-Werte aus dem 
input-stream liest.
der end-Iterator ist der generische "eof"-Iterator dazu.

d.H. der vector wird mit allen aus dem sstream lesbaren integern 
befüllt.

Wenn man das noch optimieren mag, das Zwischenspeichern im vektor ist 
eigentlich unnötig, die odd/even-Schleife könnte auch direkt über den 
istream_iterator<int> laufen.

1
  for(auto it=std::istream_iterator<int>{ ss }; it!= std::istream_iterator<int>{}; ++it)
2
  {
3
    if(*it % 2 == 0)
4
      evenSum += *it;
5
    else
6
      oddSum += *it;
7
  }

: Bearbeitet durch User
von Michael K. (brutzel)


Lesenswert?

Michael S. schrieb:
> was passiert hier, werden die Zahlen direkt aus dem String im Vector als
> int abgelegt ?

Ja. Es gibt aber noch unzählige andere Methoden, einen solchen String zu 
splitten/parsen und die Werte in einem Container (wie hier std::vector) 
abzulegen, von C-Style bis zu STL-Kunststücken und Bibliotheken wie 
Boost. Die Vorgehensweise mit einem String-Stream ist eben einfach - und 
man benötigt keine expliziten Schleifen. Dabei werden eigentlich zwei 
Dinge genutzt: Erstens, dass man mit std::stringstream mit einem String 
wie mit einem Stream arbeiten kann, zweitens, dass einer der 
Konstruktoren von std::vector ein Start- und End-Iterator-Paar 
entgegennimmt (unten "first" und "last", der Allocator ist optional, den 
kannst du ignorieren).
1
template<class InputIt>
2
vector(InputIt first, InputIt last, const Allocator& alloc = Allocator());

Wenn man das von Hand aufdröselt, ohne den speziellen Konstruktor von 
std::vector zu benutzen, sieht es in etwa so aus:
1
std::vector<int> numbers;
2
3
std::istream_iterator<int> start_it(ss);
4
std::istream_iterator<int> end_it;
5
6
for(auto it = start_it; it != end_it; ++it)
7
{
8
  numbers.emplace_back(*it);
9
}

Den Vektor brauchen wir eigentlich nicht ...
1
for(auto it = start_it; it != end_it; ++it)
2
{
3
  if(*it % 2 == 0)
4
    evenSum += *it;
5
  else
6
    oddSum += *it;
7
}
Wenn Du
1
  std::istream_iterator<int> start_it(ss);
durch
1
  std::istream_iterator<int> start_it(std::cin);
ersetzt, wird statt des String-Streams der Standard-Inputstream 
verwendet; du kannst dann in der Konsole die Werte eingeben (Beenden der 
Eingabe mit Ctrl-Z + Enter bzw. Ctrl-D + Enter - oder einfach 
irgendeinen Buchstaben eingeben + Enter).

Noch eine Möglichkeit, die Werte in einen std::vector zu bekommen, wäre
1
  std::copy(std::istream_iterator<int>{ss}, {}, std::back_inserter(numbers)); // zu {} siehe unten

BTW:
Du solltest noch
1
#include <iterator>
oben einfügen.

Auch kann man in meinem Beispiel ein wenig abkürzen:
1
std::vector<int> numbers(std::istream_iterator<int>{ss}, {});
Der Compiler kommt hier von selbst darauf, dass {} der passende 
End-Iterator sein soll (etwas vereinfacht ausgedrückt).

https://de.wikibooks.org/wiki/C%2B%2B-Programmierung/_Die_STL/_Iteratoren

https://www.kompf.de/cplus/artikel/stream4.html

https://cplusplus.com/reference/sstream/stringstream/

von Michael K. (brutzel)


Lesenswert?

Ich habe nicht gesehen, dass Εrnst B. schon geantwortet hatte (man 
sollte vielleicht nicht auf den Antwort-Button klicken und dann erst 
frühstücken :)).

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.