Personal computing discussed

Moderators: renee, SecretSquirrel, just brew it!

 
Crayon Shin Chan
Minister of Gerbil Affairs
Topic Author
Posts: 2313
Joined: Fri Sep 06, 2002 11:14 am
Location: Malaysia
Contact:

Making a string from variables

Tue Mar 08, 2011 3:20 pm

So I want to write a C++ program to automate Avisynth script making given some filenames. Before you start pointing me to scripts, lemme just say I wanna practice my C++.

usage: ./program name episodestart episodeend files

1. The program assumes that the shell will provide a sorted list of files when a wildcard is used, for instance *.mkv. Is this a reasonable assumption?

2. The output should look like name-episodecount.avs. I had the bright idea to use C++, so luckily I get the convenience of C++ string classes. However, I can't figure out how to format the string - it isn't any of the following:
string filename(&argv[1],"-",&epc,".avs");
string filename(argv[1]<<"-"<<epc<<".avs");

And I can't find any help on how to put variables in a string. Help please?
Mothership: FX-8350, 12GB DDR3, M5A99X EVO, MSI GTX 1070 Sea Hawk, Crucial MX500 500GB
Supply ship: [email protected], 12GB DDR3, M4A88TD-V EVO/USB3
Corsair: Thinkpad X230
 
Madman
Minister of Gerbil Affairs
Posts: 2317
Joined: Tue Apr 01, 2003 4:55 am
Location: Latvia

Re: Making a string from variables

Tue Mar 08, 2011 6:43 pm

Use stringstream - http://www.cplusplus.com/reference/iost ... ingstream/

Regular strings don't like formatted input/output much.

ostringstream output;
output<<"something<<nInteger<<"something else<<fFloat<<".bat"<<endl;
string result = output.str();

const char *aaa = result.c_str()
Core 2 Duo E6300, MSI P45 NEO-F, Club 3D GTX 260, 4Gb DDR2-800Mhz, Audigy X-Fi Fatal1ty Champ1on ed., 0.5Tb+1Tb Seagate Barracuda 7200.12, 630W AXP, Samsung SyncMaster BX2450, ViewSonic VP171b
 
just brew it!
Administrator
Posts: 54500
Joined: Tue Aug 20, 2002 10:51 pm
Location: Somewhere, having a beer

Re: Making a string from variables

Tue Mar 08, 2011 6:54 pm

1. Assuming that the shell will give you a sorted list of names is reasonable if this will only be executed on *NIX platforms. On Windows it is the app's responsibility to expand wildcards.

2. My personal preference for stuff like this would actually be Python. C/C++ has always been a bit clunky for string manipulation. Madman's approach will get the job done, but the C++ stream I/O model is rather brain-dead. I actually drop back to C idiom and use sprintf/snprintf/vsprintf/vsnprintf whenever I need to do stuff like that in C++, just because I find the C++ stream libraries so utterly detestable.
Nostalgia isn't what it used to be.
 
Flying Fox
Gerbil God
Posts: 25690
Joined: Mon May 24, 2004 2:19 am
Contact:

Re: Making a string from variables

Tue Mar 08, 2011 7:56 pm

just brew it! wrote:
2. My personal preference for stuff like this would actually be Python. C/C++ has always been a bit clunky for string manipulation. Madman's approach will get the job done, but the C++ stream I/O model is rather brain-dead. I actually drop back to C idiom and use sprintf/snprintf/vsprintf/vsnprintf whenever I need to do stuff like that in C++, just because I find the C++ stream libraries so utterly detestable.

They are actually not that bad. The problem now with the printf-family is that you have to pretty much know the buffer size ahead of time and if you don't, you are looking at potential buffer-overflow situations. The idea of the stream library is pretty good is that I think they do smarter buffer reallocation if the text you are appending is going to exceed the buffer. Also assuming proper C++ exception handling in place, you don't have to use the older style check error code business and you get the nicer std::exception getting thrown if something happens. Moreover, type conversion IMO is better handled with overloaded operator<<() than remembering esoteric %d, %l, %f, etc.

