Environment Variables are in a char* how to get it to a std::string
Asked Answered
P

7

6

I am retrieving the environment variables in win32 using GetEnvironmentStrings(). It returns a char*.

I want to search this string(char pointer) for a specific environmental variable (yes I know I can use GetEnvironmentVariable() but I am doing it this way because I also want to print all the environment variables on the console aswell - I am just fiddling around).

So I thought I would convert the char* to an std::string & use find on it (I know I can also use a c_string find function but I am more concerned about trying to copy a char* into a std::string). But the following code seems to not copy all of the char* into the std::string (it makes me think there is a \0 character in the char* but its not actually the end).

char* a = GetEnvironmentStrings();
string b = string(a, sizeof(a));
printf( "%s", b.c_str() );  // prints =::= 

Is there a way to copy a char* into a std::string (I know I can use strcpy() to copy a const char* into a string but not a char*).

Placatory answered 12/6, 2011 at 11:47 Comment(6)
Who the f* tries to close this off as an exact duplicate? It's a completely different question!Melisent
@Xeo: Well, no, it is not... The getenv/GetEnvironmentVariable function used is different but the result is the same... All the OP's got to do is replace the getenv call with a GetEnvironmentVariable call.Aiguillette
@rubenvb: Except GetEnvironmentStrings() returns a dodgy format, which the OP requires specific help with. You cannot just replace getenv with GetEnvironmentStrings().Presentation
Problem is not exactly the same. After all he is not trying to learn how to do it, he is after why it happened that way.Dibble
Woops, my apologies, I'm not awake enough to use my "close" votes.Aiguillette
@rubenvb: You know, even if the OP was asking about GetEnvironmentVariable, it does actually have a different interface to getenv and I wouldn't call it a duplicate anyway.Presentation
P
10

You do not want to use sizeof() in this context- you can just pass the value into the constructor. char* trivially becomes const char* and you don't want to use strcpy or printf either.

That's for conventional C-strings- however GetEnvironmentStrings() returns a bit of a strange format and you will probably need to insert it manually.

const char* a = GetEnvironmentStrings();
int prev = 0;
std::vector<std::string> env_strings;
for(int i = 0; ; i++) {
    if (a[i] == '\0') {
        env_strings.push_back(std::string(a + prev, a + i));
        prev = i;
        if (a[i + 1] == '\0') {
            break;
        }
    }
}
for(int i = 0; i < env_strings.size(); i++) {
    std::cout << env_strings[i] << "\n";
}
Presentation answered 12/6, 2011 at 11:54 Comment(5)
thanks I understand, so it must be true, that char* of environ variables is full of \0 chars. I take your approach but I think instead of iterating over every char I will use the c string function strtok to split it at the \0 charactersPlacatory
@Mack: You can't do that. GetEnvironmentStrings returns memory which you are not allowed to write over, and strtok is not thread-safe, and it's hideously unsafe anyway. Use a C++ approach.Presentation
@Mack: Not to forget, strtok is a hideously wrong thing in and of itself. It's a full-blown singleton state machine.Melisent
@Mack: Oh, and I don't think it's possible to get strtok to not stop at the first \0, and wait for a double \0. All the C-string libraries will expect \0 as a terminator- that's why you need custom parse code.Presentation
Does it work if there are not environment variables: ie "\0" is returned.Rosinweed
P
1

sizeof(a) in what you have above will return the size of char*, i.e. a pointer (32 or 64bits usually). You were looking for function strlen there. And it's not actually required at all:

std::string b(a);

should be enough to get the first environment variable pair.

Puny answered 12/6, 2011 at 11:52 Comment(3)
Check the documentation for GetEnvironmentStrings- it won't be enough.Presentation
thanks but I have tried that & it still prints out =::= it makes me think that there is a \0 character at the end of each Environment variable which is why I am getting that little bitPlacatory
@Mack, yes, the above will only catch the first one, sorry I forgot that environment block layout.Puny
C
1

The result of GetEnvironmentStrings() points to memory containing all environment strings. Similar to the solution of Puppy it will be put into a vector of string, where each string contains just one environment variable ("key=value")

std::vector<std::string> env_strings;
LPTCH a = GetEnvironmentStrings();

As example we will have 2 environment variables defined:

"A=ABC"
"X=XYZ"

LPTCH a will be:

A=ABC\0X=XYZ\0\0

Each variable is '\0' - terminated and finally the complete environment string (a) will be terminated with an additional '\0'.

strlen will return the size to the first occurrence of the termination character '\0'. The last string will always be empty.

while ((std::size_t len = strlen(a)) > 0)
{
    env_strings.push_back(std::string(a, len));
    a += len + 1;
}

Multi-byte character

For multi-byte characters it will work as well:

LPTCH a = GetEnvironmentStrings();
std::vector<std::wstring> env_strings;

while ((std::size_t len = wcslen(a)) > 0)
{
    env_strings.push_back(std::wstring(a, len));
    a += len + 1;
}

FreeEnvironmentStrings(a);
Conservationist answered 23/7, 2018 at 9:52 Comment(2)
You can use std::string_view to avoid allocating+copying the strings just to process them (e.g. looking for a specific variable). But copy what you need to save before calling FreeEnvironmentStrings().Talkathon
Note, the pointer a returned from GetEnvironmentStrings had been modified before passed to FreeEnvironmentStrings...Filagree
D
0

Does the following causes any problems?

char* a = GetEnvironmentStrings();
string b;
b=a;
printf( "%s", b.c_str() );
Dibble answered 12/6, 2011 at 11:51 Comment(1)
well I got more into the std::string, it prints out: =::=::\ nowPlacatory
E
0

When you say:

string b = string(a, sizeof(a));

you are getting the size of a, which is a pointer and is probably 4. So you will get the first 4 characters. I'm not sure what you are really trying to do, but you should be able just to say:

string b( a );
Eluvium answered 12/6, 2011 at 11:52 Comment(0)
M
0
char* a = ...;
string str(a);
string b;
b = a;
Moffett answered 12/6, 2011 at 11:54 Comment(0)
W
0

I assume you mean the Windows API GetEnvironmentStrings function. So, test the result against nullptr and perform simple assignment:

char* env = ::GetEnvironmentStrings();
if (0 != env)
{
   std::string senv = env;
   // use senv to find variables
}
else
{
   // report problem or ignore
}
Whimsy answered 12/6, 2011 at 11:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.