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*).

Xeo
  • 129,499
  • 52
  • 291
  • 397
Mack
  • 63
  • 1
  • 3
  • 2
    Who the f* tries to close this off as an exact duplicate? It's a completely different question! – Xeo Jun 12 '11 at 11:54
  • @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. – rubenvb Jun 12 '11 at 11:58
  • 2
    @rubenvb: Except GetEnvironmentStrings() returns a dodgy format, which the OP requires *specific* help with. You cannot just replace `getenv` with `GetEnvironmentStrings()`. – Puppy Jun 12 '11 at 12:00
  • 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. – Cem Kalyoncu Jun 12 '11 at 12:01
  • Woops, my apologies, I'm not awake enough to use my "close" votes. – rubenvb Jun 12 '11 at 12:02
  • @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. – Puppy Jun 12 '11 at 12:08

7 Answers7

9

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";
}
Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 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 characters – Mack Jun 12 '11 at 12:02
  • @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. – Puppy Jun 12 '11 at 12:03
  • @Mack: Not to forget, `strtok` is a hideously *wrong* thing in and of itself. It's a full-blown singleton state machine. – Xeo Jun 12 '11 at 12:08
  • @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. – Puppy Jun 12 '11 at 12:09
  • Does it work if there are not environment variables: ie "\0" is returned. – Martin York Jun 12 '11 at 17:00
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);
johv
  • 4,424
  • 3
  • 26
  • 42
ToBe
  • 921
  • 1
  • 9
  • 23
  • 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(). – johv May 15 '21 at 13:05
  • Note, the pointer `a` returned from `GetEnvironmentStrings` had been modified before passed to `FreeEnvironmentStrings`... – xenophōn Jan 14 '22 at 01:51
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.

Mat
  • 202,337
  • 40
  • 393
  • 406
  • 1
    Check the documentation for GetEnvironmentStrings- it won't be enough. – Puppy Jun 12 '11 at 11:54
  • 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 bit – Mack Jun 12 '11 at 11:55
  • @Mack, yes, the above will only catch the first one, sorry I forgot that environment block layout. – Mat Jun 12 '11 at 12:00
0

Does the following causes any problems?

char* a = GetEnvironmentStrings();
string b;
b=a;
printf( "%s", b.c_str() );
Cem Kalyoncu
  • 14,120
  • 4
  • 40
  • 62
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 );
0
char* a = ...;
string str(a);
string b;
b = a;
nirmus
  • 4,913
  • 9
  • 31
  • 50
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
}
mloskot
  • 37,086
  • 11
  • 109
  • 136