That said, if you are dumb enough to do this I will smack you in the head:
string s = "aa";
s += "'bb";
s += "cc";

Like Madman said, use stringstream in this case and at the end use stringstream::str().

Of course, for even better power string formatting, there's boost::format. ;)

OP: your code really shows some misunderstanding about C++ strings. "abc" is a char array not string, that is why there is no operator<< to do that.
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
 
just brew it!
Administrator
Posts: 54500
Joined: Tue Aug 20, 2002 10:51 pm
Location: Somewhere, having a beer

Re: Making a string from variables

Wed Mar 09, 2011 1:35 pm

Flying Fox wrote:
just brew it! wrote:
2. My personal preference for stuff like this would actually be Python. C/C++ has always been a bit clunky for string manipulation. Madman's approach will get the job done, but the C++ stream I/O model is rather brain-dead. I actually drop back to C idiom and use sprintf/snprintf/vsprintf/vsnprintf whenever I need to do stuff like that in C++, just because I find the C++ stream libraries so utterly detestable.

They are actually not that bad.

We will have to agree to disagree then. The problem with the C++ stream library is that the format of the output is determined by hidden persistent state. You have to either A) set all of the formatting options every time you want to write something; or B) assume that all other code writing to the stream plays nice and saves/restores the formatting state. This is a glaring design flaw IMO.

The problem now with the printf-family is that you have to pretty much know the buffer size ahead of time and if you don't, you are looking at potential buffer-overflow situations.

Yes, you do need to know the buffer size ahead of time; but you need not be inviting buffer overflows. All modern runtime libraries support the 'n' variants (snprintf, etc.), which allow the buffer size to be explicitly passed in. Is this a perfect solution? No. But it is less painful than using the stream libraries.

The idea of the stream library is pretty good is that I think they do smarter buffer reallocation if the text you are appending is going to exceed the buffer. Also assuming proper C++ exception handling in place, you don't have to use the older style check error code business and you get the nicer std::exception getting thrown if something happens.

Or just use Python... :wink:

Moreover, type conversion IMO is better handled with overloaded operator<<() than remembering esoteric %d, %l, %f, etc.

Heh... don't get me started. IMO the entire concept of using an overloaded << operator for formatted output falls into the category of gratuitous and overly clever use of operator overloading. This brain-dead design decision is also what forces us down the path of needing to maintain hidden format control state -- you can't pass additional optional arguments to an operator overload like you can to a member function.

It is almost as if the designers of the standard C++ I/O library said "Hey, hold my beer and watch this!"
Nostalgia isn't what it used to be.
 
Crayon Shin Chan
Minister of Gerbil Affairs
Topic Author
Posts: 2313
Joined: Fri Sep 06, 2002 11:14 am
Location: Malaysia
Contact:

Re: Making a string from variables

Thu Mar 10, 2011 9:38 am

Question: c_str() converts from a C++ string object to a C string (an array of chars, I heard)? Why is that needed? Why should I even take the time to convert it to back to a character array (const char *aaa as Madman said)?
It seems the arguments are provided as arrays of strings. Why do you call them arrays of chars, because if they are arrays of chars (which are C strings right) then each increment of the index should point to a different letter of the arguments?
How do I convert from argv[1] to a string?
Mothership: FX-8350, 12GB DDR3, M5A99X EVO, MSI GTX 1070 Sea Hawk, Crucial MX500 500GB
Supply ship: [email protected], 12GB DDR3, M4A88TD-V EVO/USB3
Corsair: Thinkpad X230
 
Flying Fox
Gerbil God
Posts: 25690
Joined: Mon May 24, 2004 2:19 am
Contact:

Re: Making a string from variables

Thu Mar 10, 2011 12:17 pm

