Du bist nicht angemeldet.

Werbeanzeige

1

21.02.2020, 14:46

C++ Letztes Zeichen eines Strings bekommen

Hallo.
Ich habe mal wieder eine Aufgabe. Es soll ein Programm geschrieben werden das das Ende von String1 mit dem Ende von String2 vergleicht. Ist String1-Ende gleich String2-Ende soll true zurückgegeben werden ansonsten false. Vorweg: Mir ist bewusst das es eine ganz einfach Lösung zu dem Problem gibt und zwar folgendes:

Quellcode

1
2
if (str1[str1.length()-1] == str2[str2.length()-1])
  return true;

Ich will aber verstehen warum mein längerer und umständlicherer Weg nicht funktioniert

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <string>

using namespace std;

bool solution(std::string str1, std::string str2) {
    string::iterator it1;
    string::iterator it2;

    // Bei it1 und it2 müssten nach ende der schleifendurchläufe doch jeweils das letzte element stehen oder nicht?
    for (it1 = str1.begin(); it1 != str1.end(); it1++);
    for (it2 = str2.begin(); it2 != str2.end(); it2++);

    // Prüfen ob Ende von String1 gleich dem Ende von String 2 ist
    if(*it1 == *it2)
        return true; // wenn ja, true zurückgeben

  return false; // wenn nein, false zurückgeben
}

int main ()
{
    string str1 = "abc";
    string str2 = "xy";

    if(solution(str1, str2))
        cout << "True";
    else
        cout << "False";;

  return 0;
}

Warum gibt mein Programm immer "True" zurück?

Sylence

Community-Fossil

Beiträge: 1 678

Beruf: Softwareentwickler

  • Private Nachricht senden

2

21.02.2020, 15:29

Zitat

Returns an iterator pointing to the past-the-end character of the string.


Weil deine beiden iteratoren nach der Schleife auf etwas zeigen, was nicht Teil des Strings ist.
Software documentation is like sex. If it's good you want more, if it's bad it's better than nothing.

dot

Supermoderator

Beiträge: 9 854

Wohnort: Graz

  • Private Nachricht senden

3

21.02.2020, 16:14

[…] Mir ist bewusst das es eine ganz einfach Lösung zu dem Problem gibt und zwar folgendes: […]

Es geht sogar noch simpler:

C-/C++-Quelltext

1
    return str1.back() == str2.back();

;)

Beachte: So wie auch dein Code, geht obiger Code natürlich davon aus, dass beide Strings nicht leer sind. Die Funktionsparameter sollten wohl besser entweder vom Typ const std::string& oder, noch besser, std::string_view sein, um unnötiges Kopieren zu vermeiden…

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »dot« (21.02.2020, 16:20)


4

21.02.2020, 17:52

Danke für die Antworten. Habe mein Programm entsprechend geändert.

Quellcode

1
2
3
   // Prüfen ob Ende von String1 gleich dem Ende von String 2 ist
   if(*(it1 - 1) == *(it2 - 1))
        return true; // wenn ja, true zurückgeben

Jetzt funktioniert es. :)

Edit:
Muss bei dem was dot geschrieben hat nochmal einhaken. Es geht um den Fall wenn der String leer ist. Hier mal die Kurzversion meines Programms.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <string>

bool solution(std::string const &str, std::string const &ending) {
    
    if (ending.length() == 0)
     // was ist hier zu tun?

    if(str.back() == ending.back())
      return true;
      
    return false;
}

Was mach ich nun wenn String2 leer ist?

Habe hier noch einen (fremden) Codeausschnitt von dem ich weiß, dass er die richtige Lösung liefert.

Quellcode

1
2
3
4
5
#include <string>

bool solution(const std::string& str, const std::string& ending) {
  return str.size() >= ending.size() && str.compare(str.size() - ending.size(), std::string::npos, ending) == 0;
}

Und hier nochmal die (englische) Aufgabenstellung:
Complete the solution so that it returns true if the first argument(string) passed in ends with the 2nd argument (also a string).

Examples:

solution('abc', 'bc') // returns true
solution('abc', 'd') // returns false
solution("abc", "") // returns true

Was bei einem leeren String passieren soll wird mir dabei aber nicht ersichtlich. Allerdings verstehe ich beim nochmaligen lesen die Aufgabe so das ALLE zeichen des zweiten stringe mit den letzten zeichen des ersten strings verglichen werden sollen. Und wenn der zweite String leer ist müsste es auch true zurückgeben da ja beide mit der Escape-Sequenz enden. Nur wie setze ich das um?

Edit 2:

