getenv in C++ returns wrong values - c++

I would like to write my program in 2 different paths. So, I proceeded like that :
std::string path1 = strcat(std::getenv("APPDATA"),"\\myprog.exe") ;
std::string path2 = strcat(std::getenv("APPDATA"),"\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\myprog.exe") ;
When I print, I get :
C:\Users\thispc\AppData\Roaming\myprog.exe
C:\Users\thispc\AppData\Roaming\myprog.exe\Microsoft\Windows\Start Menu\Programs\Startup\myprog.exe
instead of :
C:\Users\thispc\AppData\Roaming\myprog.exe
C:\Users\thispc\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\myprog.exe
Solution by Dietmar Kühl :
std::string path1 = std::getenv("APPDATA") + std::string("\\myprog.exe");
Explanation by Oliver Charlesworth :
strcat() changes the 1st variable

What is happening here is that std::getenv("APPDATA") gives you a pointer to a already written string somewhere in memory, that means the pointer returned by this function will always be the same.
Thus when you do strcat(std::getenv("APPDATA"),"\\myprog.exe") you basically concatenate that stored string in memory with "\\myprog.exe". So when you make a second call of std::getenv("APPDATA") you will get the concatenated string.
To solve this problem you should copy the string at std::getenv("APPDATA")

Related

How to concatenate string in ROOT,c++?

I want to concatenate two string and I did in my program like String Filename = name+ "" + extension where extension is an integer value that I read just above this line and name is the path that is already defined.
But in ROOT I am getting error like Error: + illegal operator for pointer 1
What went wrong here? Is there any other method?
If extension is an integer, then convert it to a string first.
std::string Filename = name+ "" + std::to_string(extension);
+""+ does nothing, btw
The TString class in ROOT has a function called "Format" which you can use to concatenate strings the same way you format a print statement. Here is the documentation for the Format method: https://root.cern.ch/root/html/TString.html#TString:Format
and here is the documentation for how the formatting works http://www.cplusplus.com/reference/cstdio/printf/
I'm going to go ahead and assume the 'name' is a char*.
Char const* name = "john";
Char const* space = " ";
Here name and space are 2 pointers to character arrays.
When you add try to add these 2 together, the compiler tries to add the value of the 2 pointer together. This makes no sense to the compiler. You can obviously only add an offset to a pointer.
The solution to this is to make sure that one of the 2 things you are adding is a std::string and not 'c string'.

Splitting a std::string into two const char*s resulting in the second const char* overwriting the first

