40

I see C's getcwd via: man 3 cwd

I suspect C++ has a similar one, that could return me a std::string .

If so, what is it called, and where can I find it's documentation?

Thanks!

anon
  • 36,629
  • 47
  • 184
  • 286
  • 4
    Why not just use `std::string cwd = getcwd();` and let the constructor do it's job? – LiraNuna Feb 04 '10 at 20:58
  • 5
    Does getcwd() leak memory if you don't free it? If so, then you should free it after creating the string, as opposed to freeing it when you no longer need it, and that's more convenient. If not, then initializing the string won't leak memory. – David Thornley Feb 04 '10 at 21:29
  • 4
    I can confirm with valgrind - string cwd = getcwd(NULL, 0); does leak memory! – Natalie Adams May 28 '13 at 20:41
  • getcwd() allocates the buffer dynamically using malloc(3) if buf is NULL – Gediminas Feb 15 '19 at 10:16

8 Answers8

31

Ok, I'm answering even though you already have accepted an answer.

An even better way than to wrap the getcwd call would be to use boost::filesystem, where you get a path object from the current_path() function. The Boost filesystem library allows you to do lots of other useful stuff that you would otherwise need to do a lot of string parsing to do, like checking if files/directories exist, get parent path, make paths complete etcetera. Check it out, it is portable as well - which a lot of the string parsing code one would otherwise use likely won't be.

Update (2016): Filesystem has been published as a technical specification in 2015, based on Boost Filesystem v3. This means that it may be available with your compiler already (for instance Visual Studio 2015). To me it also seems likely that it will become part of a future C++ standard (I would assume C++17, but I am not aware of the current status).

Update (2017): The filesystem library has been merged with ISO C++ in C++17, for

std::filesystem::current_path();
zdim
  • 53,586
  • 4
  • 45
  • 72
villintehaspam
  • 7,990
  • 6
  • 38
  • 75
  • 3
    Of course, in some situations it may not be worth including the boost::filesystem library just to get the current working directory. Though, if s/he is doing lots of filesystem stuff, then they may as well use boost for all of it. – ctrlc-root Jul 27 '12 at 19:51
  • 16
    Why is every answer boost::this boost::that? – TheRealChx101 Feb 18 '14 at 04:07
  • 1
    @chx101: I don't think Boost is always the answer. But in some cases it is, and using something that already exists and makes your life easier is usually a good thing. Note that some things that are now in the C++ standard came from Boost and that Boost Filesystem is slated for inclusion as a technical specification iirc. – villintehaspam Feb 18 '14 at 08:58
  • 4
    The reason I said that is because whenever someone asks how to achieve a certain task using an API(s), the answer is always: use this library. It makes sense if you're working on a big project and you have time to carve to get acquainted with your new library, but for an application that just wants to get the current working directory you want to download a library just for that? Third party libraries just make it harder to debug your app and like in this case add nothing but bloat and the result is a big fat file. – TheRealChx101 Feb 18 '14 at 18:14
  • @chx101: If I understand correctly, you are saying that it is unnecessary to grab a (big) third party library just to get the current working directory. This part I can agree with to some extent, however the point is that you are not likely just interested in the directory - you are going to use that for something, likely manipulating file paths. Instead of then writing something of your own, which likely is going to be buggy and nonportable you can instead use something that already exists and works. Boost may be too big for some use cases, but you don't need to get it all. – villintehaspam Feb 19 '14 at 15:38
  • @chx101: Then you say that "third party libraries just make it harder to debug your app" and "add nothing but bloat". This part I cannot agree with. Why waste your time debugging your own code if there is something else that already does what you want to do? I would instead argue that using (well written) third party libraries makes it easier to debug your own code, since you write less code. – villintehaspam Feb 19 '14 at 15:42
  • @villintehaspam When you incorporate third party code, it'll more likely hinder or slow down your application debugging process. Some libraries need to initialize and therefore must run before your code does. In that process they may do shit that'd make it hard to debug your code, which comes after the library's."Why waste your time debugging your own code if there is something else that already does what you want to do?" If it's too big for a simple task. – TheRealChx101 Feb 19 '14 at 22:36
  • @villintehaspam >> "using (well written) third party libraries makes it easier to debug your own code, since you write less code" So then what stops you from using your own (well written) code with just exactly enough functions for your task? – TheRealChx101 Feb 19 '14 at 22:38
  • @chx101: You always have a choice whether to use a library or to rewrite the same/better/partial functionality yourself. It's an engineering decision that depends on where you think your time is best spent, risk of problems, ease of use, ease of maintenance, etc. IME, it is usually better to use something that already exists - but it is impossible to give an absolute rule as your use cases are probably different from mine. Also, IME, the self-written library replacements people write tend to be buggy, non-portable, missing functionality, and a nightmare to use. You don't appear to agree, ok. – villintehaspam Feb 19 '14 at 23:40
  • Maybe it depends on who's writing the code. Someone who knows what they're coding is more likely to have less to no bugs. – TheRealChx101 Feb 20 '14 at 01:13
  • And my initial reaction was not a disagreement, I code in Assembly and when sometimes I'm looking up how to achieve something on Windows I usually get the answer use this library or that library when I know that reading the Windows API plus a little research I can roll out my on in Assembly. So yeah. Let's keep things the way they are and just give people our vulnerable libraries and watch people get hacked because the software vendor didn't know what their 3rd party code actually does. – TheRealChx101 Feb 20 '14 at 01:14
  • @chx101: Thanks for proving my point... :) Another example why rolling your own is usually a bad thing is this question itself. ATM there are 6 other answers, none of which are portable nor handle unicode paths on Windows. Another point: Boost Filesystem is essentially what will become the Filesystem Technical Specification for C++. IMHO the choice between Boost and hand-rolled assembly for normal things like this is a no brainer for most applications. One of the reasons that there are lots of vulnerable code in the wild is that people write their own instead of using something existing. – villintehaspam Sep 22 '14 at 21:02
