Seite 1 von 2

Problem mit Zugriff auf struct mittels Pointer

Verfasst: So Jan 07, 2018 10:42 pm
von raysman
Ich würde gerne folgende Lösung auf einem anderen Weg programmieren.
Leider verstehe ich nicht, wie ich auf das struct zugreifen kann, damit Buchstabe a auch den Code ausgibt.

else { cout << morse_data[*(ptr + i)].morse_code << "#"; }

funktioniert leider nicht. Ich habe jedoch keine Idee warum. Wenn ich das i aus der Schleife einsetze werden alle Codes strikt der Reihenfolge nach ausgegeben.

Großbuchstaben habe ich bisher bewusst noch nicht berücksichtigt.

Lösung:

Code: Alles auswählen

#include <iostream>
#include <string>
using namespace std;

struct T_Morse_Data
{
	char letter;
	std::string morse_code;
};
const T_Morse_Data morse_data[] = {
{ 'a', ".-" },
{ 'b', "-..." },
{ 'c', "-.-." },
{ 'd', "-.." },
{ 'e', "." },
{ 'f', "..-." },
{ 'g', "--." },
{ 'h', "...." },
{ 'i', ".." },
{ 'j', ".---" },
{ 'k', "-.-" },
{ 'l', ".-.." },
{ 'm', "--" },
{ 'n', "-." },
{ 'o', "---" },
{ 'p', ".--." },
{ 'q', "--.-" },
{ 'r', ".-." },
{ 's', "..." },
{ 't', "-" },
{ 'u', "..-" },
{ 'v', "...-" },
{ 'w', ".--" },
{ 'x', "-..-" },
{ 'y', "-.--" },
{ 'z', "--.." },
{ '0', "-----" },
{ '1', ".----" },
{ '2', "..---" },
{ '3', "...--" },
{ '4', "....-" },
{ '5', "....." },
{ '6', "-...." },
{ '7', "--..." },
{ '8', "---.." },
{ '9', "----." },
// Leerzeichen zur Worttrennung werden im Morsecode
// durch einen Slash '/' umgeben von Leerzeichen
// dargestellt ...
// (Alternative: Trennung durch 3 Leerzeichen)
// Hier bei uns, um die Testläufe eindeutiger zu
// machen: Trennung mittels drei Slashes
{ ' ', "///" },
{ '.', ".-.-.-" },
{ ',', "--..--" },
{ ':', "---..." },
{ '?', "..--.." },
{ '-', "-....-" },
{ '/', "-..-." },
{ '@', ".--.-." },
{ '=', "-...-" }
};
const int morse_data_len = 47;

int main() {
	string eingabe = "";
	string ausgabe = "";
	string code = "";
	cout << "Bitte Text eingeben (ggfs. mit Leerzeichen): ? ";
	getline(cin, eingabe);

	for (int i = 0; i < eingabe.size(); i++) {
		if (eingabe.at(i) >= 'A' && eingabe.at(i) <= 'Z') {
			eingabe.at(i) += 32;
		}
		for (int j = 0; j < morse_data_len; j++) {
			if (eingabe.at(i) == morse_data[j].letter) {
				code = morse_data[j].morse_code;
				break;
			}
			else {
				continue;
			}
		}
		ausgabe += code;
		cout << ausgabe << "#";
		ausgabe = "";
	}
	cout << endl;
	system("PAUSE");
	return 0;
}
Meine Variante

Code: Alles auswählen

int main() {
	char *ptr = new char[morse_data_len];
	cin.getline(ptr, morse_data_len);

	char p = 0;
	for (int i = 0; i < morse_data_len; i++)
	{
		if (*(ptr + i) == '\0') { break; }
		else { cout << morse_data[*(ptr + i)].morse_code << "#"; }
	}

	system("PAUSE");
	return 0;
}

Re: Problem mit Zugriff auf struct mittels Pointer

