I think its more than a year that I ask my questions about programming in this forum.Looks like its the time that I help a little too.
So I wanna put my best here.I hope it'll help some one.
Still I'll appreciate any suggestion.
Another point,It was my first time commenting my code.So I'm waiting for your opinions about it.
Thanks you all

Base.h

BaseConvert.cpp

This program converts number bases.Because of the lack of alphabets,You may encounter nonsense characters if you use bases greater than 62.
In this program I use both capital and small alphabets which means its case sensetive.
The digits are from A which is 10 to z which is 51.

Edited 5 Years Ago by pywriter: n/a

Attachments
#ifndef BASE_H
#define BASE_H


/******************************************************************************
	*
	*	Its my first time commenting my code so I apologize if you don't understand some parts of it.	
	*	I'll be happy if you ask.
	*
	*	I will appreciate it if you give some tips on commenting too.
	*										
	*																		Thanks			
	*
	*																	Shayan Javani
	*
*///***************************************************************************


#include <math.h>
#include <string>

using namespace std;


//Generates alphabetical digits for the given base
void genDigs(int base,char *digs){						
		
	if (base>36){							//Because for bases greater than 36,the capital alphabets are not enough
	
		for(int i=0;i<26;++i)						//Generates capital alphabets
			digs[i]=i+65;
			
		for(int i=26;i<base-10;++i)				//Generates small alphabets
			digs[i]=i+71;
			
	}
		
	else
	
		for(int i=0;i<base-10;++i)			//Generates capital alphabets for bases smaller than 36
			digs[i]=i+65;
	
}


//Gets the converted number in an int array and returns a string containing the number with proper digits
string toNorm(int *num,int digNum,int base){ 
	
	char *digs=new char;						//An array for keeping digits in given base
	genDigs(base,digs);
	
	string Num;									//String variable for keeping final form of number
	
	for(int i=0;i<digNum;++i){
	
		if(num[i]<10)							//For elemnts smaller than 10,we can use the element itself as digits
			Num[i]=num[i]+48;

		else
			Num[i]=digs[num[i]-10];		//Otherwise it should be replaced by an alphabetical digit
			
	}
	
	delete [] digs;
	
	return Num;
}


//Gets an string as a proper number in the given base and replaces alphabetical digits with numbers
int fromNorm(string num,int base,int *dest){

		char *digs=new char[base-10];
		genDigs(base,digs);
		
		for(int i=0;i<num.size();++i){
			
			bool found=false;
			
			for(int j=0;j<base-10;++j){
							
				if(num[i]==digs[j]){
				
					dest[i]=j+10;					//The index of a digit is its equivalent number minus 10
					found=true;
					break;
					
				}
			}
				
			if(!found)							//If the digits is a number smaller than 10
				dest[i]=num[i]-48;			//Which can be used right after converting it from char to int
				
		}
		
		delete[] digs;
		
		return num.size();

}


//One way of converting decimal numbers to a given base
int DecToB1(unsigned long int num,int base,int *dest){

	int digNum=(int)ceil(log(num)/log(base));				//Calculates the number of digits in the given base
	
	for(int i=digNum-1;i>0;--i){
	
		dest[i]=num%base;
		num=(unsigned long int)floor(num/base);
		
	}
	dest[0]=num;
	
	return digNum;
}


//A function which does the convert and also replaces numbers with proper digits
string DecToB(unsigned long int num,int base,int &digNum){
	
	int *dest=new int;
	int n=DecToB1(num,base,dest);
	
	digNum=n;
	
	string Num=toNorm(dest,n,base);
	
	return Num;

}


//Converting numbers from a base to decimal
unsigned long int BToDec(string baseNum,int base){
	
	int *num=new int;	
	int n=fromNorm(baseNum,base,num);

	int Num=0;
	for(int i=n;i>0;--i)
		Num+=num[n-i]*(unsigned long int)pow(base,i-1);
		
	delete [] num;
	
	return Num;
	
}




//Another way of converting decimal numbers to other bases which I do
int DecToB2(unsigned long int num,int base,int *dest){

	int digNum=(int)ceil(log(num)/log(base));
	int quotients[digNum];
	quotients[0]=num;
	
	for(int i=1;i<digNum;++i){
	
		quotients[i]=(int)floor(num/base);
		num=(unsigned long int)floor(num/base);
		
	}
	
	dest[0]=quotients[digNum-1];
	
	for(int i=1;i<digNum;++i)
	
		dest[i]=quotients[digNum-i-1]-quotients[digNum-i]*base;
		
	
	return digNum;
}

#endif
#include <iostream>
#include <conio.h>
#include <stdlib.h>
#include "Base.h"

using namespace std;

