Write a function write with variable number of arguments that takes a string first argument followed by any number of arguments of type double and prints on the screen a string formatted by the rules described below. The first argument may contain formats in curly braces of the form {index[:specifier]}, where the square brackets show optional parts (that is :specifier may be missing), and index is the sequence number of an argument of type double (starting from sequence number 0).
Rules for formatting: In the printed string the curly brackets and their content will be replaced by the argument with the given index, formatted according to the given format specifier. If the format specifier is missing, the argument will be printed with its default format. For example:
write("The number {0} is greater than {1}.", 5.0, -3.0);
will print
The number 5 is greater than -3.
write("There are no format specifiers here.");
will print
There are no format specifiers here.

The format specifiers and their meanings are listed in the following table

Specifier Meaning Format Output for 1.62 Output for 2.0
none default {0} 1.62 2
c currency {0:c} $1.62 $2.00
e scientific {0:e} 1.620000e+000 2.000000e+000
f fixed point {0:f} 1.620000 2.000000
i round to int {0:i} 2 2

NOTE: an overview of the C++ ios flags is available at http://www.cplusplus.com/reference/ios/ios_base/fmtflags/
Limitations: You may limit the maximum number of arguments your function can process to a certain value, for example 10.
Suggested extensions:
add an optional alignment specification in the format , e.g., make the format of the form {index[,alignment][:specifier]}, where alignment is an integer specifying the width of the field in which the corresponding argument will be printed. If alignment is positive, align to the left, if it is negative, align to the right.
Accept an optional integer after the specifier letter, specifying the required precision in the output. For example, {0:f2} will print the number 1.6234 as 1.62, but {0:f5} will print it as 1.62340.

This is what I have done so far. The Default and Currency work fine, but Scientific does not print out as 50.000e+000, and fixed point does not print 50.0000, and Round to Int does not print at all.

#include <stdarg.h>
#include <string>
#include <iostream>
#include <stdarg.h>
#include <stdio.h>
#include <vector>
#include <cstdlib>
#include<iomanip>

using namespace std;

 void  write(int n, string edit...);

int main()
{
    //example string
    string edit = "There are {1} people in this city who make {0:c}";

      write(3,edit, 500000.0, 100.0);
    //write(1,"There are no format specifiers here.");

      write(2, "Default: {0}", 50.0);
      write(2, "Currency: {0:c}", 50.0);
      write(2, "Scientific: {0:e}", 50.0);
      write(2, "Fixed point: {0:f}", 50.0);
      write(2, "Round to int: {0:i}", 50.0);
    system("pause");

    return 0;
}

void write(int n,string edit...)

{
    vector<double> args;
    va_list vargs;
    va_start(vargs, n-1);

    vector<char> sepcifier;

    for (int i=0;i<n-1;i++)
    {
        double xarg = va_arg(vargs, double);
        args.push_back(xarg);
    }
    va_end(vargs);

    //vector to store what's in specifiers
   vector<string> inbraces;

   bool found =false;
   for (int i = 0; i < edit.length(); i++)
   {
       if (edit[i] == '{')
       {
           double t2 = edit.find("}");
          string str = edit.substr(i, t2 - i + 1);

       int x = str.find(":");
       int idx = str[1] -'0'  ;
       if(x ==-1){
        cout<<args[idx] << " ";
       }else{
           int len = str.length();
           string specifier =str.substr(x+1,1);
           if(specifier=="c")
           {
               cout<<"$"<<args[idx]<<" ";
           }else if(specifier=="e")
           {
               cout<<args[idx];

           }else if(specifier=="f")
           {

                int x = str.find(":");
                string specifier = str.substr(x+1,2);
                int digit = atoi(specifier.substr(x+2,1).c_str());
                cout<<fixed<<setprecision(digit)<<args[idx]<<" ";

           }else if(specifier=="i")
           {
                cout<<(int)args[idx]<<" ";

           }
       }

           edit.erase(i, t2 - i + 1);
           found  = true;
       }else{
           cout<<edit[i];
       }
   }

   if(!found){
       cout<<"There are no format specifiers here"<<endl;
   }else{
       cout<<endl;
   }

}

Recommended Answers

All 2 Replies

Try debugging this.

In Visual C++ (free ones out there) I can set breakpoints to see what vars are at that point.
If not, I add print statements to trace my code.

This looks like a class assignment. Haven't they covered beginner's debugging?

write(2, "Fixed point: {0:f}", 50.0);

You're trying to find the integer value between 'f' and '}', correct? In this case, there is none, so that value should be 0, correct?

write(2, "Fixed point: {0:f3}", 50.0);

And in this case it would be 3, correct?

If so, you seem to find the colon fine and the f fine, but your logic in lines 76 to 78 as far as isolating the digit(s) between the f and the end bracket is flawed. So if you can ASSUME (make sure you CAN assume, otherwise you need to code to check) that you'll either have a colon followed by f followed by an end bracket or a colon followed by f followed by a single digit followed by an end bracket, you've already found the colon, so you are looking to isolate the digit 2 places AFTER the colon (assuming it exists). If it doesn't exist, it's zero.

       else if(specifier=="f")
       {
            char charDigit = str[x+2]; // one character after the 'f'
            int digit = 0;
            if(isdigit(charDigit)) // if it's a digit overwrite 0 default
            {
                digit = atoi(str.substr(x+2,1).c_str());
            }
            cout<<fixed<<setprecision(digit)<<args[idx]<<" ";
       }
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.