Verfasst: So Jan 07, 2018 11:06 pm
von Xin
Moin und willkommen :-)
raysman hat geschrieben:Ich würde gerne folgende Lösung auf einem anderen Weg programmieren.
Leider verstehe ich nicht, wie ich auf das struct zugreifen kann, damit Buchstabe a auch den Code ausgibt.

else { cout << morse_data[*(ptr + i)].morse_code << "#"; }

funktioniert leider nicht. Ich habe jedoch keine Idee warum. Wenn ich das i aus der Schleife einsetze werden alle Codes strikt der Reihenfolge nach ausgegeben.
In die eckigen Klammern kommt bei einem Array ein Index. Deine Lösung packt aber den Buchstaben als Schlüssel rein.
In der Lösung liegt das 'a' auf Index 0. 'a' ist aber auch eine gültige Zahl, nämlich eben der ASCII-Code für 'a'. Der ist 97.
Du musst also erst rausfinden, auf welchem Index das Morsezeichen für den ASCII-Code 97 - dem 'a' liegt.

Alternativ könntest Du eine Hashmap nehmen (std::map), wo du einen Schlüssel (das ASCII-Zeichen) auf den String (das Morse-Zeichen) abbildest.
raysman hat geschrieben:Großbuchstaben habe ich bisher bewusst noch nicht berücksichtigt.
Morst man bei Großbuchstaben lauter? ;)

Re: Problem mit Zugriff auf struct mittels Pointer

Verfasst: So Jan 07, 2018 11:26 pm
von raysman
Klingt so, als wäre ein Tausch von 'a' zu .- nur über den Index möglich? Wenn ich ich jetzt -97 ergänze funktioniert es :)
Jetzt hab ich gesehen, dass in der Lösung einfach das Array mit einer Schleife durchlaufen wird ..

Re: Problem mit Zugriff auf struct mittels Pointer

Verfasst: Mo Jan 08, 2018 12:32 am
von Xin
raysman hat geschrieben:Klingt so, als wäre ein Tausch von 'a' zu .- nur über den Index möglich? Wenn ich ich jetzt -97 ergänze funktioniert es :)
Für Buchstaben... nicht für Satzzeichen, da musst Du weitere Bedingungen einbauen. Allerdings kannst Du so auch einfach Großbuchstaben einbauen, wenn Du von 'A' 65 abziehst. Das geht auch mit (*(ptr+i))-'A' - unter der Vorraussetzung, dass ptr+i auf einen Großbuchstaben zeigt...
raysman hat geschrieben:Jetzt hab ich gesehen, dass in der Lösung einfach das Array mit einer Schleife durchlaufen wird ..
Wenn Du Dich nur mit dem berechneten Index durcharbeitest, brauchst Du auch den Schlüssel ('letter') nicht.

Re: Problem mit Zugriff auf struct mittels Pointer

Verfasst: Mo Jan 08, 2018 8:26 am
von mfro
was soll die Schreibweise

Code: Alles auswählen

*(ptr + i)
???

Gewöhn' dir das nicht an. Wenn man Arrays meint, sollte man n.m.M. auch Arrays hinschreiben, dafür wurden sie erfunden:

Code: Alles auswählen

ptr[i]
Wenn Du sicherstellen kannst, dass dein Übersetzungsarray immer so aufgebaut ist (und bleibt), dass es bei 'a' beginnt und (ohne Lücke) bis 'z' geht, kannst Du 1. das 'letter' member in der struct weglassen (weil das ja implizit schon dem Array-Index - 'a' entspricht) und 2. schreiben:

Code: Alles auswählen

cout << morse_data[i - 'a'].morse_code << ...
Wenn das Übersetzungsarray Lücken aufweisen (oder unsortiert sein) darf, brauchst Du Code, der dir zu einem gegebenen Zeichen den richtigen Array-Index raussucht. Also (im einfachsten Fall) so was:

Code: Alles auswählen

