is there non const variant of c_str()?

Jun 15, 2014 at 1:49pm
is there non const variant of c_str()?

I used this to convert from string to char
const char * cpath = path.c_str();
now I found I need to trim the string but const denies to change it. So is there a variant which allows to change the variable?
Jun 15, 2014 at 1:52pm
Yes. See http://www.cplusplus.com/reference/string/string/copy/

If you need to trim the string, why not do it while it was still a string. In fact, why do you need to turn it into a C-string anyway? Why don't you just pass the actual string object around?
Last edited on Jun 15, 2014 at 1:53pm
Jun 15, 2014 at 2:00pm
Are you trying to modify the original string or modify a copy of the string?

If you don't mind modifying a copy then you'll need to copy it:
1
2
3
4
char * cpath = new char[ path.size() ];
strcpy(cpath, path.c_str() );
//...
delete[] cpath;


Otherwise, getting a char* from a std::string would be returning a pointer to the internal data. That's too dangerous for std::string because it would let someone modify the internal data without considering any other internal methods such as updating the size, re-allocating memory, etc.

http://www.cplusplus.com/reference/cstring/strcpy/

Edit: I stand corrected NT3... still the same thing, A copy is needed.
1
2
char* cpath = new char[ path.size() ];
strcpy(cpath, path.c_str() );
char* cpath = new char[ path.size() ];
path.copy(cpath, path.size() );
Last edited on Jun 15, 2014 at 2:08pm
Jun 15, 2014 at 2:06pm
NT3:
To answer your question, I am testing the string path:
if( stat(cpath,&s) == 0 )
stat needs char. Maybe I did not choosed correct way how to do it. My idea was to trim dot from left for the case directory name is like ./myDir , but then I realized that there can be file name like .myfile so not good idea. I should test first two characters and if they are ./ so remove 2 and add current_path to begin of the variable.
Jun 15, 2014 at 2:34pm
stat needs char
if( stat(path.c_str(), &s) == 0 )

You should do all operation on your actual path string and convert it to c-string right before passing into function.
Jun 15, 2014 at 2:54pm
Good idea. But I have one more problem with testing the begin of the path.

path: .\88469142758.jpeg
Type: std::basic_string<char,std::char_traits<char>,std::allocator<char> >

using:
1
2
std::string prefix(".\"");
n = path.compare(0, prefix.size(), prefix);


path.compare(0, prefix.size(), prefix);
returns CXX0047: Error: argument list does not match a function
n is 1
any idea why?
Last edited on Jun 15, 2014 at 2:55pm
Jun 15, 2014 at 3:03pm
compare() returns zero on match. As your string does not starts with .", it returns nonzero value. Maybe you want to compare it with .\?
Jun 15, 2014 at 3:11pm
> I should test first two characters and if they are ./ so remove 2 and add current_path to begin of the variable.

You do not need to do that. stat() accepts relative paths.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main() 
{
    struct stat buf ;
    
    for( const std::string path : { "./test_dir", "./main.cpp", "./../../usr/local/include", "bad_path" } )
    {
        std::cout << '\'' << path << "' : " ;
        if( stat( path.c_str(), &buf ) == 0 )
        {
            const mode_t mode = buf.st_mode ;
            
            if( S_ISREG(mode) ) std::cout << "regular file\n" ;
            else if( S_ISDIR(mode) ) std::cout << "directory\n" ;
            // etc.
        }
        else std::cout << "*** stat error ***\n" ;
    }
}

http://coliru.stacked-crooked.com/a/84653bbed9e75cbd

As an academic exercise, to get a c-style string without leading ./ if any:
1
2
3
4
    const std::string path = "./my_dir" ;
    const char* cstr = path.c_str() ;
    if( path.find( "./" ) == 0 ) // begins with ./
         cstr += 2 ; // skip the first two chars 
Jun 15, 2014 at 3:24pm
MiiNiPaa, yes I want to compare .\ , I see my error now, should be
std::string prefix(".\\"); thanks
Jun 15, 2014 at 4:24pm
JLBorges: But in your 2nd example if I want to join this:
1
2
3
4
5
const char* cpath = path.c_str() ;
	if( path.find( ".\\" ) == 0 ){ // begins with .\ 
         cpath += 2 ; // skip the first two chars       
	cpath = *workingPath + cpath; // join the value of workigPath with cPath
	}

Result is failture
Last edited on Jun 15, 2014 at 4:24pm
Jun 15, 2014 at 4:27pm
What workingPath is? Why do you need to dereference it? If working path a c-string too, you need to make use of strncat function.
Jun 15, 2014 at 4:51pm
both are c string.

Edit: workingPath is c string.
Path is stiring as original.
cpath would be const c string if I use it as destination of conversation.
Last edited on Jun 15, 2014 at 4:53pm
Jun 15, 2014 at 5:05pm
cpath = *workingPath + cpath Here you are adding integral value of first character of working path to cpath pointer.
You need either:
1) Work with strings and take c-string as last step:
1
2
3
4
5
if( path.find( "./" ) == 0 ) {
    path.erase(0, 2);
    path.insert(0, workingPath);
}
const char* cpath =  path.c_str();

2) contacenate your strings:
1
2
3
4
5
6
char buffer[256];
if (path.find( "./" ) == 0) {
    strncpy(buffer, workingPath, 256);
    strncat(buffer, path.c_str() + 2, 256 - strlen(buffer));
} else
    strncpy(buffer, path.c_str(), 256);
Jun 15, 2014 at 6:40pm
MiiNiPaa
thanks, your solution works. But I am too tired to think about is father more. Just question to the second solution. Is it possible to use similar solution but for char * buffer? But the first solution is clear and simple. Simple to remember.
Jun 15, 2014 at 6:59pm
Is it possible to use similar solution but for char * buffer
It uses char* buffer already. You can use dynamic memory allocation and pointers to guarantee that any path would fit.
Topic archived. No new replies allowed.