EAN Prüfziffernberechnung in C++

bll007

Grünschnabel
Hallo,

ich würde gerne ein Programm zur EAN-Prüfziffernberechnung schreiben.
Ich habe mir gedacht das ich die Nummer eingebe und diese dann in ein array lege damit ich jede ziffer einzeln habe um schließlich die Prüfsumme zu berechnen. Sollte ich die Nummer in einen String oder in eine int-Variable legen?

Leider bin ich in C++ nicht so drinn, daher weiss ich auch nicht wie ich das mache oder ob der Weg überhaupt gut ist.

Vielleicht kann mir bei diesem Problem ja jemand helfen. Vielen Dank schonmal im voraus.
 
Ich würde die EAN-Nummer zunächst als String einlesen und dann in ein Array aus Ganzzahlen (z.B. char) überführen. Somit kann ich bequem auf jede einzelne Ziffer zugreifen und die Prüfziffer schrittweise berechnen.
 
Viel Spass
Code:
#include <iostream>
using namespace std;

int main()
{
	int gerade = 0;		// Speichert die Summe aller Zahlen mit geradem Index
	int ungerade = 0;	// Speichert die Summe aller Zahlen mit ungeradem Index
	char ean[14];		// 14 Stellen benötigt wegen der binären NULL
	cout << "Berechnung der Pruefsumme der Europaeischen Artikel Nummer.\n";
	cout << "Bitte geben Sie die (E)uropaeischen (A)rikel (N)ummer ein:";
	cin >> ean;
	//-------------------------------------------------
	// Auslesen der geraden, als auch ungeraden Indices
	// und aufsummieren der Ergebnisse.
			for(int i = 1; i <  13; i++)
			{
				if (i%2 == 0)
				{
					char temp =  ean[i-1];
					gerade += atoi(&temp);
				}
				else
				{
					char temp =  ean[i-1];
					ungerade += atoi(&temp);
				}
			}
	//-------------------------------------------------

	//-------------------------------------------------
	// Die Formel für den EAN Code lautet:
	//    7   7   2   8   3   5   5   9   7   0   3   4   4 
	//   c1  c2  c3  c4  c5  c6  c7  c8  c9 c10 c11 c12   k
	// k = Prüfsumme
	// Formel:
	//( -(c1 + c3 + c5 + c7 + c9 + c11) - 3 * (c2 + c4 + c6 + c8 + c10 + c12) ) mod 10 = k
	// Man erkennt, dass der Code zwar Einzelfehler, jedoch
	// eine Nachbartransponität nicht erkennt.
	// 1  2  3  4  5  6  7  8  9  10 11 12 k 
	// 0  0  0  0  5  0  0  0  0  0  0  0  5 ist voll kommen korrekt da (-5) - 3*(0) mod 10 = 5 = k
	// 0  0  0  5  0  0  0  0  0  0  0  0  5 ist ebenfalls korrekt da   ( 0) - 3*(5) mod 10 = 5 = k
int ergebnis = (- ungerade - 3 * gerade) % 10;
	// Wenn man -5 mod 8 rechnen will dann kommt nicht etwa -3 raus sondern 3
	// -4  -3  -2  -1  0   1   2   3   4   5   6   7   8   9   10   11   12
	//                               MOD 8 =
	//  4   5   6   7  0   1   2   3   4   5   6   7   0   1    2    3    4
	// Deswegen muss man das Ergebnis falls es negativ ist einfach + 8 nehmen
char k = ean[12];
				if (ergebnis < 0)
				{
					ergebnis += 10;
				}

if (ergebnis == atoi(&k))// Das Ergebnis muss mit der Prüfsumme übereinstimmen
	{
	cout << "\nDer EAN Code ist korrekt.\n\a";

	}
else
	{
	cout << "\nDer EAN Code ist nicht korrekt.\n";
	cout << "Die \"richtige\" Pruefsumme muesste " << ergebnis << " lauten.\n\a";
	}

return 0;
}
 
WACSF hat gesagt.:
Viel Spass
Code:
#include <iostream>
using namespace std;