Crayon Shin Chan wrote:
Question: c_str() converts from a C++ string object to a C string (an array of chars, I heard)? Why is that needed?
As I said, char* or char[] in C is just a pointer to a contiguous block of memory, not a real C++ object. std::string is an object. A lot of people who grew up on Java/C#/etc often miss this. Grab a good C book and really understand pointers please (definitely not going to recommend K&R, but "C Primer Plus" is good). So using .c_str() returns a const pointer (don't mess with it!) where you can pass in to functions that take const char*.

Crayon Shin Chan wrote:
Why should I even take the time to convert it to back to a character array (const char *aaa as Madman said)?
I think he was just illustrating. When doing mixed C/C++, try to stay with C++ strings/stringstream until the last possible moment to do c_str(). If you don't need to pass into some C function then no need.

Crayon Shin Chan wrote:
It seems the arguments are provided as arrays of strings. Why do you call them arrays of chars, because if they are arrays of chars (which are C strings right) then each increment of the index should point to a different letter of the arguments?
Again, char*/char[] != string objects. argv is actually an array of char pointers, which in theory each member can be pointing to different blocks of memory containing the arrays of characters all over your process space.

Crayon Shin Chan wrote:
How do I convert from argv[1] to a string?
Either you use good old fashion s[n]printf (or s[n]printf_s on Windows with VC++) then you can stay with char*, or if you are going to use C++/Boost's real string functions, that is easy to do:
std::string s(argv[1]);
This constructs a new string object (separate storage in memory). In the general case of course you have to be careful of the implications of that memory allocation.

Re: printf vs iostream - These days I don't do much of that because of localization. It is almost either FormatMessage or boost::format. Of course for some quick internal concat and stuff I'm actually all for stringstream (strcat/strncat is now falling out of favour due to those now infamous overflows).
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
 
cphite
Graphmaster Gerbil
Posts: 1202
Joined: Thu Apr 29, 2010 9:28 am

Re: Making a string from variables

Thu Mar 10, 2011 12:49 pm

Crayon Shin Chan wrote:
Question: c_str() converts from a C++ string object to a C string (an array of chars, I heard)? Why is that needed? Why should I even take the time to convert it to back to a character array (const char *aaa as Madman said)?
It seems the arguments are provided as arrays of strings. Why do you call them arrays of chars, because if they are arrays of chars (which are C strings right) then each increment of the index should point to a different letter of the arguments?
How do I convert from argv[1] to a string?


Technically they're arrays of pointers. Frankly, without a solid understanding of pointers, C++ is a waste of time and energy. I'd suggest getting a good book - C++ Primer by Stan Lippman is a great place to start.
 
Flying Fox
Gerbil God
Posts: 25690
Joined: Mon May 24, 2004 2:19 am
Contact:

Re: Making a string from variables

Thu Mar 10, 2011 12:51 pm

cphite wrote:
I'd suggest getting a good book - C++ Primer by Stan Lippman is a great place to start.
I have not read the latest edition. How good is the chapter on pointers? Or one should go read C Primer instead?
The Model M is not for the faint of heart. You either like them or hate them.

Gerbils unite! Fold for UnitedGerbilNation, team 2630.
 
Crayon Shin Chan
Minister of Gerbil Affairs
Topic Author
Posts: 2313
Joined: Fri Sep 06, 2002 11:14 am
Location: Malaysia
Contact:

Re: Making a string from variables

Tue Mar 15, 2011 8:02 am

Phew thanks guys. I've finally managed to get to this stage. Now to assign the mkv filenames to each of the avs and write actual text into the avs files.
shinichi@translator2 ~/source/project $ ./a.out bleach 01 35 *.mkv
9
bleach-01.avs
bleach-02.avs
bleach-03.avs
bleach-04.avs
bleach-05.avs
bleach-06.avs
bleach-07.avs
bleach-08.avs
bleach-09.avs
bleach-10.avs
bleach-11.avs
bleach-12.avs
bleach-13.avs
bleach-14.avs
bleach-15.avs
bleach-16.avs
bleach-17.avs
bleach-18.avs
bleach-19.avs
bleach-20.avs
bleach-21.avs
bleach-22.avs
bleach-23.avs
bleach-24.avs
bleach-25.avs
bleach-26.avs
bleach-27.avs
bleach-28.avs
bleach-29.avs
bleach-30.avs
bleach-31.avs
bleach-32.avs
bleach-33.avs
bleach-34.avs
bleach-35.avs