for (int index = 0; index < sizeof(morse_data) / sizeof(morse_data[0]); index++)
{
     if (morse_data[i].letter == eingabe[i])
     {
         morse_code = morse_data[i].morse_code;
         break;
     }
}
(hier musst Du noch den Fall abfangen, dass das Zeichen nicht gefunden wurde)

Re: Problem mit Zugriff auf struct mittels Pointer

Verfasst: Di Jan 09, 2018 1:02 am
von Xin
Ich habe mir mal spaßeshalber die Musterlösung angeguckt und möchte eine Alternative zeigen. Die Musterlösung ist eher altmodisch und entspricht nicht modernem C++. Die folgende Lösung ist erstens leichter zu lesen, leichter zu warten und sollte deutlich schneller in der Ausführung sein.

Code: Alles auswählen

#include <iostream>
#include <string>
#include <map>

using namespace std;

std::map< char, std::string > dict = {
{ 'a', ".-" },
{ 'b', "-..." },
{ 'c', "-.-." },
{ 'd', "-.." },
{ 'e', "." },
{ 'f', "..-." },
{ 'g', "--." },
{ 'h', "...." },
{ 'i', ".." },
{ 'j', ".---" },
{ 'k', "-.-" },
{ 'l', ".-.." },
{ 'm', "--" },
{ 'n', "-." },
{ 'o', "---" },
{ 'p', ".--." },
{ 'q', "--.-" },
{ 'r', ".-." },
{ 's', "..." },
{ 't', "-" },
{ 'u', "..-" },
{ 'v', "...-" },
{ 'w', ".--" },
{ 'x', "-..-" },
{ 'y', "-.--" },
{ 'z', "--.." },
{ '0', "-----" },
{ '1', ".----" },
{ '2', "..---" },
{ '3', "...--" },
{ '4', "....-" },
{ '5', "....." },
{ '6', "-...." },
{ '7', "--..." },
{ '8', "---.." },
{ '9', "----." },
// Leerzeichen zur Worttrennung werden im Morsecode
// durch einen Slash '/' umgeben von Leerzeichen
// dargestellt ...
// (Alternative: Trennung durch 3 Leerzeichen)
// Hier bei uns, um die Testläufe eindeutiger zu
// machen: Trennung mittels drei Slashes
{ ' ', "///" },
{ '.', ".-.-.-" },
{ ',', "--..--" },
{ ':', "---..." },
{ '?', "..--.." },
{ '-', "-....-" },
{ '/', "-..-." },
{ '@', ".--.-." },
{ '=', "-...-" }
};

int main() {
   string eingabe = "";
   cout << "Bitte Text eingeben (ggfs. mit Leerzeichen): ? ";
   getline(cin, eingabe);

   for( char c : eingabe )
   {
     auto it = dict.find( tolower( c ) );
     if( it != dict.end() )
       cout << it->second + "#";
   }
   cout << endl;

   return 0;
}

Re: Problem mit Zugriff auf struct mittels Pointer

Verfasst: Di Jan 09, 2018 9:07 am
von mfro
Das dürfte hier keine Rolle spielen, aber wenn man keinen sorted Iterator braucht, ist std::unordered_map fast immer die bessere Wahl gegenüber std::map (schneller).

Re: Problem mit Zugriff auf struct mittels Pointer

Verfasst: Di Jan 09, 2018 10:19 am
von Xin
mfro hat geschrieben:Das dürfte hier keine Rolle spielen, aber wenn man keinen sorted Iterator braucht, ist std::unordered_map fast immer die bessere Wahl gegenüber std::map (schneller).
Klugscheißer... ;)

Ich fand's so schön, das Programm auf wenige Zeilen zusammen zu streichen und dann sowas als Feedback. :D

Ansonsten müsste man das wirklich mal ausprobieren, denn eine sortiere Map könnte theoretisch ja über eine binäre Suche schneller fündig werden als eine unsortierte Map. Wäre also eine Frage der Implementierung!?

Re: Problem mit Zugriff auf struct mittels Pointer