int main()
{
	int gerade = 0;		// Speichert die Summe aller Zahlen mit geradem Index
	int ungerade = 0;	// Speichert die Summe aller Zahlen mit ungeradem Index
	char ean[14];		// 14 Stellen benötigt wegen der binären NULL
	cout << "Berechnung der Pruefsumme der Europaeischen Artikel Nummer.\n";
	cout << "Bitte geben Sie die (E)uropaeischen (A)rikel (N)ummer ein:";
	cin >> ean;
	//-------------------------------------------------
	// Auslesen der geraden, als auch ungeraden Indices
	// und aufsummieren der Ergebnisse.
			for(int i = 1; i <  13; i++)
			{
				if (i%2 == 0)
				{
					char temp =  ean[i-1];
					gerade += atoi(&temp);
				}
				else
				{
					char temp =  ean[i-1];
					ungerade += atoi(&temp);
				}
			}
	//-------------------------------------------------

	//-------------------------------------------------
	// Die Formel für den EAN Code lautet:
	//    7   7   2   8   3   5   5   9   7   0   3   4   4 
	//   c1  c2  c3  c4  c5  c6  c7  c8  c9 c10 c11 c12   k
	// k = Prüfsumme
	// Formel:
	//( -(c1 + c3 + c5 + c7 + c9 + c11) - 3 * (c2 + c4 + c6 + c8 + c10 + c12) ) mod 10 = k
	// Man erkennt, dass der Code zwar Einzelfehler, jedoch
	// eine Nachbartransponität nicht erkennt.
	// 1  2  3  4  5  6  7  8  9  10 11 12 k 
	// 0  0  0  0  5  0  0  0  0  0  0  0  5 ist voll kommen korrekt da (-5) - 3*(0) mod 10 = 5 = k
	// 0  0  0  5  0  0  0  0  0  0  0  0  5 ist ebenfalls korrekt da   ( 0) - 3*(5) mod 10 = 5 = k
int ergebnis = (- ungerade - 3 * gerade) % 10;
	// Wenn man -5 mod 8 rechnen will dann kommt nicht etwa -3 raus sondern 3
	// -4  -3  -2  -1  0   1   2   3   4   5   6   7   8   9   10   11   12
	//                               MOD 8 =
	//  4   5   6   7  0   1   2   3   4   5   6   7   0   1    2    3    4
	// Deswegen muss man das Ergebnis falls es negativ ist einfach + 8 nehmen
char k = ean[12];
				if (ergebnis < 0)
				{
					ergebnis += 10;
				}

if (ergebnis == atoi(&k))// Das Ergebnis muss mit der Prüfsumme übereinstimmen
	{
	cout << "\nDer EAN Code ist korrekt.\n\a";

	}
else
	{
	cout << "\nDer EAN Code ist nicht korrekt.\n";
	cout << "Die \"richtige\" Pruefsumme muesste " << ergebnis << " lauten.\n\a";
	}

return 0;
}
Hallo,

danke für diesen super Quellcode. Leider verstehe ich einige Sachen leider nicht.
Was macht denn char temp und wieso hast du das oben nicht deklariert?
Was passiert bei char k?
Und was macht das Programm wenn es die Prüfsumme berechnet?

Wäre echt super wenn mir das jemand erklären könnte.
Vielen Dank
 
Hi.

In C++ muß man Variablen nicht unbedingt am Anfang eines Anweisungsblocks deklarieren, sondern kann sie dann deklarieren wenn man sie braucht - was auch durchaus Sinn macht und sogar unter manchen Umständen (z.B. innerhalb im Gegensatz zu außerhalb von Schleifen) Geschwindigkeitsvorteile bringt.
bll007 hat gesagt.:
Was macht denn char temp und wieso hast du das oben nicht deklariert?
Das ist ja gerade die Deklaration (und Definition und Initialisierung) der Variablen temp.

bll007 hat gesagt.:
Was passiert bei char k?
Es wird eine Variable vom Typ char definiert und diese wird mit dem Wert von ean[12] initialisiert.
bll007 hat gesagt.:
Und was macht das Programm wenn es die Prüfsumme berechnet?
Das sollte eigentlich aus den Kommentaren ersichtlich sein - obwohl manches nicht wirklich gut / sicher ist (z.B. die Verwendung von atoi mit der Adresse eines Zeichens als Parameter ohne Stringterminierung! Das ist eigentlich mehr Zufall das da was Vernünftiges rauskommt...)

