You are here:

C++/Programming

Advertisement


Question
I have the following program in C++... A user enters a length in INCHES and i convert it to the listed units. I am trying to get it to work for CM first. and it wont... here is what i have so far:


#include <stdio.h>
#define CM=(2.54*inch)
void main(void) {

float inch,cm,mm,m,yrd,mls,km,ft;

printf("\nEnter Length In Inches: ") ;
scanf("%d",&inch);

if (inch<0){
   printf("Length CANNOT Be Negative");
}

if (inch>=0){
   
   
   printf("%d","CM");
}}    

Answer
C++ you say. This looks like pure C to me, not C++ - OK so a C++ compiler might compile it but it is still a C program.

Now other than your dodgy layout and use of K & R brace placement - generally not used for readable code these days - your code contains several problems.

So assuming we are talking C here and not C++:

void main( void ) is not a valid signature for main. I would think this is a Microsoft Visual C++ "extension" or deficiency. The only valid forms for main (from the latest C standard) are:

       int main(void) { /* ... */ }
and
       int main(int argc, char *argv[]) { /* ... */ }


The C++ standard has the equivalent forms:

       int main() { /* ... */ }
and
       int main(int argc, char* argv[]) { /* ... */ }

The only difference being that in C++ you are allowed to omit the void when specifying an empty argument list for a function.

Now the program does not work for at least two very good reasons.

- first you specify in the patterns to printf and scanf that you are entering / outputting int values, then pass inches - a float type. Use "%f" (float) for scanf and maybe "%6.2f" ( double field 6 characters wide, with 2 decimal places of precision).

- second this call to printf is not what want, even if the output value type were correct:

       printf("%d","CM");

The first string contains a pattern specifying that an integer is to be output. This is wrong as mentioned.

You then pass it a string literal - which will be converted to a char * - so you will probably see some strange value that represents the address the string literal exists at in memory...

These are the reason printf, scanf etc can be dangerous - there is no type checking or even checking that there are enough parameters to match the input/output pattern given in the first string. You should probably change the printf statement to something like:

       printf("%6.2f", CM);

You should also always check the retuned value from scanf to ensure all fields were assigned to variables.

Now I have had a look at your CM macro and it is horrid! Even for a pre-processor macro. You do work like a function but you hardcode the parameter as a variable named inches. Also the syntax is bad so I doubt the code would even compile. Take out the = .

       #define CM (2.54*inch)

A better bet (for a C program) would be to define the inches to cm value:

       #define INCHES_TO_CM        2.54

then your printf call would be:

       printf("%6.2f", INCHES_TO_CM * inches);

Or to parameterise the macro:

       #define INCHES_TO_CM(inches)        (inches*2.54)
then

       printf("%6.2f", INCHES_TO_CM(inches) );

Now I see no reason to use a vile, unsafe pre-processor macro here unless you are really bothered about efficiency - which you probably are not - so just make INCHES_TO_CM a function and have done with it:

       double InchesToCm( double aInches )
       {
               return 2.54 * aInches;
       }

then
       printf( "%6.2f", InchesToCm(inches) );


Notice that I changed the type to double - C always passes floating point types as doubles anyway.

Now how about using some actual C++:

// First as we will be using the C++ iostreams, include the appropriate
// C++ library header.
#include <iostream>

// Use an unnamed namespace to keep these values local to this file
namespace
{
// We define the InchesToCm shown previously. As it is very simple
// if we were concerned about performance we could specify it as inline
// as a request to the compiler to expand calls inline at the call
// sites instead of making a function call
           
           double InchesToCm( double aInches )
           {
                   return 2.54 * aInches;
           }
}

// Use the correct, C++ style of main we require:
int main()
{
// Use C++ IOStreams to request the inches value
       std::cout << "Enter a positive length in inches: ";
       
// Here I define inches to be double but float would do too
       double inches(0.0);

// Use C++ IOStreams to input the value
       std::cin >> inches;

       if ( inches < 0.0 )
         {
         // Use C++ IOStreams to output the error message
                 std::cout << "Value should be positive...\n";
         }
       
       if ( inches >= 0.0 )
         {
         // Use C++ IOStreams to output the result
                 std::cout << inches << " inches is "
                           << InchesToCm(inches) << "cm.\n";
         }
}

For both the C and C++ versions of the code the two if statements could be replaced with if .. else as the value is either OK or it is not:

       if ( inches < 0.0 )
         {
                 std::cout << "Value should be positive...\n";
         }
       else // value good
         {
                 std::cout << inches << " inches is " <<
                           << InchesToCm(inches) << "cm.\n";
         }

Next, you may wish to add a loop to allow the user to enter more than one value for each run. If so you will have to decide how to exit the program.

Now if you would rather have your conversion function return the same type as it is passed - so if you pass an int it returns an int, if you pass a double it returns a double you could just overload the function. I admit this is probably not what you wish for such unit conversions, but it demonstrates some useful C++ features:

           int InchesToCm( int aInches )
           {
                   return 2.54 * aInches;
           }

           double InchesToCm( double aInches )
           {
                   return 2.54 * aInches;
           }

The only problem is that you may well receive warnings from the compiler when it converts the double result of 2.54*aInches back to an integer for the int version. If we want to be really flash we could make the function a function template:

namespace
{
           template < typename LengthType >
           inline LengthType InchesToCm( LengthType aInches )
           {
                   return 2.54 * aInches;
           }
}

Note that I made the function inline just for the sake of example.

Then when InchesToCm is called the compiler generates a particular version of InchesToCm from its template definition based on the type of the aInches it is passed - if it is passed a double then a function taking and returning a double is generated. If it is passed an int then a function taking and return an int is generated.

Now I could go on - making the raw values class types that represent units for example - but I think you have enough to think about for now.  

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


Ralph McArdell

Expertise

I am a software developer with more than 15 years C++ experience and over 25 years experience developing a wide variety of applications for Windows NT/2000/XP, UNIX, Linux and other platforms. I can help with basic to advanced C++, C (although I do not write just-C much if at all these days so maybe ask in the C section about purely C matters), software development and many platform specific and system development problems.

Experience

My career started in the mid 1980s working as a batch process operator for the now defunct Inner London Education Authority, working on Prime mini computers. I then moved into the role of Programmer / Analyst, also on the Primes, then into technical support and finally into the micro computing section, using a variety of 16 and 8 bit machines. Following the demise of the ILEA I worked for a small company, now gone, called Hodos. I worked on a part task train simulator using C and the Intel DVI (Digital Video Interactive) - the hardware based predecessor to Indeo. Other projects included a CGI based train simulator (different goals to the first), and various other projects in C and Visual Basic (er, version 1 that is). When Hodos went into receivership I went freelance and finally managed to start working in C++. I initially had contracts working on train simulators (surprise) and multimedia - I worked on many of the Dorling Kindersley CD-ROM titles and wrote the screensaver games for the Wallace and Gromit Cracking Animator CD. My more recent contracts have been more traditionally IT based, working predominately in C++ on MS Windows NT, 2000. XP, Linux and UN*X. These projects have had wide ranging additional skill sets including system analysis and design, databases and SQL in various guises, C#, client server and remoting, cross porting applications between platforms and various client development processes. I have an interest in the development of the C++ core language and libraries and try to keep up with at least some of the papers on the ISO C++ Standard Committee site at http://www.open-std.org/jtc1/sc22/wg21/.

Education/Credentials

©2012 About.com, a part of The New York Times Company. All rights reserved.