Verfasst: Di Jan 09, 2018 1:10 pm
von mfro
Xin hat geschrieben: Klugscheißer... ;)
aber immer wieder gern ;)
Xin hat geschrieben: Ich fand's so schön, das Programm auf wenige Zeilen zusammen zu streichen und dann sowas als Feedback. :D
... wenn wir schon beim Klugscheissen sind ( ;) ), Stichwort Zeilen sparen. Da geht noch was, die maps haben einen hübschen Array-Operator:

Code: Alles auswählen

for (char c : eingabe)
    cout << dict[tolower(c)] + "x";
Das hat allerdings den möglicherweise unerwünschten Seiteneffekt, dass für nicht erkannte Zeichen neue "leere" Map-Einträge erzeugt werden (was dann allerdings auch bedeutet, dass die gehasht werden und das Programm mit mehr solcher Einträge immer schneller werden müsste).
Xin hat geschrieben: Ansonsten müsste man das wirklich mal ausprobieren, denn eine sortiere Map könnte theoretisch ja über eine binäre Suche schneller fündig werden als eine unsortierte Map. Wäre also eine Frage der Implementierung!?
Das will ich nicht ausschließen, glaube aber nicht daran. Schließlich reden wir ja von Hash-Tabellen. std::map (und std::unordered_map) verwendet std::hash<char> und das bildet (solange Du nicht bei der Template-Instanzierung was eigenes übergibst) das eben *nicht* 1:1 aufeinander ab. Das wird also wahrscheinlich nix mit der binären Suche.

Re: Problem mit Zugriff auf struct mittels Pointer

Verfasst: Di Jan 09, 2018 3:00 pm
von Xin
mfro hat geschrieben:
Xin hat geschrieben: Klugscheißer... ;)
aber immer wieder gern ;)
Ich bitte doch darum :)
mfro hat geschrieben:
Xin hat geschrieben: Ich fand's so schön, das Programm auf wenige Zeilen zusammen zu streichen und dann sowas als Feedback. :D
... wenn wir schon beim Klugscheissen sind ( ;) ), Stichwort Zeilen sparen. Da geht noch was, die maps haben einen hübschen Array-Operator:

Code: Alles auswählen

for (char c : eingabe)
    cout << dict[tolower(c)] + "x";
Das hat allerdings den möglicherweise unerwünschten Seiteneffekt, dass für nicht erkannte Zeichen neue "leere" Map-Einträge erzeugt werden (was dann allerdings auch bedeutet, dass die gehasht werden und das Programm mit mehr solcher Einträge immer schneller werden müsste).
Dass es schneller wird, halte ich für eine interessante Theorie, ich würde jetzt eher vermuten, je voller die map, desto langsamer.
Bei eine Map, die von char ausgeht, könnte eine Spezialisierung natürlich einen referenzierten Zugriff über ein Array ausmachen, was natürlich nicht zu toppen wäre. Aber das würde auch mit leeren Elementen gehen und dann wäre es schneller, wenn dafür keine leeren Strings angelegt werden müssen. ^^
mfro hat geschrieben:
Xin hat geschrieben: Ansonsten müsste man das wirklich mal ausprobieren, denn eine sortiere Map könnte theoretisch ja über eine binäre Suche schneller fündig werden als eine unsortierte Map. Wäre also eine Frage der Implementierung!?
Das will ich nicht ausschließen, glaube aber nicht daran. Schließlich reden wir ja von Hash-Tabellen. std::map (und std::unordered_map) verwendet std::hash<char> und das bildet (solange Du nicht bei der Template-Instanzierung was eigenes übergibst) das eben *nicht* 1:1 aufeinander ab. Das wird also wahrscheinlich nix mit der binären Suche.
Einen Hash kann man doch binär suchen?
Ich habe mir noch keine Implementierung von map angeguckt. Die Idee ist bei mir da recht einfach: Es ist Standard und hat damit per Definition halbwegs passabel zu sein. Bei einer Hashmap, wo ich wissen will, was da intern funktioniert, nehme ich eine eigene Implementation.