# C++ Kreditkartennummer überprüfen



## freeak2305 (15. Dezember 2010)

Hallo,

ich soll eine Programm schreiben, in dem eine Kreditkartennummer überprüft werden soll. Dazu gibt es einen Algorithmus.

Problem: Ich habe überhaupt keinen Plan wie, wo und warum. Habe mir jetzt hier was zusammengebastelt,. aber das scheint nicht das Gelbe vom Ei zu sein. Bricht ab mit "Run-Time Check Failure #2 - Stack around the variable 'Feld' was corrupted." Und die Ausgaben am Ende stimmen auch nicht.....glaube ich.

Könnt Ihr bitte einmal drüberschauen?

```
// Kreditkarte.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung.
//

#include "stdafx.h"
#include <iostream>
#include <stdlib.h>

using namespace std;

int main()
{

	char Feld[16];
	int zahl = 15;
	
	cout << "Bitte Kreditkartennummer eingeben:" << endl;
	cout << endl;

	cin >> Feld;
	cout << endl;


	
	int zw1 = 0, zw2 = 0, zw3 = 0, zwges = 0;
	int pruefziffer, rest;
	

	for(int i = 0; i == zahl; i++)											
		{															
											
	
			if ((i == 0) || (i == 2) || (i == 4) || (i == 6) || (i == 8) || (i == 10) || (i == 12) || (i == 14))
				{
					zw3 = Feld[i] * 2;								
					
				}
			else
				{
					zw2 = zw2 + Feld[i];						
				}
		}

		zwges = zw1 + zw2;							

		rest = zwges % 10;
		pruefziffer = 10 - rest;

		
		
	if(Feld[15]=pruefziffer)
	{
			cout << "Dies ist eine moegliche Kreditkartennummer" << endl;
	}
	else
	{
					cout << "Dies ist keine moegliche Kreditkartennummer!" << endl;
	}
	
	cin.ignore();
	getchar();
	return 0;

}
```


----------



## MiMi (15. Dezember 2010)

Schreib doch bitte deinen Code in cpp-tags, danke 

Zudem ist 

```
Feld[15]=pruefziffer
```
eine Zuweisung und keine Pruefung wie du es in der if vor hast. Zahlen vergleichen mit ==


----------



## freeak2305 (15. Dezember 2010)

So, bin nun angemeldet. Sorry, das sich den Code nicht richtig formatiert habe


Ich hab das mal mit nem "==" gemacht, aber da ist immernoch dieser nervige "Stack Fehler".


----------



## MiMi (15. Dezember 2010)

Als Gast kannst du keine Beitraege bearbeiten? Hm, falls net, poste den code bittenochmal in tags, dann wirds einfacher zu lesen. Danke


----------



## freeak2305 (15. Dezember 2010)

```
//Kreditkarte.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung.
//

#include "stdafx.h"
#include <iostream>
#include <stdlib.h>

using namespace std;

int main()
{

	char Feld[16];
	int zahl = 15;
	
	cout << "Bitte Kreditkartennummer eingeben:" << endl;
	cout << endl;

	cin >> Feld;
	cout << endl;


	
	int zw1 = 0, zw2 = 0, zw3 = 0, zwges = 0;
	int pruefziffer, rest, einer, zehner;
	

	for(int i = 0; i == zahl; i++)											
		{															
											
	
			if ((i == 0) || (i == 2) || (i == 4) || (i == 6) || (i == 8) || (i == 10) || (i == 12) || (i == 14))
				{
					zw3 = Feld[i] * 2;				
				}
			else
				{
					zw2 = zw2 + Feld[i];						
				}
		}

		zwges = zw1 + zw2;							

		rest = zwges % 10;
		pruefziffer = 10 - rest;

		
		
	if(Feld[15]==pruefziffer)
	{
			cout << "Dies ist eine moegliche Kreditkartennummer" << endl;
	}
	else
	{
					cout << "Dies ist keine moegliche Kreditkartennummer!" << endl;
	}
	
	cin.ignore();
	getchar();
	return 0;

}
```


----------



## ComFreek (15. Dezember 2010)

@MiMi: Wie soll das denn funktionieren? Man hat ja keine Identifikationsmöglichkeiten.


----------



## vfl_freak (15. Dezember 2010)

Moin,

