Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.
int ReturnString(int , char);
int Finisher(int ChosenSave)
{ 
       char SaveFolder1[20]="./Data/Saves/Save1/";
       char SaveFolder2[20]="./Data/Saves/Save2/";
       char SaveFolder3[20]="./Data/Saves/Save3/";
       char SaveFolder4[20]="./Data/Saves/Save4/";
       ofstream MyFileOut;

       if(ChosenSave==1) FileOut.open(ReturnChar(1 , SaveFolder1));
  else if(ChosenSave==2) FileOut.open(ReturnChar(1 , SaveFolder2));
  else if(ChosenSave==3) FileOut.open(ReturnChar(1 , SaveFolder3));
  else if(ChosenSave==4) FileOut.open(ReturnChar(1 , SaveFolder4));
}

int ReturnChar(int x, char Folder[50])
{
    if (x==1)
        strcat(Folder , "MapTXT.txt");
    else if (x==2)
        strcat(Folder , "MapPNG.png");
    else if (x==3)
        strcat(Folder , "TreesRare.txt");
    else if (x==4)
        strcat(Folder , "TreesMedium.txt");
    else if (x==5)
        strcat(Folder , "TreesMany.txt");
    return Folder;
}

Working at a game which includes worlds and I must save different files to the selected save slot (folder) and I'm not sure how to Return my char back in the .open statement . I need to return the save route + the name of the file and type . As it's very obvious it doesn't work , please help ?

share|improve this question
1  
Programming questions not directly related to game development should be asked on stackoverflow.com –  Byte56 Jun 7 '13 at 14:01
add comment

closed as off topic by msell, Nicol Bolas, Byte56, Patrick Hughes, Josh Petrie Jun 7 '13 at 17:58

Questions on Game Development Stack Exchange are expected to relate to game development within the scope defined by the community. Consider editing the question or leaving comments for improvement if you believe the question can be reworded to fit within the scope. Read more about reopening questions here.If this question can be reworded to fit the rules in the help center, please edit the question.

4 Answers

up vote 1 down vote accepted

I agree with Liosan, however I will expand upon the reasons to use std::string over cstrings for clarity.

Why not to use c strings

The first, and most important, is that c strings take a large amount of cautious coding and double checking to ensure memory safe operations. Case in point in your code: each call to strcat should be checked before it is run to ensure that the buffer Folder is not overrun. ReturnChar has no idea what the contents of Folder are to start with, and it is assuming that is has enough space remaining in the buffer to fit whatever arbitrary file name you've selected. A better solution (if you HAD to use c strings) would be to use strncat rather than strcat, however this is not so simple as it sounds. The proper usage of this is something like:

char* FileNameLookup(int x){
    switch(x){
        case 1: return "MapTXT.txt";
        case 2: return "MapPNG.png";
        case 3: return "TreesRare.txt";
        case 4: return "TreesMedium.txt";
        case 5: return "TreesMany.txt";
        default: return "";
    }
}

char* SavePathCreation(int x, char saveLocation[SAVE_PATH_MAX_SIZE+1] ){
    char fileName[FILE_NAME_MAX_SIZE+1] = FileNameLookup(x);

    int fileNameLen = strlen( fileName );

    int spaceAvailableForFileName = SAVE_PATH_MAX_SIZE - fileNameLen ;

    if( path == null ){ 
/* THIS IS AN ERROR THAT WOULD NEED TO BE DEALT WITH  instead of continuing */
    }

    return strncat( saveLocation, fileName , spaceAvailableForFileName );

}

int Finisher(int ChosenSave){ 
    char SaveFolder1[20]="./Data/Saves/Save1/";
    char SaveFolder2[20]="./Data/Saves/Save2/";
    char SaveFolder3[20]="./Data/Saves/Save3/";
    char SaveFolder4[20]="./Data/Saves/Save4/";
    ofstream MyFileOut;

    if(ChosenSave==1) FileOut.open(SavePathCreation(1 , SaveFolder1));
    else if(ChosenSave==2) FileOut.open(SavePathCreation(1 , SaveFolder2));
    else if(ChosenSave==3) FileOut.open(SavePathCreation(1 , SaveFolder3));
    else if(ChosenSave==4) FileOut.open(SavePathCreation(1 , SaveFolder4));
    //This looks like it should return something? Not sure what your code is doing here
}

As you can see, there is actually more overhead than the simple one line call to strcat than you used to safely work with c strings. Not only that, FAR more dangerously this is prone to human error and is very difficult to read it's intentions properly. If you are using c strings instead of std::string for optimization, then I suggest you abandon this reasoning quickly as it is DEFINITELY premature optimization.