The source is:
#include <fstream>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <iomanip>
using namespace std;

int main ( int argc, char *argv[] )
{
        cout << argc << endl;
        if (argc==1){cout<<"usage: "<< argv[0] << " name episodestart episodeend files" <<endl;}
        int epstart=atoi(argv[2]);
        int epend=atoi(argv[3]);
        int epcount=epstart;
        ostringstream output;
        for(int i=epcount;epcount<=epend;epcount++){
                output<<argv[1]<<"-"<<setw(2)<<setfill('0')<<epcount<<".avs";
                cout<<output.str()<<endl;
                output.clear();output.str("");
        }
        return 0;
}



Criticism? Any object oriented way of doing this? I'm aware that my code always looks very procedural, i.e. C-like. Not that there's a problem with that, but maybe it would be nice to jump on this OO bandwagon.
Mothership: FX-8350, 12GB DDR3, M5A99X EVO, MSI GTX 1070 Sea Hawk, Crucial MX500 500GB
Supply ship: [email protected], 12GB DDR3, M4A88TD-V EVO/USB3
Corsair: Thinkpad X230
 
Crayon Shin Chan
Minister of Gerbil Affairs
Topic Author
Posts: 2313
Joined: Fri Sep 06, 2002 11:14 am
Location: Malaysia
Contact:

Re: Making a string from variables

Thu Mar 17, 2011 8:38 am

fstream refuses to do this:
ofstream contents;
contents.open(filename.str()); //obviously open("filename.str()"); doesn't work either
contents << "DirectShowSource(\"....

Also, I tried making the actual part that puts in the values into the text file a separate function, but I had real trouble passing my string/ostringstream objects into this function. Is it really necessary to convert an ostringstream into a string just so I can use string's c_str() function to pass it into a function?
Mothership: FX-8350, 12GB DDR3, M5A99X EVO, MSI GTX 1070 Sea Hawk, Crucial MX500 500GB
Supply ship: [email protected], 12GB DDR3, M4A88TD-V EVO/USB3
Corsair: Thinkpad X230
 
bitvector
Grand Gerbil Poohbah
Posts: 3293
Joined: Wed Jun 22, 2005 4:39 pm
Location: San Francisco, CA

Re: Making a string from variables

Sat Apr 09, 2011 8:22 pm

just brew it! wrote:
I actually drop back to C idiom and use sprintf/snprintf/vsprintf/vsnprintf whenever I need to do stuff like that in C++, just because I find the C++ stream libraries so utterly detestable.

You'd probably appreciate the Google C++ string-printf utility functions (this post is a bit late because I didn't realize that implementations were publicly available in Chrome until now). See stringprintf.h/cc and stringprintf_unittest.cc in Chromium's base library:
http://src.chromium.org/svn/trunk/src/base/

There's StringPrintf (returns a new string), SStringPrintf (takes a pointer to the destination string as first argument), and StringAppendF. Since they just wrap sprintf, the behavior is the same, so they're super convenient. The only wart IMO is that passing actual C++ strings requires adding .c_str() to each one since printf style functions use C variadic functions (va_list and so forth) and C++ objects don't play nice with that (the C++ standard says that things passed in as va_arg must be POD -- plain old data -- which any non-trivial class is not). Still, on balance, I find it to be very convenient, especially since it's identical to sprintf and doesn't require you to add an entire new formatting library dependency to your project.

Who is online

Users browsing this forum: No registered users and 1 guest
GZIP: On