In the project I created a folder "levels" and put a file with a map there, and if you set the full path, then everything works.

ifstream level; level.open("/users/Stolz/git/Roguelike/levels/level" + to_string(aLevelNumber) + ".map"); 

But if you specify the path as "levels/level" + to_string(aLevelNumber) + ".map" then he no longer sees the file, how can I fix this?

  • one
    (1) What is your current directory? (2) And what is your current directory if the user starts your program from the root directory? - VladD
  • I suspect that the program is launched not from the project directory, but from some subdirectory of the type ./Release , ./Debug etc - PinkTux
  • @VladD current Roguelike directory, it contains all executable files - Nicholas Goncharov
  • 2
    @NicholasGoncharov, you need to look at what lies in argv[0] (and what getcwd() will say) - PinkTux

2 answers 2

There are several ways to set a "starting point", i.e. the table of contents, knowing that we can calculate all the paths we need to the configuration files, etc.

This may be the environment variable, the home directory of the user who launched the program, and the directory in which the executable code is located.

When the system starts, the first argument passes to the program its name, as entered by the user in the shell (or what the programmer indicated when calling it through exec ).

If the name of the program being started does not contain an absolute or relative (relative to the current (where its name is typed from) directory) path, then the system looks for a directory with the program code in the PATH environment variable, where the symbols : listed through the symbol :

Using this knowledge, you can easily write a couple of functions that, after getting the name from the command line parameter, return the directory in which the program is running.

 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <limits.h> #include <unistd.h> char * srcpath (const char *pgm) { char *path = getenv("PATH"), dir[PATH_MAX], *p; if (path) for (p = path; *p; *p ? p++ : p) { char *t = dir, *e = dir + PATH_MAX - 1; while (*p && *p != ':' && t < e) *t++ = *p++; if (snprintf(t, e - t, "/%s", pgm) < e - t && access(dir, R_OK | X_OK) == 0) return strndup(dir, t - dir); } return 0; } char * srcdir (const char *av0) { const char *pgm = strrchr(av0, '/'); return pgm ? strndup(av0, pgm - av0) : srcpath(av0); } int main (int ac, char *av[]) { char *dir; for (; *av; av++) { printf("%s : %s\n", av[0], dir = srcdir(av[0])); free(dir); } return puts("End") == EOF; } 

At least in Linux (starting from 2.2) in the / proc directory for each process there is a file (actually a symbolic link) /proc/[pid]/exe containing the full path to the executable file.

Let's write a similar function that extracts the directory from /proc :

 char * linux_srcdir () { char buf[PATH_MAX]; int n = readlink("/proc/self/exe", buf, PATH_MAX); return n > 0 ? buf[n] = 0, strndup(buf, strrchr(buf, '/') - buf) : 0; } 

    The most oak variant is from argv[0] (passed to main ) the path to your executable file, cut everything from the end to the left slash in it, then paste the path to the desired subdirectory there.

    Ways to get the path to the executable file - a huge amount .

    A good way to find a slash :

     #include <iostream> #include <cassert> using std::string; using std::cout; using std::endl; int main(int argc,char* argv[]) { assert(argc>0); static constexpr char levels_dir[]="levels"; static constexpr char slashes[]="/\\"; const string bin_path(argv[0]); const auto slash_position = bin_path.find_last_of(slashes); assert(slash_position!=string::npos); const auto levels_path = bin_path.substr(0,slash_position+1) + levels_dir + bin_path[slash_position]; cout << "Bin path: " << bin_path << endl << "Levels_path: " << levels_path << endl; return 0; } 

    Cross-platform option - works with both forward and backslash.

    IDEONE

    • argv [0] does not necessarily contain a working directory - Vladimir Gamalyan
    • @VladimirGamalian we don’t need the working directory for free, we need the one in which the binary is. Since it is obvious that the levels of toys should lie next to the binary. - gbg
    • argv [0] doesn't necessarily show the binary directory - Vladimir Gamalyan
    • @Vladimir Gamalian if this is some kind of crazy UNIX, there may be garbage there, I agree. - gbg
    • one
      You have assert on the number of arguments, why not put it on slash_position != string::npos (even if it’s an oak version). - Vladimir Gamalyan