Now compare this to using std classes

An alternative using std::string

std::string FileNameLookup(int x){
    switch(x){
        case 1: return std::string( "MapTXT.txt" );
        case 2: return std::string( "MapPNG.png" );
        case 3: return std::string( "TreesRare.txt" );
        case 4: return std::string( "TreesMedium.txt" );
        case 5: return std::string( "TreesMany.txt" );
        default: return std::string( "" );
    }
}

int Finisher(int ChosenSave){ 
    std::string SaveFolder1 ( "./Data/Saves/Save1/" );
    std::string SaveFolder2 ( "./Data/Saves/Save2/" );
    std::string SaveFolder3 ( "./Data/Saves/Save3/" );
    std::string SaveFolder4 ( "./Data/Saves/Save4/" );
    std::string SaveFolders[] = { SaveFolder1, SaveFolder2, SaveFolder3, SaveFolder4 };
    std::string fileName = FileNameLookup(1);
    ofstream MyFileOut;

    if(ChosenSave>=1 && ChosenSave <= 4){
        /* 
         * Note that c_str is only guaranteed to be valid as long as the string 
         * is unmodified; This is safe, but it is a good caveat to remember.
         */
        FileOut.open( SaveFolders[ChosenSave].append(fileName)->c_str() );
    }
    else {
        //Handle invalid save location parameter here
    }
    //This looks like it should return something? Not sure what your code is doing here
}

Going EVEN further down the std rabbit hole (using Vectors)

We can even improve this a bit, but using a vector returned from a function to give further memory security AND future extensibility as vector sizes are flexible where as arrays are not. (Even better would be looking up said folder names in a configuration, so folders could be adjusted without recompiling the code).

std::string FileNameLookup(int x){
    switch(x){
        case 1: return std::string( "MapTXT.txt" );
        case 2: return std::string( "MapPNG.png" );
        case 3: return std::string( "TreesRare.txt" );
        case 4: return std::string( "TreesMedium.txt" );
        case 5: return std::string( "TreesMany.txt" );
        default: return std::string( "" );
    }
}

std::vector<std::string> GetSaveFolders(){

    std::vector<std::string> sf;

    //push folders onto vector
    sf.push( std::string( "./Data/Saves/Save1/" ) );
    sf.push( std::string( "./Data/Saves/Save2/" ) );
    sf.push( std::string( "./Data/Saves/Save3/" ) );
    sf.push( std::string( "./Data/Saves/Save4/" ) );

    return sf;

}

int Finisher(int ChosenSave){

    std::vector<std::string> saveFolders = GetSaveFolders();

    std::string fileName = FileNameLookup(1); //arbitrary file for this example

    ofstream MyFileOut;

    if(ChosenSave > 0 && ChosenSave <= saveFolders.size ){

        /*
         * append returns a pointer to the string appended to, which is a local
         * variable so no need to free the memory
         */
        std::string* path = SaveFolders.at(ChosenSave-1).append(fileName);

        /* 
         * Note: c_str is only guaranteed to be valid as long as the string 
         * is unmodified; This is safe, but it is a good caveat to remember.
         */
        FileOut.open( path->c_str() );
    }
    else {
        //Handle invalid save location parameter here
    }
    //This looks like it should return something? 
    //Not sure what your code was doing here
}
share|improve this answer
add comment

I'm not really sure on what you're trying to achieve here. You can't return a pointer to a string (char*) and cast it to an integer (you can but you shouldn't do it).

Instead, you should organize your whole saving in a different way (the following is pseudo code, you might have to replace or implement some of the functions based on your target system etc.):

char savepath[256]; // temporary string to store the file name
char oldpath[256]; // temporary string to store current working dir
const char pathtemplate[] = "./Data/Saves/Save%d/"; // save path template

// first create a string with the actual path to save to
snprintf(savepath, 255, pathtemplate, chosenSave);

// save the current working directory
storeWorkingDir(oldpath);

// change the working directory
changeWorkingDir(savepath);

// now open the actual file(s)
ofstream someFile("map.txt");

// restore the working directory
changeWorkingDir(oldpath);
share|improve this answer
add comment

I have no idea what you are doing, but I think it would be a lot easier if you used std::string. You can get it's c-string (const char*) using c_str().

share|improve this answer
add comment

Your ReturnChar function has its return type set to int when it seems you want to return char. And you probably want to return a char* at that.

share|improve this answer
add comment

Not the answer you're looking for? Browse other questions tagged or ask your own question.