26

std::string's constructor can safely take a char* as a parameter. Surprisingly there's a windows version too.

Edit: actually it's a little more complicated:

std::string get_working_path()
{
   char temp[MAXPATHLEN];
   return ( getcwd(temp, sizeof(temp)) ? std::string( temp ) : std::string("") );
}

Memory is no problem -- temp is a stack based buffer, and the std::string constructor does a copy. Probably you could do it in one go, but I don't think the standard would guarantee that.

About memory allocation, via POSIX:

The getcwd() function shall place an absolute pathname of the current working directory in the array pointed to by buf, and return buf. The pathname copied to the array shall contain no components that are symbolic links. The size argument is the size in bytes of the character array pointed to by the buf argument. If buf is a null pointer, the behavior of getcwd() is unspecified.

Daniel Trugman
  • 6,100
  • 14
  • 35
Kornel Kisielewicz
  • 51,225
  • 12
  • 100
  • 147
  • 2
    Both this answer and Liranuna's comment use `getcwd` as a no-argument function, yet the documentation I see shows two parameters. Am I reading the wrong docs? – Rob Kennedy Feb 04 '10 at 21:01
  • 2
    is the char * automatigally freed? or does this give me a memory leak? – anon Feb 04 '10 at 21:01
  • @anon no, the resulting char* is `malloc` ed and should be `free` d after creating a std::string from it. – Bill Feb 04 '10 at 21:06
  • 1
    @Bill, that's a non-standard extension, as far as I can tell. Linux, Mac, and Windows all implement it, which may or may not be "portable enough." – Rob Kennedy Feb 04 '10 at 21:09
  • 2
    @Bill, the POSIX specification explicitly states that data is copied, not allocated, hence no freeing is needed. – Kornel Kisielewicz Feb 04 '10 at 21:15
  • Sorry, I was looking at the no-parameter version before the edit changed it to take a buffer. If you use the no-parameter version (or the non-standard version that mallocs if given a NULL buffer) then you will need to use free. – Bill Feb 04 '10 at 21:54
  • -1 Potential buffer overflow. Bad code. ( will allocate std::string based on garbage in temp if getcwd fails, garbage may not be nul terminated; you need to check return value from ::getcwd and throw on error ) – Pete Kirkham Feb 04 '10 at 22:29
  • @Pete, exceptions are not a solution that can be used always - refrain from wanting to throw everywhere. However the error checking was ommited for verbosity as usual in such cases. Where do you see a buffer overflow? – Kornel Kisielewicz Feb 04 '10 at 22:38
  • If an error occurs, then the contents of temp are undefined. As you were creating a string using the single argument constructor expecting a nul terminated string, the constructor could scan off the end before you hit a nul. Hence, buffer (read) overflow. Your edited code does not have this issue, but may cause weird behaviour in whatever is using the return value if it does fail, unless the client tests for an empty string. Personally, I wouldn't wrap the posix function at all, and let the client code test the documented POSIX result rather than testing for empty. – Pete Kirkham Feb 04 '10 at 23:00
  • @RobKennedy undefined here on OSX 10.6 – o0'. Apr 03 '12 at 21:39