Gruß
 
char temp ist nur eben um innerhalb der Klammern temporär etwas zwischenzuspeichern.
char k ist die Kontrollsumme, die an letzter stelle steht.

Mein Code ist sicherlich nicht schön, war aber wollte auch nicht ein poliertes Prog reinstellen, sondern nur mal so meine Gedanken dazu. Ich könnt es ja verändern, sodass es schöner wird ;). Bitte um Euer Verständniss.

Bye,

WACSF
 
Hi.
WACSF hat gesagt.:
Mein Code ist sicherlich nicht schön, war aber auch nicht lange durchdacht.
Nicht schön ist eine Sache, falsch und gefährlich eine andere. Die Funktion atoi erwartet einen Pointer auf den Anfang eines nullterminierten char Arrays, d.h. für eine Ziffer muß man mind. ein Array der Länge 2 benutzen:
Code:
char k[2]; k[0] = ean[i]; k[1] = '\0';
Du hattest vermutlich nur Glück das auf dem Stack nach k keine gültigen Ziffern waren und somit atoi nach dem Scannen des ersten Buchstabens gestoppt hat.

Ansonsten hätte man auch einfach den Wert der Ziffer berechnen können:
Code:
int digit;
if (isdigit(ean[i]) digit = ean[i] - '0';
else exit(1);
Gruß
 
Da das Programm ja des Stack und Heap - Speicherplatz allokiert und ihn von oben nach unten (Vektor ähnlich) liest, kann es schon vorkommen, dass es zu einem Buffer Overrun Hack kommt. [Edit] Ein relativ einfache Art [/Edit] Dies ist die billigste Art und Weise einen Hack zu machen. Dies kann auch bei atoi passieren, da sie ein array liest und temporär die Werte temporär auf dem Stack speichert. Wenn nun die atoi Funktio nicht terminiert (über das array hinausläuft), dann kann es zu diesem Hack kommen. Microsoft Visual Studio .NET 2005 überprüft mit einer 98 % Sicherheit, ob solche Buffer Overrun Hack in einem Code vorkommen. Deswegen ist diese atoi in o.g. zusammenhang mit Vorsicht zu genießen, aber es ist auch nicht das übelste auf dieser Welt. Einfach terminiereung oder elementartiges kopieren eines Arrays statt dessen verwenden, fertig.

Viele Wege führen ans ziel.

Bye.
 
Zuletzt bearbeitet:
Heap ist übrigens der Speicher bezeichnet, auf dem fest gespeichert wird.
Stack wird beim Programmstart allokiert.
Mit (C) Malloc und Free, bzw. (C++) New und Delete, wird auf den Heap neuer Speiche allokiert.

Bye.
 
Zuletzt bearbeitet:
@WACSF: Was redest du da für einen Unsinn?

Der Heap ist eine Implementierung für die Verwaltung von Free Store. Auf dem Free Store kann man mit new/malloc Speicher reservieren. Der Free Store ist theoretisch unberenzt (praktisch logischerweise nicht). Dem Stack wird normalerweise eine feste größe zugewiesen und (wie es der Name schon sagt) als Stapel organisiert -> First in, Last out. Das gilt nicht nur für heute Implementierungen wie Windows etc sondern afaik auch für die meisten Embedded Systeme (bei mir isses so).

Funktionen wie itoa, atoi, etc... verwendet man in C++ normalerweise nicht mehr sondern die Streams.

@Buffer-Overrun: Das ist nicht gerade die "billigste" Art einen Hack zu machen und ich sehe keinen Zusammenhang mit dem Thema. Bei einem Buffer-Overrun wird normalerweise durch eine (absichtlich) gefälschte Benutzereingabe der Stack so weit überschrieben dass man die Rücksprungadresse der Funktion überschreibt. Das ganze ist aber nicht so einfach wie sich das anhört, schließlich muss man auch noch irgendwo im Programm seinen eigenen Code platzieren und da dann hin springen.

Ich würde mich generell nie auf irgendwelche Range-Checks des Compilers verlassen.
 
Zurück