# EAN Prüfziffernberechnung in C++



## bll007 (17. Januar 2006)

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.


----------



## Matthias Reitinger (17. Januar 2006)

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.


----------



## WACSF (19. Januar 2006)

Viel Spass

```
#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;
}
```


----------



## bll007 (27. Januar 2006)

WACSF hat gesagt.:
			
		

> Viel Spass
> 
> ```
> #include <iostream>
> ...


 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


----------



## deepthroat (27. Januar 2006)

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ß


----------



## WACSF (2. Februar 2006)

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


----------



## deepthroat (2. Februar 2006)

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:

```
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:
	
	
	



```
int digit;
if (isdigit(ean[i]) digit = ean[i] - '0';
else exit(1);
```
Gruß


----------



## WACSF (6. Februar 2006)

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.


----------



## WACSF (10. Februar 2006)

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.


----------



## FireFlow (10. Februar 2006)

@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.


----------



## WACSF (10. Februar 2006)

Beim Programmstart werden zwei Arten erstellt, Heap (den man auch als Freispeicher bezeichnen kann) und den Stack.
"Lokale" Variablen, das sind Variablen, die innerhalb eines Blocks deklariert sind, werden "auf" dem Stack gespeichert. Sie werden dort automatisch angelegt, wenn mit der Ausführung des Blocks begonnen wird und existieren nur bis zum Verlassen des Blocks. 
ich muss zugeben ichhabe oben mal die Bezeichnungen vertauscht, und die adresse zu überschreiben kann man ziemlich einfach erreichen, ich kann hier gerne mal sowas zeigen, nur würde ich wahrscheinlich irgendjemanden damit "gefährden".


----------



## FireFlow (10. Februar 2006)

Ist jetzt zwar extremes Offtopic, aber ein Exploit für ein einfaches Programm wie folgendes zu schreiben kann schon relativ kompliziert werden (naja wenn man es einmal verstanden hat...), aber normalerweise hat man eben keinen Quellcode 

```
void foo() {
    char buffer[3];
    cin >> buffer;
}
int main(int argc, int *argv[]) {
    foo();
}
```

@topic: c++-Style is etwa so:


```
bool validateEan(std::string const& ean)
{
    unsigned checksum = 0;
    int multiply = 1;
    for(std::string::size_type p = ean.size() - 1; p != std::string::npos; --p) {
        checksum += multiply * (ean[p] - '0');
        if(multiply == 3)
            multiply = 1;
        else
            multiply = 3;
    }

    if((checksum % 10) == 0)
        return true;
    return false;
}
```


----------



## wieschoo (11. Februar 2006)

> schließlich muss man auch noch irgendwo im Programm seinen eigenen Code platzieren



Nicht direkt im Prog mit neueren Techniken geht das auch außerhalb.


----------