I am taking a line of input which is separated by a space and trying to read the data into two integer variables.
for instance: "0 1" should give child1 == 0, child2 == 1.
The code I'm using is as follows:
int separator = input.find(' ');
const char* child1_str = input.substr(0, separator).c_str(); // Everything is as expected here.
const char* child2_str = input.substr(
separator+1, //Start with the next char after the separator
input.length()-(separator+1) // And work to the end of the input string.
).c_str(); // But now child1_str is showing the same location in memory as child2_str!
int child1 = atoi(child1_str);
int child2 = atoi(child2_str); // and thus are both of these getting assigned the integer '1'.
// do work
What's happening is perplexing me to no end. I'm monitoring the sequence with the Eclipse debugger (gdb). When the function starts, child1_str and child2_str are shown to have different memory locations (as they should). After splitting the string at separator and getting the first value, child1_str holds '0' as expected.
However, the next line, which assigns a value to child2_str not only assigns the correct value to child2_str, but also overwrites child1_str. I don't even mean the character value is overwritten, I mean that the debugger shows child1_str and child2_str to share the same location in memory.
What the what?
1) Yes, I'll be happy to listen to other suggestions to convert a string to an int -- this was how I learned to do it a long time ago, and I've never had a problem with it, so never needed to change, however:
2) Even if there's a better way to perform the conversion, I would still like to know what's going on here! This is my ultimate question. So even if you come up with a better algorithm, the selected answer will be the one that helps me understand why my algorithm fails.
3) Yes, I know that std::string is C++ and const char* is standard C. atoi requires a c string. I'm tagging this as C++ because the input will absolutely be coming as a std::string from the framework I am using.
First, the superior solutions.
In C++11 you can use the newfangled std::stoi function:
int child1 = std::stoi(input.substr(0, separator));
Failing that, you can use boost::lexical_cast:
int child1 = boost::lexical_cast<int>(input.substr(0, separator));
Now, an explanation.
input.substr(0, separator) creates a temporary std::string object that dies at the semicolon. Calling c_str() on that temporary object gives you a pointer that is only valid as long as the temporary lives. This means that, on the next line, the pointer is already invalid. Dereferencing that pointer has undefined behaviour. Then weird things happens, as is often the case with undefined behaviour.
The value returned by c_str() is invalid after the string is destructed. So when you run this line:
const char* child1_str = input.substr(0, separator).c_str();
The substr function returns a temporary string. After the line is run, this temporary string is destructed and the child1_str pointer becomes invalid. Accessing that pointer results in undefined behavior.
What you should do is assign the result of substr to a local std::string variable. Then you can call c_str() on that variable, and the result will be valid until the variable is destructed (at the end of the block).
Others have already pointed out the problem with your current code. Here's how I'd do the conversion:
std::istringstream buffer(input);
buffer >> child1 >> child2;
Much simpler and more straightforward, not to mention considerably more flexible (e.g., it'll continue to work even if the input has a tab or two spaces between the numbers).
input.substr returns a temporary std::string. Since you are not saving it anywhere, it gets destroyed. Anything that happens afterwards depends solely on your luck.
I recommend using an istringstream.

c++ strtok in function changes original string value as parameter

when I use strtok to tokenize a c++ string, it happens a confusing problem, see the simple code below:
void a(string s){
strtok((char*)s.c_str(), " ");
}
int main(){
string s;
s = "world hello";
a(s);
cout<<s<<endl;
return 0;
}
the program outputs "world".
Shouldn't it output "world hello"? Because I pass the string as a value parameter to function a, the strtok shouldn't modify the original s...
Can anyone explain this trick.
thank you.
The problem is (char*)s.c_str(), you are casting the constness away and modified the string contents in a way that you are not supposed to. While the original s should not be modified, I pressume you may have been hit by a smart optimization that expects you to play by the rules. For instance, a COW implementation of string would happen to show that behavior.
c_str() returns a const pointer, which is a promise to the compiler that the thing being pointed at won't be modified. And then you're calling strtok which modifies it.
When you lie to the compiler, you will be punished.
That's the way strtok() works. It use the first parameter as a buffer. By casting it to a char*, you allow it to modify the string. strtok() does not known about the original std::string. It also store the string pointer in a static variable, that's why you have to call it with a null pointer the next times to continue to parse the same string.
By the way, in c++, you should use std::istringstream instead. It does not use an internal static variable, which is not thread-safe. And you can extract the parameters directly into int, double, etc like we do with cin. std::ostringstring replace sprintf().

Trying to understand strtok

Consider the following snippet that uses strtok to split the string madddy.
char* str = (char*) malloc(sizeof("Madddy"));
strcpy(str,"Madddy");
char* tmp = strtok(str,"d");
std::cout<<tmp;
do
{
std::cout<<tmp;
tmp=strtok(NULL, "dddy");
}while(tmp!=NULL);
It works fine, the output is Ma. But by modifying the strtok to the following,
tmp=strtok(NULL, "ay");
The output becomes Madd. So how does strtok exactly work? I have this question because I expected strtok to take each and every character that is in the delimiter string to be taken as a delimiter. But in certain cases it is doing that way but in few cases, it is giving unexpected results. Could anyone help me understand this?
"Trying to understand strtok" Good luck!
Anyway, we're in 2011. Tokenise properly:
std::string str("abc:def");
char split_char = ':';
std::istringstream split(str);
std::vector<std::string> token;
for (std::string each; std::getline(split, each, split_char); token.push_back(each));
:D
Fred Flintstone probably used strtok(). It predates multi threaded environments and beats up (modifies) the source string.
When called with NULL for the first parameter, it continues parsing the last string. This feature was convenient, but a bit unusual even in its day.
It seems you forget that you have call strtok the first time (out of loop) by delimiter "d".
The strtok is working fine. You should have a reference here.
For the second example(strtok("ay")):
First, you call strtok(str, "d"). It will look for the first "d", and seperate your string. Specifically, it sets tmp = "Ma", and str = "ddy" (dropping the first "d").
Then, you call strtok(str, "ay"). It will look for an "a" in str, but since your string now is only "ddy", no matching occurs. Then it will look for an "y". So str = "dd" and tmp = "".
It prints "Madd" as you saw.
Actually your code is wrong, no wonder you get unexpected results:
char* str = (char*) malloc(sizeof("Madddy"));
should be
char* str = (char*) malloc(strlen("Madddy") + 1);
I asked a question inspired from another question about functions causing security problems/bad practise functions and the c standard library.
To quote the answer given to me from there:
A common pitfall with the strtok()
function is to assume that the parsed
string is left unchanged, while it
actually replaces the separator
character with '\0'.
Also, strtok() is used by making
subsequent calls to it, until the
entire string is tokenized. Some
library implementations store
strtok()'s internal status in a
global variable, which may induce some
nasty suprises, if strtok() is
called from multiple threads at the
same time.
As you've tagged your question C++, use something else! If you want to use C, I'd suggest implementing your own tokenizer that works in a safe fashion.
Since you changed your tag to be C and not C++, I rewrote your function to use printf so that you can see what is happening. Hoang is correct. You seeing correct output, but I think that you are printing everything on the same line, so you got confused by the output. Look at Hoang's answer as he explains what is happening correctly. Also, as others have noted, strtok destroys the input string, so you have to be careful about that - and it's not thread safe. But if you need a quick an dirty tokenizer, it works. Also, I changed the code to correctly use strlen, and not sizeof as correctly pointed out by Anders.
Here is your code modified to be more C-like:
char* str = (char*) malloc(strlen("Madddy") + 1);
strcpy(str,"Madddy");
char* tmp = strtok(str,"d");
printf ("first token: %s\n", tmp);
do
{
tmp=strtok(NULL, "ay");
if (tmp != NULL ) {
printf ("next token: %s\n", tmp);
}
} while(tmp != NULL);

How to use string and string pointers in C++

I am very confused about when to use string (char) and when to use string pointers (char pointers) in C++. Here are two questions I'm having.
which one of the following two is correct?
string subString;
subString = anotherString.sub(9);
string *subString;
subString = &anotherString.sub(9);
which one of the following two is correct?
char doubleQuote = aString[9];
if (doubleQuote == "\"") {...}
char *doubleQuote = &aString[9];
if (doubleQuote == "\"") {...}
None of them are correct.
The member function sub does not exist for string, unless you are using another string class that is not std::string.
The second one of the first question subString = &anotherString.sub(9); is not safe, as you're storing the address of a temporary. It is also wrong as anotherString is a pointer to a string object. To call the sub member function, you need to write anotherString->sub(9). And again, member function sub does not exist.
The first one of the second question is more correct than the second one; all you need to do is replace "\"" with '\"'.
The second one of the second question is wrong, as:
doubleQuote does not refer to the 10th character, but the string from the 10th character onwards
doubleQuote == "\"" may be type-wise correct, but it doesn't compare equality of the two strings; it checks if they are pointing to the same thing. If you want to check the equality of the two strings, use strcmp.
In C++, you can (and should) always use std::string (while remembering that string literals actually are zero-terminated character arrays). Use char* only when you need to interface with C code.
C-style strings need error-prone manual memory management, need to explicitly copy strings (copying pointers doesn't copy the string), and you need to pay attention to details like allocating enough memory to have the terminating '\0' fit in, while std::string takes care of all this automagically.
For the first question, the first sample, assuming sub will return a substring of the provided string.
For the second, none:
char doubleQuote = aString[9];
if( doubleQuote == '\"') { ... }
Erm, are you using string from STL?
(i.e. you have something like
#include <string>
#using namespace std;
in the beginning of your source file ;) )
then it would be like
string mystring("whatever:\"\""");
char anElem = mystring[9];
if (anElem=="\"") { do_something();}
or you can write
mystring.at(9)
instead of square brackets.
May be these examples can help.