13

Let's try and rewrite this simple C call as C++:

std::string get_working_path()
{
    char temp [ PATH_MAX ];

    if ( getcwd(temp, PATH_MAX) != 0) 
        return std::string ( temp );

    int error = errno;

    switch ( error ) {
        // EINVAL can't happen - size argument > 0

        // PATH_MAX includes the terminating nul, 
        // so ERANGE should not be returned

        case EACCES:
            throw std::runtime_error("Access denied");

        case ENOMEM:
            // I'm not sure whether this can happen or not 
            throw std::runtime_error("Insufficient storage");

        default: {
            std::ostringstream str;
            str << "Unrecognised error" << error;
            throw std::runtime_error(str.str());
        }
    }
}

The thing is, when wrapping a library function in another function you have to assume that all the functionality should be exposed, because a library does not know what will be calling it. So you have to handle the error cases rather than just swallowing them or hoping they won't happen.

It's usually better to let the client code just call the library function, and deal with the error at that point - the client code probably doesn't care why the error occurred, and so only has to handle the pass/fail case, rather than all the error codes.

Pete Kirkham
  • 46,814
  • 5
  • 86
  • 159
6

You'll need to just write a little wrapper.

std::string getcwd_string( void ) {
   char buff[PATH_MAX];
   getcwd( buff, PATH_MAX );
   std::string cwd( buff );
   return cwd;
}
Brian Gianforcaro
  • 24,434
  • 11
  • 53
  • 76
  • maybe try ```std::string getcwd_string( void ) { string ret(PATH_MAX,0); getcwd( &ret[0], PATH_MAX ); ret.resize(ret.find_first_of('\0',0)); return ret; } ``` - avoiding VLA's (which is technically not part of c++ standards, at least not yet, albeit most compilers support it as an extension to the language) – hanshenrik Aug 31 '18 at 08:25
  • You have to check for nullptr (NULL) returned from getcwd. – Doncho Gunchev Oct 15 '19 at 14:15
4

I used getcwd() in C in the following way:

char * cwd;
cwd = (char*) malloc( FILENAME_MAX * sizeof(char) );
getcwd(cwd,FILENAME_MAX);

The header file needed is stdio.h. When I use C compiler, it works perfect.

If I compile exactly the same code using C++ compiler, it reports the following error message:

identifier "getcwd" is undefined

Then I included unistd.h and compiled with C++ compiler. This time, everything works. When I switched back to the C compiler, it still works!

As long as you include both stdio.h and unistd.h, the above code works for C AND C++ compilers.

Eugene Loy
  • 11,677
  • 8
  • 47
  • 73
Zhongming Qu
  • 2,777
  • 1
  • 9
  • 2
3

All C functions are also C++ functions. If you need a std::string, just create one from the char* that getcwd gets for you.

Rob Kennedy
  • 156,531
  • 20
  • 258
  • 446
1

I also used boost::filesystem as stated in another answer above. I just wanted to add that since the current_path() function does not return a std::string, you need to convert it.

Here is what I did:

std::string cwd = boost::filesystem::current_path().generic_string();
crecre
  • 11
  • 2
-2

You could create a new function, which I would prefer over linking to a library like boost(unless you already are).

 std::string getcwd()
 {
     char* buff;//automatically cleaned when it exits scope
     return std::string(getcwd(buff,255));
 }