int main(){

	while(1){
		
		system("cls");
		
		int choice;
		
		cout<<"\n\n\n   1-Convert from decimal";
		cout<<"\n   2-Convert to decimal";
		cout<<"\n   3-Exit";
		
		cout<<"\n\n   Enter your choice:";
		cin>>choice;
		
		switch(choice){
			
			case 1:{
			
				system("cls");
				
				unsigned long int num;
				int base,n;
				
				cout<<"\n\n   Enter the number:";
				cin>>num;
				
				cout<<"   Enter the destination base:";
				cin>>base;
				
				string Num=DecToB(num,base,n);
				
				cout<<"\n   The number you entered is ";
				for(int i=0;i<n;++i)
					cout<<Num[i];
				cout<<" in base "<<base;
				cout<<"\n\n   (Press any key to return to the main screen)";
				
				getch();
				continue;
				
			}
			
			case 2:{
			
				system("cls");
					
				string Num;
				int base;
				
				cout<<"\n\n   Enter the number:";
				cin>>Num;
					
				cout<<"   Enter its base:";
				cin>>base;
				
				cout<<"\n   The nuber you entered is "<<BToDec(Num,base)<<" in decimal";
				cout<<"\n\n   (Press any key to return to the main screen)";
				
				getch();
				continue;
				
			}
			
			case 3:
				
				return 0;
					
		}
	}
	
	return 0;
}

Comments...

Get rid of the tabs. You can see what happens when you assume 4 spaces and Daniweb assumes 8 spaces. Convert tabs to spaces.

//Generates alphabetical digits for the given base
void genDigs(int base,char *digs){						
		
	if (base>36){							//Because for bases greater than 36,the capital alphabets are not enough
	
		for(int i=0;i<26;++i)						//Generates capital alphabets
			digs[i]=i+65;
			
		for(int i=26;i<base-10;++i)				//Generates small alphabets
			digs[i]=i+71;
			
	}
		
	else
	
		for(int i=0;i<base-10;++i)			//Generates capital alphabets for bases smaller than 36
			digs[i]=i+65;
	
}

Much nicer.

//Generates alphabetical digits for the given base
void genDigs(int base,char *digs){
    if (base>36){  //Because for bases greater than 36,the capital alphabets are not enough	
        for(int i=0;i<26;++i)	//Generates capital alphabets
            digs[i]=i+65;
			
        for(int i=26;i<base-10;++i) //Generates small alphabets
            digs[i]=i+71;			
    }	
    else
        for(int i=0;i<base-10;++i)	//Generates capital alphabets for bases smaller than 36
            digs[i]=i+65;	
}

As far as comments go, a comment would be in order when using "71". I assume it's because 71 is 97 - 26, or 'a' - 26. In which case, make life easy and do the replacement.

//Generates alphabetical digits for the given base
void genDigs(int base,char *digs){
    if (base>36){  //Because for bases greater than 36,the capital alphabets are not enough	
        for(int i=0;i<26;++i)	//Generates capital alphabets
            digs[i]=i+'A';
			
        for(int i=26;i<base-10;++i) //Generates small alphabets
            digs[i]=i+'a' - 26;			
    }	
    else
        for(int i=0;i<base-10;++i)	//Generates capital alphabets for bases smaller than 36
            digs[i]=i+'A';	
}

Maybe a constant for 26 like NUM_LETTERS. Makes the code reading easier.


Generally you'll have a file called BaseConvert.h and a file called BaseConvert.cpp. All the stuff in BaseConvert.h goes in BaseConvert.cpp. Your DECLARATIONS go in BaseConvert.h. Your implementation code goes into BaseConvert.cpp. That's usually the way things are done. Makes linking and including easier.

string Num;									//String variable for keeping final form of number
	
for(int i=0;i<digNum;++i){
    if(num[i]<10)//For elemnts smaller than 10,we can use the element itself as digits
        Num[i]=num[i]+48;
    else
        Num[i]=digs[num[i]-10]; //Otherwise it should be replaced by an alphabetical digit
}

Looks like a seg fault just waiting to happen. Use the += operator. Even if it isn't a seg fault, if you're appending a character to the end, the += operator is the way to go.

Num[i] += digs[num[i]-10];

But you've got bigger problems...

char *digs=new char; //An array for 
delete [] digs;

I don't see an "array" of chars allocated. I see ONE char allocated. But I see an "array" deleted. And I see a function that expects an array.

I didn't actually run your program. Does it compile? Does it run? Does it crash? Give good results?

Edited 5 Years Ago by VernonDozier: n/a

Not a bad effort, however, your comments suggest that you would like some feedback...
So here are a few things that I have noticed.

First off, I don't like seeing using namespace std; anywhere, but NEVER in a header.

In function BToDec, you do this:

int *num=new int;         // This only allocatts ONE integer

fromNorm(baseNum,base,num);         // This uses num as if it is an array of size dependent
                                    // on the string baseNum. 

// ... other stuff.
delete [] num;   // definately wrong

This error is repeated throughout

