1
errno_t _dupenv_s(
   char **buffer,
   size_t *sizeInBytes,
   const char *varname
);

I have several questions regarding this:

  1. why a pointer to pointer(**) is required instead of a pointer(*)?
  2. why sizeInBytes is necessary,isn't that available by strlen(buffer)?
compile-fan
  • 16,885
  • 22
  • 59
  • 73

3 Answers3

4

Any function suffixed with _s under msvc is a secure function, this means it makes no assumptions about the integrity of the data passed. For this very reason the length of the string is required, because you can't assume its null terminated, or terminated at all (you might also only want half the string, but thats a side effect).

The secure functions all return error codes so that they can be checked without the possibility of faulting, and due to this any returns need to be sent via pointers. And seeing as the non-secure version of strdup & dupenv return a char*, you get a double indirection so that the pointer to the variable you pass gets the address of the allocated buffer.

Necrolis
  • 25,836
  • 3
  • 63
  • 101
0

No, it's asking for the address of a character pointer. The method will allocate the necessary space to hold the variable's value and set the value of your pointer to it, otherwise NULL. Refer to the example code down the page:

http://msdn.microsoft.com/en-us/library/ms175774(v=VS.80).aspx

Matt
  • 339
  • 1
  • 5
  • @Matt,why is `sizeInBytes` necessary,isn't that available by `strlen(buffer)`? – compile-fan May 29 '11 at 04:19
  • sizeInBytes tells you the size (number of bytes) of the character pointer that was allocated, this pattern is used because in unicode versions of the function, a character is not a single byte, it is two bytes because of UTF-16. So yes in your case strlen on the char * would return the correct value, in unicode it would be wcslen(buffer), or for depending on the compiler flags, it could be tcslen if using tchar which determines whether unicode or ansi at compile time. – Matt May 29 '11 at 04:24
  • @matt: the msvc crt already has unicode and multibyte versions of `strdup`, so why on earth would you use the ascii version for utf-16? (aka there is no such pattern, if your using utf, you better be using the unicode functions), see: http://msdn.microsoft.com/en-us/library/y471khhc(v=vs.80).aspx – Necrolis May 29 '11 at 05:13
  • @Necrolis, I wasn't informing anyone to mix use of multibyte and single byte functions, but the method that compile-fan is using is not unicode. I was saying that the second parameter returns the number of bytes allocated to inform the user of the size of the buffer. What I was trying to point out to compile-fan was that you can't always expect to get 1 byte for 1 character, as in the case of unicode methods, this would return 2 bytes for every character. – Matt May 29 '11 at 05:45
  • @Matt,if you take the encoding into account ,`sizeInBytes` is still not enough,say,you still have no idea how to get its nth bytes,simply by `buff[n]` will fail. – compile-fan May 29 '11 at 06:01
  • I think this can be explained with an example. Let's say someone gives you a buffer like above, but instead of giving you the actually pointer type, they give it to you as CONST PVOID. If you were to give me a count of characters, this would be useless to me, but if you gave me a count of bytes, I could use it to determine the type of text in the buffer which is exactly what the method BOOL IsTextUnicode does, it takes a void pointer to a buffer, and requires a count of bytes to know the size of the buffer to test. It is in these instances where count of bytes is more useful than Cch. – Matt May 29 '11 at 06:19
  • @Matt: that makes more sense, though I still think one should be using unicode if your expecting *not* to get ansi back, imo best way as you say is using tchar.h instead. just a slight errata to my comment, should be `dupenv`, not `strdup` (though technically the latter can be used to implement the former), correct link is: http://msdn.microsoft.com/en-us/library/ms175774(v=vs.80).aspx – Necrolis May 29 '11 at 06:29
0

In this context, the type char** is a pointer to a pointer to an array of chars. (It can also mean a pointer to a pointer to a single char, but that's not how it's used with _dupenv_s()).

The _dupenv_s() function allocates an array of chars by asking the operating system to reserve some chunk of memory big enough to hold it. The operating system reserves a chunk of memory and gives the _dupenv_s() function the address of this newly-allocated char array. The _dupenv_s() function stores the address of this array into a char* variable, because it's a pointer to an array of chars.

Now, the function has to pass this char* value out to the caller so the calling code can use it. The return value is already used to return an error code, so that can't be used. But let's say that the caller has a char* variable ready to receive the address to the allocated buffer.

If the _dupenv_s() function knows where the caller's char* variable is located, then the function can go ahead and fill the caller's char* variable with the correct value. To do that, the caller needs to pass the address of the caller's char* variable. That is, you need to pass a pointer to a pointer to an array of chars. That means a char** must be passed.

Note that's also the reason why sizeInBytes is a size_t*. The caller has a variable size_t, and the caller can pass the address of the variable to the function as a size_t* so that the function can fill the variable with the correct value.

While it may be true that strlen(buffer) == sizeInBytes, the strlen() function determines the length of the string by counting the number of characters until it sees a null-terminator. The amount of time required for strlen() to complete is linear to the number of characters, i.e. it's not constant. Why not skip the trouble of requiring the caller to do that and just provide the size directly?


If pointers still confuse you (and they are confusing at times), this Stack Overflow answer can be of assistance.

Community
  • 1
  • 1
In silico
  • 51,091
  • 10
  • 150
  • 143
  • I've no doubt with the `char **` thing now,but still has problem with the `sizeInBytes`.When is that info helpful? – compile-fan May 29 '11 at 06:03