Member Avatar for Brian Perrigan
#include <iostream>
#include <string>
#include <sstream>
using namespace std ;

int main ()
{
    
        char promptisbn [] = "Plese Enter 10 Digit ISBN" ;
        string isbn ;
        int x = 0 ;
        char buffer[1024] ;
        
        cout << promptisbn << endl ;
        cin.getline ( buffer, sizeof(buffer), '\n') ;
        isbn = buffer ;
        
        
                for ( x=0 ; x < isbn.length() ; x++ )
                    
                        if ( !isdigit(isbn[x]) && toupper(isbn[x]) != 'X') 
                            { printf("erasing: %c\n", isbn[x]) ;isbn.erase (x,1) ; --x ;}
                    
        
        
        cout << "You Entered: " << endl ;
        cout << isbn << endl ;

		 int a, b , c , d , e , f , g , h , i , j ;

        a = isbn[0] ;
        b = isbn[1] ;
        c = isbn[2] ;
        d = isbn[3] ;
        e = isbn[4] ;
        f = isbn[5] ;
        g = isbn[6] ;
        h = isbn[7] ;
        i = isbn[8] ;
        j = isbn[9] ;


        cout << a << endl ;
        cout << b << endl ;
        cout << c << endl ;
        cout << d << endl ;
        cout << e << endl ;
        cout << f << endl ;
        cout << g << endl ;
        cout << h << endl ;
        cout << i << endl ;
        cout << j << endl ;
     
		getchar () ;
}

I'm working on writing an ISBN validation program. I need to be able to access the individual values of the isbn string after it's been cleaned up. Right now when I output this I get as follows:

Please Enter 10 Digit ISBN
123456789X
You Entered:
123456789X
49
50
51
52
53
54
55
56
57
88

so the output is the address of where the values are... not the actual values in that block of memory.

What approach would I take to be able to access these values individually so I can continue with the homework and start doing arithmetic with them?

It's not outputting the address of the values.. an address looks like 0x00401000 and the individual elements of the string wouldn't just take 1 byte (and also.. '88' doesn't really follow 57 :P).

Basically, you have stumbled upon something called 'implicit conversion'. When you access isbn[ i ] the datatype is 'char', and you are storing it in an int variable (the a through j variables). So what happens is the compiler is implicitly converting the character it finds at index i to an int.
Now if the character at index 0 is '1' and the compiler is converting that you should get 1 in your 'a' variable shouldn't you? Wrong! Instead you get the ASCII value of '1' in your 'a' variable (see www.asciitable.com '1' is ASCII 49).

So you need to find another way...
- You can convert a char* to an int using atoi (abbrevation for 'array-to-int'). But this is a C-style function.
- A C++ approach would be to use 'std::stringstream'.

I'll leave it to you to read up on these topics and if you're stuck.. ask again.

Member Avatar for Brian Perrigan

Rad. That smiley face cracked me up.

I tried using string stream like this:

int isbn_int1;
stringstream(isbn) >> isbn_int1;
cout << isbn_int1 << endl ;

and if I enter 12345689X I get:
123456789

okay I see that it worked... but if I just try to store one value of the number like this:

int isbn_int1;
stringstream(isbn[0]) >> isbn_int1;
cout << isbn_int1 << endl ;

I get:
-858993460

So I obviously cannot do that hahah. Using the atoi method like this:

#include <stdio.h>
#include <stdlib.h>
int isbn_intatoi ;
isbn_intatoi = atoi (isbn) ;

I get these errors:

error C2664: 'atoi' : cannot convert parameter 1 from 'std::string' to 'const char *'
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

Hmm well let's think of another way... you know that '1' is ASCII 49, so if in your original code you substract 48, you get the integral number. Since you know that the ISBN consists of 0-9 this is imo an acceptable solution.

Member Avatar for Brian Perrigan

yes that is true. I could do that. The problem is that I'm suing the 123456789X as an example. it can be any 10 digit isbn... ending with a number (0-9) or an X.

I'll keep working on it. I have until the 17th to finish it. :D

What I want to be able to do is access the numbers and separate them like this, if isbn = 123456789X
I want to be able to seperate that isbn string into

int a = isbn[0]
int b = isbn[1]
...

so I can then go ahead and use the cheksum method like this:

(a * 1) + (b * 2) + (c * 3) ....

Yes, so you could do:

int a = isbn[0] - 48;

You need to deal with the X of course... but that should not be too hard if you know that isbn[ i ] - 48 has to be in [0-9]

error C2664: 'atoi' : cannot convert parameter 1 from 'std::string' to 'const char *'
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

atoi conversion using <string>

std::string str_isbn = "123456789";
int isbn_numerical = atoi(str_isbn.c_str());

//alternatively
char isbn[] = "123456789";
isbn_numerical = atoi(isbn);

Not sure why you would store all the values from your array into single ints a-j when you could just use the array and for loops to store the sums into a value.

You could use stringstream but if you don't want to include another header file and since the use of it is so small I think just subtracting 48 from the characters (as said above) is a faster and easier method for this small assignment.

When doing mini programs like these I would try to make the program as small and clean as possible just for good practice for when you have to work on bigger projects where it can get really confusing if everything is crammed together with poor formatting and poorly named variables.

#include <iostream>

using namespace std;

int main()
{
	string input; //stores input
	cout << "Please enter a 10-digit ISBN number: " << endl;
	getline(cin, input);

	for( int i = 0; i < (int)input.length(); i++ )
	{
		//checks if each index of the string is valid and if the length is correct
		if( (!(input[i] >= 48 && input[i] <= 57) && !(i == (int)input.length()-1 && toupper(input[i]) == 'X')) || input.length() != 10 )
		{
			cout << "Not valid input!" << endl;
			getchar();
			return 0;
		}
	}
	int sum = 0;
	// (a*1)+(b*2)+(c*3)+(d*4)+(e*5)+(f*6)+(g*7)+(h*8)+(i*9) % 11 = checksum
	for( int i = 0 ; i < (int)input.length()-1; i++ ) //sums the product of the first 9 numbers and 1-10
		sum += ((int)input[i]-48)*(i+1);
	sum %= 11; //takes the remainder of the sum divided by 11

	if( sum != (int)input[9]-48 || ( sum == 10 && toupper(input[9]) == 'X' ) ) //checks to see if the sum is the 10th number
		cout << "Invalid ISBN number!" << endl;
	else
		cout << "Valid ISBN number." << endl;

	getchar();
	return 0;
}
Member Avatar for Brian Perrigan

You guys are rad. Great advice with keeping things simple. I'm gonna take a look at the code posted above and try to re write mine to be simpler and cleaner.

This is my first experience with coding of any type. And I am just starting to wrap my head around the mental state needed to work out these problems. It's all very simple but it takes a particular way of looking at things that I am not used to. I think it's partly because I yet do not know the entire language very well.

Member Avatar for Brian Perrigan
if( sum [B]![/B]= (int)input[9]-48 || ( sum == 10 && toupper(input[9]) == 'X' ) )

is supposed to be:

if( sum = (int)input[9]-48 || ( sum == 10 && toupper(input[9]) == 'X' ) )

minus the "not" symbol right? Since I'm reading it as

if the sum mod 11 of the input number is equal to the inputs number 10th digit OR if the sum mod 11 of the input number is an X, then the ISBN is valid.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.