Additionally, in that function you do this:

int Num; 
for(int i=n;i>0;--i)
  Num+=num[n-i]*(unsigned long int)pow(base,i-1);

Several problems with just those three lines. First you take the trouble to convert the result of pow() to an unsigned long int only to add it to a value that is only an int.
Obviously not really a good idea.
Surely the power etc could be avoided with code like this:

int Num(0); 
for(int i=0;i<n;i++)
  {
     Num*=base;
     Num+=num[i];
  }

Also you know how to use references, so get into the habit of using them, time and time again you just pass large objects by value (e.g. strings etc).

Also fromNorm just needs a re-write. What happens if base is less than 10?? e.g in line char *digs=new char[base-10]; Anyway it is good that you are trying to write an extended piece. Writing numerical code, both efficiently and robustly, is extremely taxing and will significantly improve you coding ability.

Thank you for your advices.They solved some problems of the program but I don't know how.
Stu,with my algorithm,for some numbers and bases,I got a wrong answer for the first time but a right one for further trys.Your new algorithm almost solved it.
But a new problem remains now.Sometimes when I enter a number and a base usually bigger than 20,the program terminates.As I remember,when I printed some flags,I understood it terminates while reaches new commands.But when I give one or more numbers with bases smaller than 20 and then try bases bigger,It works.
What's wrong?
this is the new code

Edited 5 Years Ago by pywriter: n/a

Unfortunately, there is still lots wrong with this. It would also have helped if you had just posted your code, nobody does (or should) run executables from unknown sources.

Now to the code itself..... I am going to list a number of types of errors, but only one of each type (as I classify it, so it is very arbitrary ;)

void genDigs(int base,char *digs)
{							
  if(base<10)
    {
      digs=NULL;
      return;
  }
//....

The error here is that setting digs to null has zero effect. If you had done this *digs ='c'; , then it would have had an effect.
Reason that you still have this error: You did not turn on warnings in your compiler.
(or pay attention to them).

std::string 
toNorm(int *num,int digNum,int base)
{ 
  std::string Num;      //String variable for keeping final form of number
  char *digs=new(std::nothrow) char;      //An array for keeping digits in given base
  genDigs(base,digs);
  if (digs)
//....

you allocate ONE character, but then use digs as a multiple character array.
Either (a) allocate sufficient characters, (b) use an expandable storage, e.g. std::string. (c) make getDigs allocate the space.

You specifically use the nothrow new, and test digs AFTER using it!!!!

You use variables called num and Num, that is one small mistype away from a difficult error, and it is close to impossible to read easily. Think about your variable naming!

for(int i=0;i<digNum;++i)
   {
     if(num[i]<10)	
       Num+=num[i]+'0';
      else
        Num+=digs[num[i]-10];     
   }

The code above is what you wrote, consider this:

std::string toNorm(const int *num,const int digNum,const int base)
{
  static const char digs[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  // Tests here on the sanity of digNum, num[i]
  std::string Out;
  for(int i=0;i<digNum;i++)
    {
      // test if num[i]<0 or >base etc.
      Out+=digs[num[i]];
    }
  return Out;
}

The toNorm function I have written, that isn't that complex, but replaces some 67 lines of your code.

In short there is nothing special about base 10. you can easily avoid ALL the base<10 tests that you have.

You can also count up and divide, to avoid some of your calculation to the number of digits.


Hope this helps....

Thanks for all of your advices.They solved lots of problems.
This is the OO version of the program.

But there is one problem about it.I overloaded the insertion operator (<<) like below:

ostream& operator<<(ostream &stream,const BaseConvertor &param){
	
	stream<<param.sNum<<"("<<param.Base<<")";
	
	return stream;
	
}

I also overloaded both postfix and prefix versions of ++ and --:

BaseConvertor& BaseConvertor::operator++(){

	int base=this->Base;
	
	this->Convert(10);
	
	*this=*this+1;
	
	this->Convert(base);
	
	return *this;
	
}


BaseConvertor BaseConvertor::operator++(int){

	BaseConvertor temp=*this;
	
	int base=this->Base;
	
	this->Convert(10);
	
	*this=*this+1;
	
	this->Convert(base);
	
	return temp;
	
}

The problem is with the code below:

BaseConvertor num;
	
cin>>num;
	
cout<<"\n"<<num<<"-"<<num++<<"-"<<num<<"-"<<++num<<"\n";

If you give e.g. 5 in base 10,the output is:

7(10)-6(10)-7(10)-7(10)

But ,as you know,if you do it with an int,you will get:

5-5-6-7

what's wrong?

thanks

Edited 5 Years Ago by pywriter: n/a

After some tests,I understood that the thing I mentioned above,is the normal behaviour.
As you can see,its a bit confusing and brings this question to mind:
How streams really work?

This article has been dead for over six months. Start a new discussion instead.