0

I am using VisualStudio 2013, I am having some trouble on the following code for my c++ class. I just can' t seem to figure out what to do next. I am trying to create a function that will format a string. It will take a string like this

write("The number {0} is smaller than {1}", -3, 8);

And have it output it formatted correctly. The arguments will always be doubles. So it would output to console like this:

The number -3 is smaller than 8.

My problem is I guess I don't understand the variable arguments enough or I am just doing something wrong in the code below. Everytime I try to set something like

userString[i] = var_arg(userString, arguments);

I get like an overflow error. Any guidance would be greatly appreciated.

#include <iostream>
#include <string>
#include <cstdarg>

using namespace std;
//Prototype
string write(string userString...);

void main()
{
    write("This is {0} a string.{1}", 5);
    system("pause");
}
string write(string userString...)
{
    char target1 = '{';
    char target2 = '}';

    va_list arguments;

    va_start(arguments, userString);
    for (int i = 0; i < userString.size(); ++i)
    {
        if (userString[i] == target1 & userString[i + 2] == target2)
        {
        //Need help here...



        }
    }
    va_end(arguments);
    return userString;
}
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
  • 2
    If you need this functionality (and this isn't a personal exercise in coding) you're pretty much inventing [`boost::format`](http://www.boost.org/doc/libs/1_57_0/libs/format/doc/format.html). – Drew Dormann Apr 03 '15 at 14:16
  • 1
    Have you seen: http://stackoverflow.com/questions/1657883/variable-number-of-arguments-in-c – W.F. Apr 03 '15 at 14:16
  • 1
    Your code has undefined behavior because `userString` is not a type that results from the default argument promotions. – David G Apr 03 '15 at 14:18
  • 1
    It will help this question if you include whether you're using C++03, C++11, etc. – Drew Dormann Apr 03 '15 at 14:25
  • @DrewDormann Unfortunately, I do not now which version I have. I am using VisualStudio 2013 if that helps. Also, this is an exercise for my c++ class. I just can' t seem to figure out what to do next. Thanks. – VashTheStampede Apr 03 '15 at 14:49
  • Usage example here http://www.cplusplus.com/reference/cstdarg/va_start/. I think you will struggle with your idea as you don't indicate types in your format string like printf does. This ain't c# or Python. Unless you are assuming the arguments are always int? – Paul Rooney Apr 03 '15 at 15:59
  • The arguments will always be doubles if that changes anything. – VashTheStampede Apr 03 '15 at 16:12
  • 1
    When using `var_arg` the arguments are the `val_list` and the type (tells compiler how many bytes to read). So you'd use `double val=va_arg(arguments,double);` Then write that to the string. – Paul Rooney Apr 03 '15 at 16:44
  • 2
    @user2610654: The arguments in your samples are _not_ doubles, which is a huge part of the problem. – Mooing Duck Apr 03 '15 at 17:38
  • @user2610654: This is pretty complex stuff for a class. Are you _certain_ that's the string format you're supposed to use, and not a [printf format string](http://en.wikipedia.org/wiki/Printf_format_string)? Can it be a template? Are you certain it has to be one variadic function and not a series of overloads? Actually, the overload idea is a good one, that could be done by a novice for a class... – Mooing Duck Apr 03 '15 at 18:13
  • @MooingDuck Yeah that is the example string. There is also a second part to it as well. He did not mention using a template. I am just having trouble importing the string in the correct way. – VashTheStampede Apr 03 '15 at 19:48
  • [`main.cpp:9:1: error: 'main' must return 'int'`](http://coliru.stacked-crooked.com/a/783b8208e0eb26df), – Mooing Duck Apr 03 '15 at 19:51
  • Are the parameters guaranteed to always be in order with no duplicates? (`{0} fdsaf {1} dsaa{2} {3} asssd@{4}`) If not, this is a _really complex_ assignment that requires a fair bit of code. – Mooing Duck Apr 03 '15 at 19:53
  • They will always numbers of type double. the function should be able to handle any double in any order. This problem is worth like 10% of my grade by itself. It is a real mind bender. – VashTheStampede Apr 03 '15 at 20:39

1 Answers1

0

Here is something that works for your given inputs. It is neither optimal nor bulletproof in terms of error handling. A badly formatted string could probably cause it to crash, but it should demonstrate the principle.

#include <cstdarg>

#include <string>
#include <iostream>
#include <sstream>

using namespace std;

string write(string userString, ...)
{
    ostringstream ss;
    string::iterator it;

    char target1 = '{';
    char target2 = '}';

    va_list arguments;    
    va_start(arguments, userString);

    for (it = userString.begin(); it < userString.end(); ++it)
    {
        if ((*it == target1) & (*(it + 2) == target2))
        {
            double val=va_arg(arguments,double);
            ss << val;
            it += 2;  // remember its incremented by the loop aswell
        } else
        {
            ss << *it;
        }
    }

    va_end(arguments);
    return ss.str();
}

int main()
{
    cout << write("This is {0} a string. {1}", 5.0, -1.9) << '\n';
}
Paul Rooney
  • 20,879
  • 9
  • 40
  • 61
  • 1
    A simple template wrapper can remove the crash-prone-ness: http://coliru.stacked-crooked.com/a/fc2a9505a3a0a4bc – Mooing Duck Apr 03 '15 at 17:42
  • [`main.cpp:18:25: warning: 'va_start' has undefined behavior with reference types [-Wvarargs]`](http://coliru.stacked-crooked.com/a/295897c80f1c740c) – Mooing Duck Apr 03 '15 at 17:44
  • You're right. All the more reason to avoid va_start etc. with c++ http://stackoverflow.com/questions/222195/are-there-gotchas-using-varargs-with-reference-parameters. – Paul Rooney Apr 03 '15 at 17:52
  • Is it possible to find a length of the argument being passed to va_arg? So if the user enters 500 or 5000 I can have the length to format the string correctly? – VashTheStampede Apr 03 '15 at 19:45
  • 1
    @PaulRooney: Your answer assumes that all the numbered parameters are unique and in order. Not sure if that's an issue, but I would guess it is. – Mooing Duck Apr 03 '15 at 19:54
  • It there a way I can access a certain index of the the variable argument. Because you are right Mooing Duck. It may be in any order. – VashTheStampede Apr 03 '15 at 20:41
  • It makes plenty of assumptions and that is certainly one of them. It's certainly not a comprehensive String.Format function that would be tough to write. @user2610654 I don't think you can tell how arguments are passed, without using a sentinel value which is weak. – Paul Rooney Apr 03 '15 at 21:04