hat zwar nichts mit Deinem konkreten Problem zu tun, aber statt

```
for( int i = 0; i == zahl; i++ )
```
 
*besser *

```
for( int i = 0; i <= zahl; i++ )
```


So, und das Fehlermeldung von der Variablen "feld " spricht, vermute ich mal, dass hier irgendwo der Knackpunkt ist:

```
char Feld[16];
int zahl = 15;
...
cin >> Feld;
```

Mal davon angesehen, dass vlt. String etc. pfiffiger wäre, würde ich mal versuchen, NACH dem Einlesen die Variable mit 

```
feld[] 15 = 0;
```
zu terminieren !


gruß
Klaus


----------



## MiMi (15. Dezember 2010)

Evtl mit der IP ^^
Sind zwar immer noch keine cpp-tags, aber schonma besser als nix 

Ich bin net so fit in cpp aber gehts nicht schon schief weil char Feld[16]; nicht initialisiert ist?


----------



## ComFreek (15. Dezember 2010)

Die IP kann sich ja ändern.


----------



## deepthroat (15. Dezember 2010)

Hi.





MiMi hat gesagt.:


> Evtl mit der IP ^^
> Sind zwar immer noch keine cpp-tags, aber schonma besser als nix
> 
> Ich bin net so fit in cpp aber gehts nicht schon schief weil char Feld[16]; nicht initialisiert ist?


Nein, in C/C++ muß man Variablen nicht initialisieren.

Und schließlich wird dann auch in die Variable eingelesen (@vfl_freak: und auch automatisch terminiert).

Aber, der C-String feld kann max 15 Buchstaben speichern - da C-Strings mit \0 terminiert sind. Falls man 16 Zeichen eingibt, schreibt man über die Feldgrenze hinaus -> Stackkorruption.

```
char feld[17];
```
Es wäre allerdings durchaus besser std::strings zu verwenden.

Gruß


----------



## freeak2305 (15. Dezember 2010)

Okay, danke schonmal, dass die Stackkorruption weg ist.

Allerdings scheint immernoch ein Fehler im Programm zu sein, den ich nciht finde.

Ich habe zB eine Kreditkartennummer, die definitv gültig sein muss, weil sie aus der Aufgabenstellung kommt 
4509472140549006

Gebe ich diese ein kommt raus, dass es KEINE gütlige ist..... Ich bin verzweifelt.........

Hier der aktuelloe Code:

```
// Kreditkarte.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung.
//

#include "stdafx.h"
#include <iostream>
#include <stdlib.h>

using namespace std;

int main()
{

	char Feld[17];
	int zahl = 15;
	
	cout << "Bitte Kreditkartennummer eingeben:" << endl;
	cout << endl;
	cin >> Feld;
	cout << endl;


	int zw1 = 0, zw2 = 0, zw3 = 0, zwges = 0;
	int pruefziffer, rest, einer, zehner;
	

	for(int i = 0; i <= zahl; i++)											
		{															
			if ((i == 0) || (i == 2) || (i == 4) || (i == 6) || (i == 8) || (i == 10) || (i == 12) || (i == 14))
				{
					zw3 = Feld[i] * 2;
					if(zw3 >= 10)
						{
							zehner = zw3 / 10;
							einer = zw3 % 10;
							zw3 = zehner + einer;
							zw1 = zw1 + zw3;
						}
					else
						{
							zw1 = zw1 + zw3;
						}
				}
			else
				{
					zw2 = zw2 + Feld[i];						
				}
		}

	zwges = zw1 + zw2;							

	rest = zwges % 10;
	pruefziffer = 10 - rest;

		
	if(Feld[15]==pruefziffer)
	{
		cout << "Dies ist eine moegliche Kreditkartennummer" << endl;
	}
	else
	{
		cout << "Dies ist keine moegliche Kreditkartennummer!" << endl;
	}

	cin.ignore();
	getchar();
	return 0;

}
```


----------



## MiMi (15. Dezember 2010)

Hast du dir mal das Feld und die Pruefziffer ausgeben lassen?
Vermutlich geht das vergleichen von char mit int nicht gut.


----------



## vfl_freak (15. Dezember 2010)

Moin,


deepthroat hat gesagt.:


> Und schließlich wird dann auch in die Variable eingelesen (@vfl_freak: und auch automatisch terminiert).
> ...
> Aber, der C-String feld kann max 15 Buchstaben speichern - da C-Strings mit \0 terminiert sind. Falls man 16 Zeichen eingibt, schreibt man über die Feldgrenze hinaus -> Stackkorruption


ja eben ... derartige Probleme hatte ich hier anfangs schon mal 
Oder meinst Du das * [EDIT] *mit dem automatischen Terminieren*[/EDIT]* nur im Zusammenhang mit *cin* ?



freeak2305 hat gesagt.:


> Ich habe zB eine Kreditkartennummer, die definitv gültig sein muss, weil sie aus der Aufgabenstellung kommt
> 4509472140549006


Die Nummer ist 16 Ziffern lang, aber Du prüfst nur max. 15 Stellen - ist das nicht das Problem ?

Gruß
Klaus


----------



## deepthroat (15. Dezember 2010)

freeak2305 hat gesagt.:


> Allerdings scheint immernoch ein Fehler im Programm zu sein, den ich nciht finde.
> 
> Ich habe zB eine Kreditkartennummer, die definitv gültig sein muss, weil sie aus der Aufgabenstellung kommt
> 4509472140549006
> ...


Vermutlich ist einfach deine Prüfungsvorschrift falsch.

Wie sieht denn die Vorschrift zur Prüfung aus?

Gruß


----------



## deepthroat (15. Dezember 2010)

vfl_freak hat gesagt.:


> ja eben ... derartige Probleme hatte ich hier anfangs schon mal
> Oder meinst Du das nur im Zusammenhang mit *cin* ?


Naja, cin speichert fröhlich alles was da kommt an die Adresse der Variablen und terminiert dann den String mit \0. \edit: Ja, das automatische Terminieren meinte ich nur im Zusammenhang mit cin.

Da Feld[15] offenbar eine Prüfziffer ist, darf ja nicht \0 da stehen. Das Feld muss also noch eins größer sein.

@freeak2305: 

Das Problem ist, du rechnest da mit Buchstaben ('4' == 52 usw.). Du müßtest die Buchstaben erstmal in Ziffern umwandeln.

Außerdem solltest du noch prüfen ob überhaupt genug Buchstaben eingegeben wurden und ob die Eingabe überhaupt aus Ziffern besteht.

Gruß


----------



## freeak2305 (15. Dezember 2010)

Ich verstehe nicht, was du mir damit sagen willst....Wie gesagt, ich bin da ein totaler Idiot in diesem Gebiet...


----------



## deepthroat (15. Dezember 2010)

freeak2305 hat gesagt.:


> Ich verstehe nicht, was du mir damit sagen willst....Wie gesagt, ich bin da ein totaler Idiot in diesem Gebiet...


Du hast da einen String. Ein String besteht aus Buchstaben bzw. Zeichen.

"0123" <- String
'0' <- Zeichen

Zeichen haben laut ASCII Tabelle einen bestimmten Wert:

'a' => 97
'0' => 48
'1' => 49

usw.

Feld = "4509472140549006"

Feld[0] => '4' => 52

Zum Umrechnen:

```
int digit = Feld[i] - '0';
```
Zum Prüfen ob das Zeichen überhaupt eine Ziffer ist:

```
#include <cctype>

if (isdigit(Feld[i])) {
  ...
} else {
  // Fehler, kann keine Kred.-Nr. sein.
  ...
}
```
Gruß


----------



## freeak2305 (15. Dezember 2010)

Okay, das ist verständlicher für mich(tut mir Leid. Ich bin Systemintegrator und soll in der Anwendungsentwicklung aushelfen....lustig)

So, ich hab nun mal alles komplett umgeschmissen. Hat leider alles nichts gebracht. Der Wurm war trotzdem noch drin. hier nun meine Lösung, die funktioniert, aber ein kleines bisschen umständlicher ist!


