Pointer als Rückgabewert eines Unterprogramms



  • SeppJ schrieb:

    Du beschreibst keine Zahl, sondern eine Ziffernfolge. Sieht zwar beides gleich aus (in den üblichen Darstellungen), ist aber ganz was anderes.

    Doch die IBAN wird in eine Zahl umgewandelt um die Prüfsumme zu berechnen. Vielleicht verwechselst du das mit der ISBN(da ist es eine Ziffernfolge).

    BTT: Erstelle ersteinmal die Ziffernfolge in der richtigen Reihenfolge, so wie du es beschrieben hast. Nimm dafür einfach ein int Array der nötigen Länge(24?).
    Danach musst du von hinten nach vorne die Stellen der letztendlichen Zahl berechnen. Als Datentyp probier mal long long int.

    //array = die Ziffernfolge mit Ziffern in der richtigen Reihenfolge
    int i;
    long long int zahl = 0;
    for (i = sizeof (array)-1; i >= 0; i--)
    {
    zahl += pow (10, (sizeof (array) - i)) * array[i];
    }
    

    So in etwa, ist eher Pseudo Code. 🙂
    Für pow benötigst du math.h, damit berechnest du die zehner, hunderter, etc. Stelle der Zahl.


  • Mod

    sacridex schrieb:

    SeppJ schrieb:

    Du beschreibst keine Zahl, sondern eine Ziffernfolge. Sieht zwar beides gleich aus (in den üblichen Darstellungen), ist aber ganz was anderes.

    Doch die IBAN wird in eine Zahl umgewandelt um die Prüfsumme zu berechnen. Vielleicht verwechselst du das mit der ISBN(da ist es eine Ziffernfolge).

    Eine Prüfsumme macht aus einer Ziffernfolge keine Zahl, sondern ist ein weiteres Argument, dass es sich nicht um eine Zahl handelt.



  • @sacridex
    Für eine 24-Stellige Dezimalzahl braucht man ca. 80 Bit zu Darstellung.
    long long hat meist 64 Bt. Reicht also nicht.

    Und statt pow und hinten am Array anzufangen, fängt man vorne an und rechnet immer mal 10. Zumal auch pow (auch für long double) für volle 24 Dezimalstellen nicht ausreicht.



  • Mit C99 liegt die min. garantierte Grenze für unsigned long long int bei 18446744073709551615 bzw. 18446744073709551615ULL, d.h. man kann max. 19 Dezimalstellen bei Integer-Berechnungen damit verwenden.
    Ältere MSVC haben stattdessen (weil kein C99) dafür unsigned __int64.



  • SeppJ schrieb:

    sacridex schrieb:

    SeppJ schrieb:

    Du beschreibst keine Zahl, sondern eine Ziffernfolge. Sieht zwar beides gleich aus (in den üblichen Darstellungen), ist aber ganz was anderes.

    Doch die IBAN wird in eine Zahl umgewandelt um die Prüfsumme zu berechnen. Vielleicht verwechselst du das mit der ISBN(da ist es eine Ziffernfolge).

    Eine Prüfsumme macht aus einer Ziffernfolge keine Zahl, sondern ist ein weiteres Argument, dass es sich nicht um eine Zahl handelt.

    eine zahl ist eine folge von ziffern, wo ist das problem und was soll die haarspalterei?



  • x.x. schrieb:

    eine zahl ist eine folge von ziffern, wo ist das problem und was soll die haarspalterei?

    Ja, aber nicht jede Folge von Ziffern ist eine Zahl. Wer das nicht versteht, addiert auch Telefonnummern.



  • Wenn man rechnen will, benötigt man ein Zahl (interpretierte Ziffernfolge zu einer Basis), um darauf einen Operator (hier wohl 😵 anwenden zu können.
    Die Frage ist bloß, ob man wirklich rechnen muss oder nur vermeintlich und es auch anders geht.
    Mit C99 wie gesagt max. 19 Dezimalstellen, ansonsten muss man zu einer Big-Integer Bibliothek greifen, es gibt mehrere mehr oder weniger handliche.



  • SeppJ schrieb:

    Eine Prüfsumme macht aus einer Ziffernfolge keine Zahl, sondern ist ein weiteres Argument, dass es sich nicht um eine Zahl handelt.

    Lies dir doch bitte erstmal die Definition der IBAN durch, bevor du hier wild rumspekulierst...
    http://de.wikipedia.org/wiki/International_Bank_Account_Number#Validierung_der_Pr.C3.BCfsumme

    btt: Gut, dann reicht long long nicht. Habe es nur vermutet. 😉
    long long long gibts nicht? Bei einem 64bit System dürfte es doch sowas geben?



  • Das hast du nicht verstanden, unsigned long long int nutzt bereits die 64Bit-Breite, denn 264-1 == 0xFFFFFFFFFFFFFFFF == 18446744073709551615



  • Ja, ich weiß, aber das tut es ja auch auf einem 32bit System, deshalb könnte es ja sein, dass es einen Datentyp mit 128bit auf 64bit Systemem gibt, wäre ja in beiden Fällen doppelte Wortbreite.
    Habe schon __int128 probiert, geht aber irgendwie nicht. 😞



  • sacridex schrieb:

    Habe schon __int128 probiert, geht aber irgendwie nicht. 😞

    RTFM von deinem Compiler statt rumzuraten.



  • DirkB schrieb:

    RTFM von deinem Compiler statt rumzuraten.

    Hab ich gemacht, aber es wird halt nicht unterstützt.
    http://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html

    An was liegt, es, dass 128bit ints unterstützt werden?



  • Ein 128-Bit Integertyp wird von keinem C-Standard unterstützt, deshalb kocht jeder Compilerhersteller hier sein eigenes Süppchen (der Nachteil, wenn man sich nicht an den Standard hält/halten kann).

    MS hat hierfür vorgefertigte sogenannte x64-Intrinsics

    #include <intrin.h>
    

    , bei gcc musst du dich mit asm-Gefrickel auseinandersetzen und auf dieser asm-Ebene mit 2 64-Bit-Werten rumhantieren, die nur zusammengenommen einen 128-Bit Wert repräsentieren.
    D.h. der Compiler muss 64-Bit beherrschen, (der Prozessor natürlich auch, dass "Machinen-Wort" also auch 64-Bit beherrschen, entweder direkt oder in irgendwelchen Emulationsmodi)
    Portabel ist das Ganze natürlich überhaupt nicht mehr.

    Es gibt aber auch den lcc-win, der bietet sogar in der 32-Bit Variante einen (natürlich nichtportablen) int128 (Struktur)Typ an und dafür dann die Operatoren +-*/.

    #include <stdio.h>
    #include <int128.h>
    int main()
    {
      char buf[100];
      int128 a = 3602004100123456781ULL;
    
      a = a * 100000;
      a = a + 31400;
    
      a = a - ((a / 97) * 97); /* kleiner modulo-Ersatz, da %-operator für int128 nicht unterstützt wird */
    
      i128toa(&a,buf);
      printf("%s\n",buf);
    
      return 0;
    }
    

    Der Compiler scheint zwar ziemlich fehlerhaft zu sein, aber immerhin bietet er eben diesen nativen 128Bit-Support.
    Ansonsten empfehle ich wie schon erwähnt diverse Big-Integer Bibliotheken, die sind dann natürlich für die angebotenen Plattformen portabel.



  • 32 bits reichen schon...

    #include <algorithm>
    #include <vector>
    #include <cctype>
    #include <string>
    #include <iostream>
    
    /* Aufbau einer IBAN lt. ECBS EBS 204:
                    1           2            3
         1234 5678 9012 3456 7890 1234 5678 9012 34
    IBAN LLPZ [ BBAN                              ]
    
    LL: 2-stelliger Ländercode lt. ISO 3166
    PZ: 2-stellige numerische Prüfziffer (Modulo 97-10 gemäß ISO 7064) über die ganze IBAN
    BBAN: bis zu 30-stellige Basic Bank Account Number, bestehend aus Instituts-Identifikation (IID, 4 bis 12 Stellen) und Kontoidentifikation (BAN, 8 bis 20 Stellen) */
    
    class iban_t
    {
    	friend std::ostream & operator<<( std::ostream &, const iban_t & );
    
    	private:
    		static const char * const prefix;
    		std::string iban;
    		bool valid;
    
    		unsigned calc( ) {
    
    			std::string temp = iban.substr( 4, iban.length() ) + iban.substr( 0, 4 );
    
    			std::vector< unsigned char > iban_data;
    
    			for( std::string::iterator i = temp.begin(); i != temp.end(); ++i ) {
    
    				std::string::value_type c = *i;
    
    				if( std::isdigit( c ) ) {
    
    					iban_data.push_back( c - '0' );
    
    				} else if( std::isalpha( c ) ) {
    
    					c = c - 'A' + 10;
    					iban_data.push_back( c / 10 );
    					iban_data.push_back( c % 10 );
    
    				} else {
    
    					return false;
    				}
    			}
    
    			unsigned long block = 0;
    			unsigned int remainder = 0;
    
    			for( std::vector< unsigned char >::size_type i = 0, iban_data_size = iban_data.size(); i < iban_data_size; i += 9 ) {
    
    				block = 0;
    				unsigned long p = 1;
    
    				for( std::vector< unsigned char >::size_type j = i + 9 <= iban_data_size ? i + 9 : iban_data_size; j > i; --j, p *= 10 ) {
    
    					block += iban_data[ j - 1 ] * p;
    				}
    				remainder = block % 97;
    				unsigned int remainder_digits = remainder / 10 ? 2 : 1;
    
    				if( i + 9 < iban_data_size ) {
    
    					iban_data.insert( iban_data.begin() + i + 9, remainder_digits, 0 );
    
    					if( remainder_digits == 1 ) {
    
    						iban_data[ i + 9 ] = remainder;
    
    					} else {
    
    						iban_data[ i + 9 ] = remainder / 10;
    						iban_data[ i + 10 ] = remainder % 10;
    					}
    
    					iban_data_size = iban_data.size();
    				}
    			}
    
    			return remainder;
    		}
    
    		bool validate() {
    
    			return calc() == 1;
    		}
    
    	public:
    		iban_t( const std::string &ibanstring ) : iban( ibanstring ), valid( false )
    		{
    			iban.erase( std::remove_if( iban.begin(), iban.end(), std::isspace ), iban.end() );
    			std::transform( iban.begin(), iban.end(), iban.begin(), std::toupper );
    
    			if( iban.substr( 0, 4 ) == "IBAN" ) {
    				iban = iban.substr( 4, iban.length() );
    			}
    
    			valid = validate( );
    		}
    
    		bool is_valid() const { return valid; }		
    
    		void recalc() {
    
    			iban[ 2 ] = '0';
    			iban[ 3 ] = '0';
    
    			unsigned int remainder = 98 - calc();
    
    			iban[ 2 ] = '0' + remainder / 10;
    			iban[ 3 ] = '0' + remainder % 10;
    
    			valid = validate();
    		}
    };
    
    const char * const iban_t::prefix = "IBAN";
    
    std::ostream & operator<<( std::ostream &os, const iban_t &iban )
    {
    	os << iban_t::prefix;
    
    	for( std::string::size_type i = 0, length = iban.iban.length(); i < length; i++ ) {
    
    		if( i % 4 == 0 ) {
    			os << ' ';
    		}
    
    		os << iban.iban[ i ];
    	}
    	return os;
    }
    
    int main()
    {
    	iban_t iban( "DE68210501700012345678" );
    
    	std::cout << iban << " is" << ( iban.is_valid() ? "" : " not" ) << " valid.\n";
    }
    

    // Hoppala ... die Lösung in C läuft ähnlich 😃


Anmelden zum Antworten