C++
November 4, 2008 8:04 AM   Subscribe

How can a program output a variable number of files in C++?

For example, if a user enters 3, then 3 files would be created:

file1.txt
file2.txt
file3.txt

Can I do this without just having a bunch of if statements for each option the user could enter?
posted by londontomasbird to Computers & Internet (15 answers total) 1 user marked this as a favorite
 
With a for or while loop.

Read up on control flow.
posted by qxntpqbbbqxl at 8:11 AM on November 4, 2008


rather than using nested if statements you would want to use a loop.
posted by phil at 8:13 AM on November 4, 2008


Looks like we're missing a part of the puzzle here --- Why would you need a bunch of if statements to
do this? Like others said, you need some sort of loop.

Are you perhaps having trouble generating the filenames? In plain C you would use snprintf with your loop counter on a scratch variable for this:


char[12] filename;
FILE * file;

for(i=0;i<IMAX;i++){
snprintf(filename,12,"file%2d.txt",i);
file=fopen(filename, "w");
/* Do stuff with file ... */
}


Note that for a real-world program you have to make sure filename is long enough, and that snprintf won't overrun it, and that IMAX is not more than 99, and all sorts of other things, for which coding this kind of thing in C is a pain in the butt.
posted by ghost of a past number at 8:31 AM on November 4, 2008


AUGH! It's messed up again! The Live Preview LIED!

Sorry for all my spam. Just ignore me and look up for-loops
posted by nikkorizz at 8:33 AM on November 4, 2008


homework filter?
posted by jeffburdges at 8:58 AM on November 4, 2008 [1 favorite]


Response by poster: Ok, I wasn't sure if you could use this type of statement with file output:

(filename,12,"file%2d.txt",i)

like you can with printf.

And to answer ghost of a past number's question, I was thinking if statements would be used like this:

if (x == 2)
file1.txt;
file2.txt;

if (x == 3)
file1.txt;
file2.txt;
file3.txt;

Obviously, that doesn't do anything, but you get the idea.
posted by londontomasbird at 9:07 AM on November 4, 2008


In general, any time you think you need a set of if-statements like that, you're doing it wrong.

If you're doing a similar thing more than once, you should be looping.
posted by Netzapper at 9:59 AM on November 4, 2008


And to answer ghost of a past number's question, I was thinking if statements would be used like this:

Code like that usually ends up on thedailywtf, don't do that.
posted by cmonkey at 10:07 AM on November 4, 2008


I was thinking if statements would be used like this ...

That's definitely not a good way to do it. In the interest of demonstrating exactly why, I propose that this would be better:

switch(number_of_files)
{
case 99: create_file("file99.txt");
case 98: create_file("file98.txt");
case 97: create_file("file97.txt");
...
case 3: create_file("file03.txt");
case 2: create_file("file02.txt");
case 1: create_file("file01.txt");
break;
default:
printf("I can't handle that many files.\n");
}
posted by sfenders at 10:56 AM on November 4, 2008 [1 favorite]


You don't really want to use printf formatting, or anything else from the C example except for the 'for' loop.

You can use std::stringstream to put the file name together without worry of overflowing anything or having to set a maximum size on the input integer.
posted by moift at 11:05 AM on November 4, 2008 [1 favorite]


Unless this is a homework problem or an intellecual exercise, please don't do this in C++.

This is doable in a single line of code in a large handful of languages. Here's a ruby example:

ARGV[0].to_i.times {|time| File.new("./file#{time + 1}.txt", "w")}
posted by Caviar at 2:27 PM on November 4, 2008


Perl does it better. :P

utime($t=time,$t, map {"file$_.txt";} (1 .. 3) );
posted by jeffburdges at 3:08 PM on November 4, 2008 [1 favorite]


Use a for loop. The C++ standard library will give you robust input and output. As mentioned above, doing this in C is a royal pain in the ass. Here's an example of a program that will do what you want. The important parts are the for loop, which executes the code in braces num times, and the std::stringstream, which is used to construct the filename.
#include <iostream>#include <sstream>#include <fstream>#include <string>int main(void){  unsigned num;  std::cin >> num;  for (unsigned i = 1; i <= num; i++) {    std::stringstream ss;    ss << "file" << i << ".txt";    std::string filename;    ss >> filename;    std::ofstream file(filename.c_str());  }  return 0;}
Of course, this is really not something you want to be doing in C++. Using a more expressive language lets you do this in many fewer lines of code. For example, here's the exact same program in Haskell:
main = mapM_ (flip writeFile "" . Text.Printf.printf "file%d.txt") . enumFromTo 1 . read =<< getLine

posted by panic at 4:39 PM on November 4, 2008


I really don't want to get into a language argument, but the statement "Perl does it better" is factually incorrect.

The power of ruby in this example is in its simplicity in extension while maintaining readability. This example doesn't get much more complicated in ruby if you want to, say, put a default value into the files:

ARGV[0].to_i.times {|time| File.open("./file#{time + 1}.txt", "w") {|newfile| newfile.puts Time.now}}

ruby lends itself to elegance through simplicity, not just compact code.

However, without further input from the OP, we've hijacked this thread, and this will be my last comment on the topic.
posted by Caviar at 5:06 AM on November 5, 2008


I stand corrected, Haskell does it better, but Ruby meh. I really must start using Haskell more.
posted by jeffburdges at 8:04 AM on November 5, 2008


« Older Sticker me!   |   Redskins Lose, Obama wins... Newer »
This thread is closed to new comments.