Habe jetzt endlich eine Lösung gefunden. Das Programm vergleicht jetzt ALLE Zeichen des letzten string mit den letzten Zeichen des ersten string. (also z.B str1"abcd", str2 "bcd" --> true oder str1"abcd", str2"dcd" --> false)
Bei diesem Programm habe ich einfach die enden der strings mit str.back() verglichen und dann die letzten Elemnte mit str.pop_back() gelöscht um dann wieder mit str.back() zu prüfen. Das ganze geht so lange bis alle zeichen weggelöscht wurden (return true) oder er auf einen falschen buchstaben trifft (return false). Bei einem leeren string habe ich einfach true zurückgegeben da ja beide strings mit der Escape-Sequenz enden.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
bool solution(std::string *str1, std::string *str2) {

    bool isItTrue = false;

    if (str2->length() == 0)
        return true;

    for (int i= str2->length(); i > 0; i--)
    {
        if (str1->back() == str2->back())
        {
            isItTrue = true;
            str1->pop_back();
            str2->pop_back();
        }

        else
        {
            isItTrue = false;
            break; // jumps out of the for-loop
        }

    }
    return isItTrue;
}

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »justmytwocents« (23.02.2020, 16:25)


Schorsch

Supermoderator

Beiträge: 5 193

Wohnort: Wickede

Beruf: Student

  • Private Nachricht senden

5

23.02.2020, 18:02

Dazu fallen mir ein paar Kleinigkeiten auf. Wenn dein erster String kürzer ist als der zweite, kommt es zu einem Fehler.
Deine isItTrue Variable kannst du raus werfen. Sobald die zu testenden Zeichen unterschiedlich sind kannst du false zurück liefern. Beendet deine Schleife weißt du dass die Zeichen alle gleich waren und du kannst true zurück geben.
Es ist nicht besonders gut dass du Zeiger auf Strings als Parameter erwartest. Diese könnten null sein, worauf du in deinem Fall nicht prüfst. Einfacher wäre es wenn du einfach mit Referenzen arbeiten würdest. Noch besser wäre es wenn du mit const Referenzen arbeiten und die beiden Strings nicht verändern würdest. Dann müsstest du allerdings deine pop_back Lösung verwerfen und anders vorgehen. Möchtest du bei dieser Lösung bleiben würde ich die Parameter per Value übergeben, dann werden sie kopiert und die originalen Strings werden nicht verändert.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

6

25.02.2020, 17:44

Okay. Habe meinen Code nochmal angepasst. Arbeitet jetzt mit Call by Value. Das ganze mit const Referenzen zu machen ist mir momentan zu hoch. Vielleicht komme ich später nochmal darauf zurück.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
bool solution(std::string str1, std::string str2) {
    if (str2.length() == 0)
        return true;

    for (int i = str2.length(); i > 0; i--)
    {
        if (str1.back() == str2.back())
        {
            str1.pop_back();
            str2.pop_back();
        }

        else
            return false;
    }
    return true;
}

David Scherfgen

Administrator

Beiträge: 10 236

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

7

25.02.2020, 22:27

Erklär doch mal, was dieser Code deiner Meinung nach tut. Das stimmt doch hinten und vorne nicht:
- Deine Funktion stürzt ab, wenn str1 leer ist.
- Deine Funktion stürzt potenziell ab, wenn str1 kürzer als str2 ist: Gib ihr mal "a" und "aa" als Eingabe.
- Deine Funktion gibt nie das korrekte Ergebnis aus.
- Warum zählst du rückwärts?
- Wenn du schon mit back() arbeitest (aber nicht so, wie du es jetzt tust!), dann ist die Schleife überflüssig. In deinem Fall sorgt sie sogar für falsche Ergebnisse.

Sorry, aber da ist eigentlich alles falsch. Es ergibt überhaupt keinen Sinn. :rolleyes:

Und warum machst du das überhaupt so kompliziert? Das hier tut's doch:

C-/C++-Quelltext

1
2
3
4
bool sameLastCharacter(const std::string& str1, const std::string& str2)
{
    return !str1.empty() && !str2.empty() && str1.back() == str2.back();
}

8

26.02.2020, 18:18

Hallo David.
Tur mir leid das ich alles so umständlich geschrieben habe. Am Anfang des Beitrags ging ich noch von einer völlig andern Aufgabenstellung aus. Zuerst dachte ich das man nur die letzten beiden Zeichen miteinander vergleichen muss. Bei nochmaligem Lesen der Aufgabe habe ich allerdings bemerkt, dass alle Zeichen des zweiten strings am ende des ersten strings vorkommen sollen. Auch ist durch die Aufgabenstellung gewährleiste das str1 nie leer und str2 immer kürzer als str1 ist. Es sind Aufgaben die sich eher an Anfänger wie mich richten. In späteren Aufgabe werden die von dir genannten Fehlerquellen wohl wichtiger werden.

David Scherfgen

Administrator

Beiträge: 10 236

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

9

27.02.2020, 00:14

Ach so, sorry, das hatte ich überlesen. Abstürze gibt's bei deiner Funktion trotzdem ;)

Werbeanzeige