aromahola
aromahola

Reputation: 190

why passing string to a function which accepts LPSTR does noy work?

Following code gives empty string and length = 0, but while debugging I can see the childDisplayName has correct name.

    CHAR fileSystemName[MAX_PATH + 1] = { 0 }; 
    DWORD serialNumber = 0; DWORD maxComponentLen = 0; 
    string childDisplayName = "";
    DWORD fileSystemFlags = 0; 
    if (GetVolumeInformationA("C:\\", // L"\\MyServer\MyShare\"
        (LPSTR)&childDisplayName, MAX_PATH+1,
        &serialNumber, &maxComponentLen,
        &fileSystemFlags, fileSystemName, sizeof(fileSystemName)) == true)
    {
        
        cout << childDisplayName << "length: "<<childDisplayName.length()<<endl;
    }


following code works fine. I am not getting why LPSTR works when I pass char array and does not work when I pass a string.

    CHAR fileSystemName[MAX_PATH + 1] = { 0 }; 
    DWORD serialNumber = 0; DWORD maxComponentLen = 0; 
    CHAR childDisplayName[MAX_PATH + 1] = { 0 };
    DWORD fileSystemFlags = 0; 
    if (GetVolumeInformationA("C:\\", // L"\\MyServer\MyShare\"
        childDisplayName, MAX_PATH+1,
        &serialNumber, &maxComponentLen,
        &fileSystemFlags, fileSystemName, sizeof(fileSystemName)) == true)
    {
        
        cout << childDisplayName << "length: "<<strlen(childDisplayName)<<endl;
    }

Upvotes: 0

Views: 448

Answers (2)

Zeus
Zeus

Reputation: 3890

In first code snippet, I cannot get the correct name of childDisplayName.

enter image description here

Although it seems to have several characters, but an exception is triggered when I want to output it.

enter image description here

So you passed a wrong address to the GetVolumeInformationA.Because the address of a string is not the address of the characters

You can test like the following code:

string s("test");
CHAR cs[] = "test";
cout << (void*)&s << endl;
cout << (void*)&s[0] << endl;

cout << (void*)&cs << endl;
cout << (void*)&cs[0] << endl;

Output: enter image description here

As @churill says, std::string only manages a dynamic array of characters.So you can not pass the address of string to the function.

And according to MSDN:

If you modify the contents of the string returned by the const overload of data, the behavior is undefined. You also get undefined behavior if the terminal null character is changed to any other value. The returned pointer may be invalidated if a non-const reference to the string is passed to a standard library function. It can also be invalidated by a call to a non-const member function.

So even if you really succeed in passing childDisplayName.data() into the function. This is also an undefined behavior.I recommend that you pass in the parameter types required by the function correctly, instead of trying to pass other undefined or untyped behaviors, which will cause you a lot of confusion.

Upvotes: 0

Frodyne
Frodyne

Reputation: 3973

string childDisplayName = ""; creates an empty empty string (zero size and unspecified capacity). Using that as a data-buffer to write into is not likely to go well.

You can do this: string childDisplayName(MAX_PATH + 1, ' '); to create a string with the proper space allocated.

Secondly, as @churill wrote, the address of a string is not the address of the characters in it. Instead use childDisplayName.data() to get a char* to the internal storage of the string that you can write in - but make sure not to write outside the range [data(); data() + size()).

EDIT: A bit on how std::string and .data() works.

I made a small example program:

#include<iostream>
#include<string>

void print(const std::string& s)
{
    std::cout << "String size: " << s.size() << '\n';
    std::cout << "String contents: >>" << s << "<<\n";
    std::cout << "String as c-string: >>" << s.c_str() << "<<\n";
    std::cout << '\n';
}

int main() {
    std::string bla = "";
    auto bladata = bla.data();
    for (int i = 0;i < 5;++i) {
        bladata[i] = '!';
    }
    print(bla);

    std::string bla2(10, '\0');
    auto bla2data = bla2.data();
    for (int i = 0;i < 5;++i) {
        bla2data[i] = '!';
    }
    print(bla2);
}

When run this outputs:

String size: 0
String contents: >><<
String as c-string: >>!!!!!╠╠╠╠╠╠╠╠╠╠╠<<

String size: 10
String contents: >>!!!!!     <<
String as c-string: >>!!!!!<<

What is going on here? First thing to notice is that an empty std::string is created with zero size and unspecified capacity - looking in my debugger, I know that on my system that unspecified capacity is 15, so as long as I don't go beyond that nothing should crash. But this is obviously not something you should do in real code (writing here is strictly undefined behavior).

This means that the bla string is size 0, and contains a 15 character char buffer, where I set the first 5 characters to '!'. So when I try to print its size() or print it as a std::string it is identical to any regular empty string. However, if I use .c_str() to print the internal buffer directly, then it prints as any old char* and just prints whatever is in memory until it encounters a null-character.

On the other hand, bla2 is initialized to contain 10 null-characters. That means that its size is 10, and its capacity is at least 10 (in my case it happens to also be 15). This means that after the loop it still reports as size 10, regardless of how many '!'s I put into the buffer, and when I print it as a std::string it prints all the 10 characters it contains; both the 5 '!'s and the 5 '\0's. However, when I print it as a char* it prints the 5 '!'s and then stop as soon as it encounters a null-character.

Upvotes: 1

Related Questions