C++ School Assignment? Project Due Tomorrow? Chat LIVE With A Programming Expert!

Welcome to Dream.In.Code
Become a C++ Expert!

Join 300,503 C++ Programmers for FREE! Get instant access to thousands of C++ experts, tutorials, code snippets, and more! There are 1,894 people online right now. Registration is fast and FREE... Join Now!




Accepting an unspecified number of arguments to a function

 
Reply to this topicStart new topic

> Accepting an unspecified number of arguments to a function, Making a printf() like function

gabehabe
Group Icon



post 7 Sep, 2008 - 07:10 AM
Post #1


Creating a function which accepts an unspecified number of arguments
Using va_list, va_arg, va_start and va_end

What should I know before following this tutorial?
You should have at least a basic knowledge of stringstreams. Other than that, you only really need to know the basics.

So what will I get out of this tutorial?
This tutorial is going to explain how you can pass an undefined number of arguments to a function. The code from this tutorial is going to be a basic version of sprintf, which is used to format a string, using tokens %s and %d. Sound fun? Read on!

So, all programs start with the header files that should be included. We're going to be using cstdarg, string, iostream, and sstream. yeah, I know, quite a few. Don't worry though, they're really only for the example. To include those va macros, you need to include cstdarg.

Let's start:
cpp
#include <cstdarg>   // for the macros va_list, va_arg, va_start and va_end
#include <iostream> // standard input/output stream
#include <string> // string data type
#include <sstream> // string stream

using namespace std;


So now we can get started on writing our function. Let's call it MYsprintf, since it will have a similar effect to that of sprintf()
cpp
string MYsprintf (const char *str, ...)
{

Let's go over what's going to be passed to the function. We have const char *str which is basically the main string. Think of that of printf, it takes a string first, right? Same applies here.

After that, we have ... to which I guess your reaction is a little like this:
IPB Image

No worries, it basically means that we're going to be accepting more arguments, but we don't know what they are yet. smile.gif

Now, the first thing we want to do is create a va_list which is basically a list of arguments. It will store all those additional arguments that were passed to MYsprintf. We're also going to want to initialise that, using va_start() like so:
cpp
    va_list args;
va_start(args, str);

Next, I'm just going to create an ostringstream so that we can add everything to a string.
cpp
    ostringstream output;


The next thing that we need to do is loop through str Nothing new here (or it shouldn't be) we just loop, like so:
cpp
    for (unsigned int i = 0; i < strlen(str); i++)
{

Now, as we loop through str we just need to format it. A little pseudocode:
CODE
if the current character is % and the following character is d or s
{
    add it to the output stream
    increment the counter to avoid adding % to the output string
}
else add the current character to the output string stream
Let's have a look at the code for the if statement:
cpp
        if (str[i] == '%' && str[i+1] != '%' && i+1 < strlen(str)) // we need to format it
{
making sense so far? I hope so! Basically, we're making sure i+1 is still in the scope of str, and making sure that the character after '%' is not '%' (in which case, there's nothing to format)
Now, since we only accept s and d as parameters (string or int) we're gonna need a switch, too.
Let's take a look at the cases:
cpp
            switch (str[i+1]) // switch the next character
{
case 's':
char *temp = va_arg (args, char*);
output << temp;
break;
case 'd':
int Temp = va_arg (args, int);
output << Temp;
break;
default:
output << str[i];
} // end switch
i++; // increment to avoid outputting the next character
} // end if

Pretty simple, the only new thing there should be va_arg()
Basically, we add our temporary value to args (our va_list) and then add it to the output string stream. The reason that we add it to args is to make sure that all arguments are accounted for by the end of the function.

After that, it's our else statement, and then the end of the function! So we're nearly there! smile.gif
cpp
        else output << str[i];
} // end for

Now all we need to do is clear up args, return the string, and exit the function, like so:
cpp
    va_end(args);
return output.str();
} // end MYsprintf

And there we have it! Let's take a quick look at the implementation of MYsprintf:
cpp
int main ()
{
string myStr = MYsprintf ("%s is %d years old. %s", "gabehabe", 18, "(happy.gif)\"");
cout << myStr; // output the string

cin.get (); // hold the window open
return EXIT_SUCCESS; // successful execution
}


And here's the whole code:
cpp
#include <cstdarg>   // for the macros va_list, va_start and va_end
#include <iostream> // standard input/output stream
#include <string> // string data type
#include <sstream> // string stream

using namespace std;

string MYsprintf (const char *str, ...)
{
va_list args;
va_start(args, str);
ostringstream output;
for (unsigned int i = 0; i < strlen(str); i++)
{
if (str[i] == '%' && str[i+1] != '%' && i+1 < strlen(str)) // we need to format it
{
switch (str[i+1]) // switch the next character
{
case 's':
char *temp = va_arg (args, char*);
output << temp;
break;
case 'd':
int Temp = va_arg (args, int);
output << Temp;
break;
default:
output << str[i];
} // end switch
i++; // increment to avoid outputting the next character
} // end if
else output << str[i];
} // end for
va_end(args);
return output.str();
} // end MYsprintf

int main ()
{
string myStr = MYsprintf ("%s is %d years old. %s", "gabehabe", 18, "(whatsthat.gif.)\"");
cout << myStr; // output the string

cin.get (); // hold the window open
return EXIT_SUCCESS; // successful execution
}
Go to the top of the page
+Quote Post


Register to Make This Ad Go Away!

NickDMax
Group Icon



post 9 Sep, 2008 - 06:12 AM
Post #2
I think you got some smiles in your code. You have to be careful of that when using the syntax coloring.

Though to be honest the syntax coloring is wrong. In C/C++ "// " is valid and not a open quotes followed by an end of line comment.

I would like to point out my own snippet to you (Centered Printf) -- The vsprintf() function can be of value when trying to create your own member of the printf family. Of course to use it you need to be familiar with va_list, va_arg, va_start, and va_end.
Go to the top of the page
+Quote Post


Reply to this topicStart new topic
1 User(s) are reading this topic (1 Guests and 0 Anonymous Users)
0 Members:

 


Lo-Fi Version Time is now: 11/8/09 05:04AM

Live C++ Help!

Be Social

Dream.In.Code RSS Feed Dream.In.Code LinkedIn Group Follow Us On Twitter Fan Us On Facebook

C++ Tutorials

Reference Sheets

C++ Snippets

DIC Chatroom

Bye Bye Ads

Monthly Drawing

Thumb Drive

Top Contributors

Top 10 Kudos This Month