```
// Kreditkartennummer überprüfen.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung.
//

#include "stdafx.h"
#include <iostream>
#include <stdlib.h>

using namespace std;

int main()
{
	int z1=0, z2=0, z3=0, z4=0, z5=0, z6=0, z7=0, z8=0, z9=0, z10=0, z11=0, z12=0, z13=0, z14=0, z15=0, z16=0;
	int pz=0, summe=0, zwischenerg=0;
	int rest1=0,rest2=0,rest3=0,rest4=0,rest5=0,rest6=0,rest7=0,rest8=0;
	
	cout << "Kreditkartennummer pruefen" << endl;
	cout << endl;
	cout << "Jede Ziffer einzeln, gefolgt von ENTER eingeben" << endl;				//Leider klappte die Version mit einem Array gar nicht
	cout << endl;

	cin >> z1;
	rest1=(z1*2)/10;																//Doppelt gewichtete Ziffern der Kreditkartennummer
	rest1+=((z1*2)%10);																//Erst Zehnerstelle ermitteln, danach die Einerstelle addieren
	cin >> z2;
	cin >> z3;
	rest2=(z3*2)/10; 
	rest2+=((z3*2)%10);
	cin >> z4;
	cin >> z5;
	rest3=(z5*2)/10; 
	rest3+=((z5*2)%10);
	cin >> z6;
	cin >> z7;
	rest4=(z7*2)/10; 
	rest4+=((z7*2)%10);
	cin >> z8;
	cin >> z9;
	rest5=(z9*2)/10; 
	rest5+=((z9*2)%10);
	cin >> z10;
	cin >> z11;
	rest6=(z11*2)/10; 
	rest6+=((z11*2)%10);
	cin >> z12;
	cin >> z13;
	rest7=(z13*2)/10; 
	rest7+=((z13*2)%10);
	cin >> z14;
	cin >> z15;
	rest8=(z15*2)/10; 
	rest8+=((z15*2)%10);
	cin >> z16;
	cout << endl;

	summe = rest1+z2+rest2+z4+rest3+z6+rest4+z8+rest5+z10+rest6+z12+rest7+z14+rest8;	//Quersumme bilden
	zwischenerg = summe % 10;															//Rest ermitteln
	pz = 10 - zwischenerg;																//Prüfziffer errechnen
	
	if(z16 == pz) 
	{ 
		cout << "Moegliche Kreditkartennummer!" << endl;
	}
	else
	{
		cout << "Kreditkartennummer nicht moeglich!" << endl;
	}

	cout << "Pruefziffer = " << pz << endl;
	cout << "Letzte Stelle der Nummer = " << z16 << endl;
	
	cin.ignore();
	getchar();
	return 0;
}
```


----------



## ComFreek (16. Dezember 2010)

Ja, du hättest das auch mit Schleifen programmieren können.


----------



## deepthroat (16. Dezember 2010)

freeak2305 hat gesagt.:


> Okay, das ist verständlicher für mich(tut mir Leid. Ich bin Systemintegrator und soll in der Anwendungsentwicklung aushelfen....lustig)
> 
> So, ich hab nun mal alles komplett umgeschmissen. Hat leider alles nichts gebracht. Der Wurm war trotzdem noch drin. hier nun meine Lösung, die funktioniert, aber ein kleines bisschen umständlicher ist!


Was hast du denn gemacht? Du hättest doch einfach nur überall da wo "Feld[..]" steht nur "(Feld[..] - '0')" hinschreiben müssen...

Nicht ganz so umständlich, mit Fehlerprüfung:

```
#include <iostream>
#include <string>
#include <cctype>

using namespace std;

int main(int argc, char *argv[])
{
    cout << "Kreditkartennr: ";

    std::string nr;
    if (cin >> nr && nr.size() == 16) {
        int zw1 = 0, zw2 = 0, zw3 = 0;

        for (int i = 0; i < nr.size() - 1; ++i) {
            if (!isdigit(nr[i])) {
                cerr << "ungültige Eingabe\n"
                     << nr << '\n'
                     << string(i, ' ') << '^' << endl;
                return 2;
            } else {
                int digit = nr[i] - '0';

                if (i % 2 == 0) {
                    zw3 = digit * 2;
                    if (zw3 >= 10) {
                        zw3 = (zw3 / 10) + (zw3 % 10);
                    }
                    zw1 += zw3;
                } else {
                    zw2 += digit;
                }
            }
        }
        int p = 10 - (zw1 + zw2) % 10;
        int l = nr[15] - '0';

        if (p == l) {
            cout << "ok" << endl;
            return 0;
        } else {
            cout << "invalid" << endl;
            return 3;
        }
    }

    cout << "Keine gültige Eingabe." << endl;
    return 1;
}
```
Normalerweise sollte man sich da Funktionen definieren...

Gruß


----------

