6

I read through some topic about relative path, but i still got i wrong. I hope sb can help me :). I am using Visual studio 2013, windows 7

I got the following directories:

Here is my .exe file D:\uni\c++\ex5\msvc2013\ex5\Debug

Here is the file i want to read D:\uni\c++\ex5\res\thehead.raw

The code for opening the file:

FILE* f;
f = fopen("..\\..\\..\\res\\thehead.raw", "rb");
if (f == NULL)
printf("FAIL!!");

As i need to use relative paths i figured it out as following: ..\ gets to parent directory.

so "..\..\..\" should get me into the folder "D:\uni\c++\ex5\".

\res should open the res foulder.

Needless to say it fails and i have no idea why. Any help would be appreciated.

Jerry YY Rain
  • 4,134
  • 7
  • 35
  • 52
Käptn Freiversuch
  • 258
  • 1
  • 3
  • 14
  • 1
    Where your program launches and what your starting working directory are are not necessarily the same things. – Joe Jul 06 '14 at 14:45
  • Look up the term "current working directory". Relative paths are relative to this directory. – n. m. could be an AI Jul 06 '14 at 14:49
  • thx, im looking that up. it does not crash. f is just NULL so it prints "FAIL". – Käptn Freiversuch Jul 06 '14 at 14:50
  • [**@Käptn Freiversuch**](http://stackoverflow.com/users/1700016/k%c3%a4ptn-freiversuch) Note, you're sailing tough seas here ;) ... – πάντα ῥεῖ Jul 06 '14 at 14:50
  • 1
    It may help to print the value of [`errno`](http://en.cppreference.com/w/c/error/errno), using [`strerror`](http://en.cppreference.com/w/c/string/byte/strerror). Although `fopen` is not required to set `errno`, many implementations will do so. – NicholasM Jul 06 '14 at 14:52
  • Thx, i did that. the output is: Can't open "..\..\..\res\thehead.raw": No error – Käptn Freiversuch Jul 06 '14 at 14:58
  • @NicholasM Care to provide a reference for `fopen` not being required to set `errno`? How is a correct program to report the error? – user4815162342 Jul 06 '14 at 15:00
  • 1
    @KäptnFreiversuch Try printing the current working directory: http://stackoverflow.com/questions/143174/how-do-i-get-the-directory-that-a-program-is-running-from – NicholasM Jul 06 '14 at 15:03
  • @user4815162342 For the C function fopen, see section 7.21.5.3 of the [C11 Draft Standard (large PDF)](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf): "If the open operation fails, fopen returns a null pointer." – NicholasM Jul 06 '14 at 15:06
  • Yes i knew, that if it fails fopen returns a nullpointer. using _fullpath(NULL,path,40) i found my mistake, as i was going one directory too high – Käptn Freiversuch Jul 06 '14 at 15:08
  • @NicholasM Technically C++ (at least C++11) references the C99 standard. – Alan Stokes Jul 06 '14 at 15:10
  • @AlanStokes Good point. I should have referred to the [C99 Standard](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf), which contains the same statement in 7.19.5.3. – NicholasM Jul 06 '14 at 15:14

2 Answers2

7

Relative paths are relative to the current working directory, not the path of the executable. The current working directory is the directory from which you started the program.

To treat a path as relative to the position of the executable, the simplest portable option is to access the executable as argv[0], extract the directory, and chdir() into it. Note that this will work only as long as the program was itself started with the full path name.

user4815162342
  • 141,790
  • 18
  • 296
  • 355
  • 1
    Under Windows it's common to use `GetModuleFilename`, passing 0 for `hModule`, since `argv[0]` may not be right under various circumstances. – Alan Stokes Jul 06 '14 at 15:07
  • Thanks for the help. i figured it out using printf(" %s", _fullpath(NULL, path, 40)); apparently i was going one directory to high. "..\\..\\res\\thehead.raw"; instead of "..\\..\\..\\res\\thehead.raw" works fine now. thanks for the help – Käptn Freiversuch Jul 06 '14 at 15:07
  • Hello, thanks for the helpful answer. *"Relative paths are relative to the current working directory, not the path of the executable*" - this indeed seems to be true on my (Windows) system. But is this guaranteed by the standard? Or is this prone to behave differently on different machines? – Aviv Cohn Mar 29 '20 at 15:58
  • @AvivCohn It's definitely the case on Unix-like systems as well, although the syntax of relative and absolute paths differs. (E.g. `c:\xyz` is an absolute path on Windows, whereas the same path would be relative on Unix.) Neither C nor C++ have the concept of a working directory in the language standard, so they provide no guarantees either way. – user4815162342 Mar 29 '20 at 18:04
  • `the simplest option is to access the executable as argv[0], extract the directory, and chdir() into it.` This is not always true. argv[0] is what gets typed in the shell, not necessarily be the program's real path. See [link](https://stackoverflow.com/a/42291142/14233885) – user239216 Apr 12 '21 at 08:35
  • @user239216 You're right, I've now amended the answer to warn of this. – user4815162342 Apr 12 '21 at 08:47
3

@Käptn With some modifications to the code, due to some warnings encountered, I found the following worked, although I used the C drive and not D drive as my system does not have a D drive. Effectively, the following code works same and my system will have the "file opened" message that I have added. I find this works the same whether it is run through the debugger, or executed directly from the executable in the Debug folder.

Paths

Here is my .exe file C:\uni\c++\ex5\msvc2013\ex5\Debug    
Here is the file i want to read C:\uni\c++\ex5\res\thehead.raw

Source Code

#include <iostream>

int main (int argc, char ** argv)
{
    FILE* f;
    fopen_s(&f, "..\\..\\..\\res\\thehead.raw", "rb");
    if (f == NULL)
    {
        printf("FAIL!!");
    }
    else
    {
        printf("File opened.");
    }
    return 0;
}
localhost
  • 375
  • 1
  • 3
  • 15