problem to join strings - error C2059

I would like to join three strings - working path, "\\", and (*it) to make test if path exists.

S::I().Stat.workingPath is char *.
(*it) returns string from the iterator.
I am trying to convert to C string with ((*it).c_str())

error C2059: syntax error : 'string'

1
2
3
4
if (FILE_::IsDirectory(arg, (S::I().Stat.workingPath)."\\".((*it).c_str()) ) 
{
S::I().Stat.subFolder = (S::I().Stat.workingPath."\\").((*it).c_str());
}
The dot operator does not concatenate strings as you seem to think it does. If you have string objects (as in, std::string), you can concatenate strings with the + operator. Otherwise, if you have a char array, you can use the strcat function.

Assuming Stat.subFolder is a string and not a char array, you can do it like this:

1
2
S::I().Stat.subFolder = S::I().Stat.workingPath;
S::I().Stat.subFolder += "\\" + *it;


The reason for the two-step assignment here is because you cannot use + to join char arrays -- at least one of them must be a string object. Both "\\" and workingPath are char arrays, so they cannot be joined with +. So that's why I assign workingPath to subFolder (assuming subFolder is a string) first.

The second line I can use + to join "\\" and *it because *it is a string object.

* Note you could do this in one line by constructing a string object from workingPath or "\\":

 
S::I().State.subFolder = S::I().Stat.workingPath + string("\\") + *it;




If subFolder is not a string... if it is a char array... then blech... .stop using char arrays. Anyway, if that's the case, then you can do this:

1
2
3
strcpy( S::I().Stat.subFolder, S::I().Stat.workingPath );
strcat( S::I().Stat.subFolder, "\\" );
strcat( S::I().Stat.subFolder, it->c_str() );


As you can see, this becomes a 3 step problem as each portion of the string must be appended individually

* technically this is not true, you could cram all of this into one line by nesting all these calls within each other, but it is ugly and confusing:

1
2
// I think I did this right...
strcat( strcat( strcpy( S::I().Stat.subFolder, S::I().Stat.workingPath ), "\\"), it->c_str() );




Ideally... everything here would be a string object. Then we could just do this:

 
S::I().Stat.subFolder = S::I().Stat.workingPath + "\\" + *it;


So let that be the moral to this story: favor strings over char arrays.
Last edited on
I'd try to build my own function, but I have problem with the strcpy

1
2
3
4
5
6
7
8
void FILE_::addDirectory(const char *dir, char * toDir){
	strcpy( toDir, S::I().Stat.workingPath );
	strcat(  toDir, "\\" );
	strcat(  toDir, "dir" );
}

toDir = "";
FILE_::addDirectory( (*it).c_str(), toDir);


When I enter addDirectory so it will break when running strcpy. It will break in file strcat.asm - second line:

1
2
3
main_loop:                          ; edx contains first dword of sorc string
        mov     [edi],edx           ; store one more dword
        add     edi,4               ; kick dest pointer

break is here:
strcpy( toDir, S::I().Stat.workingPath );

Actually if I will use this:
strcat( toDir, S::I().Stat.workingPath );
so it will do the same.
Last edited on
What does the manual say? http://www.cplusplus.com/reference/cstring/strcpy/
To avoid overflows, the size of the array pointed by destination shall be long enough to contain the same C string as source (including the terminating null character), and should not overlap in memory with source.

(I would write "must".)

And: http://www.cplusplus.com/reference/cstring/strcat/
Pointer to the destination array, which should contain a C string, and be large enough to contain the concatenated resulting string.


So, how much did you reserve?
char * toDir = "";
Your pointer does not point to any allocated space. Your toDir has an address of a byte in the read-only memory area of string literals, and that byte contains a '\0'.

Disch wrote:
stop using char arrays

+1
Ah, I understand
char * toDir = new char[1024]();
thanks :-)
What are those parentheses () doing there?

http://www.informit.com/articles/article.aspx?p=1852519

Explicit dynamic allocation makes you responsible for managing that memory. Frankly, I don't think you are up to the challenge yet.


Why can't you just use the std::string?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (i == 1 && (*it) != "-r" ){
	FILE_::addDirectory( (*it).c_str(), toDir);
	if ( FILE_::isDirectory(toDir, "") ) 
	{
	S::I().Stat.subFolder = toDir;
	// find out if there is -r option after 1st argument to join files
	src_temp.join = true;
	S::I().Stat.getRegEx = true;
	}
	else	{
	src_temp.file = (*it); src_temp.join = false;
	}
	delete [] toDir;
	}


I use std::string but not here.

http://stackoverflow.com/questions/3134458/how-to-initialize-a-char-array
It's known as value-initialisation, and was introduced in C++03


Edit:
I corrected the memory deallocation. Thanks
Last edited on
> I use std::string but not here.
¿and why is that?
You would at least avoid mistakes as delete toDir;
As ne555 said... why not?

And to elaborate on his 2nd point... you are using new[] but not delete[]... therefore you have a memory leak.

new[] -> delete[]
new -> delete

or better yet... don't use new/delete because they make it difficult to write exception safe code and are very easy to make mistakes with and cause memory leaks. RAII containers (like std::string) are easier and safer to work with.

std::string is even potentially faster for the kind of work you're doing (string concatenation). There is very rarely any reason to choose char arrays over strings.
I could not find this thread (idk how to find it in the list of my topics, I see only few links there).

I corrected the memory deallocation. I had found the error today when I was searching how to create 2D array.

So the char arrays have to be deallocated from memory using the brackets [] after delete but normal objects don't.

I prefer using C string when I use it later in findFiles function. Command HANDLE handle = FindFirstFileA(searchItem, &search_data); uses searchItem which is char array.

Also I am using while loop to search files and I prefer C string to compare data because I am using sscanf http://www.cplusplus.com/reference/cstdio/sscanf/ which uses C strings.
Last edited on
You could use 'std::string::c_str()', as you are already doing in other places.
When I am using
1
2
3
4
pattern = new char[100]();
strcat( pattern, "%d" );
strcat( pattern, midS );
strcat( pattern, "%d" );	

inside a loop, how could I improve the first line, when I don't want to use std::string?
I mean, it does not make sense to allocate memory every time in the loop. If I would use just pattern = ""; so it will break the program. Maybe I could do something like:

1
2
3
4
5
6
7
8
char * temp = new char[100]();
while(handle != INVALID_HANDLE_VALUE){
pattern = temp;
strcat( pattern, "%d" );
strcat( pattern, midS );
strcat( pattern, "%d" );
...
}

(see line 3) would this be OK? But the temp is alwazys pointer, would it make any change to reset the char array? Or it would just mean "set the pointer pattern to pointer temp" so the content of memory is not changed at all?
Last edited on
1- replace the first 'strcat()' with 'strcpy()'
a- pattern[0] = '\0';

'midS' will change in every iteration, ¿right?

> char * temp = new char[100]();
If the size is going to be a compile time constant
char temp[100] = {};


> when I don't want to use std::string?
¿would you at least use nih::string?
Thanks. midS is constant. nih?
¿Then why don't simply char pattern[] = "%dthe mid string%d"?
or if it is a parameter of a function just set it once, outside the loop

nih: not invented here. Develop your own string class so you it doesn't have the quirks, but it is encapsulated and can be tested and trusted.
Last edited on
It's not clear to me how can I get the const char * to the expression: "%dthe mid string%d" It is surrounded with double quotes, so the midS will be interpreted as string "midS" not as cont string midS. The compiler will not put the content of the constant into the string.
Topic archived. No new replies allowed.