0

我有一个 const char 指针,我知道它肯定来自一个字符串。例如:

std::string myString = "Hello World!";
const char* myCstring = myString.c_str();

在我的情况下,我知道 myCstring 来自一个字符串,但我不再有权访问该字符串(我从函数调用中收到了 const char*,我无法修改函数的参数列表)。

鉴于我知道 myCstring 指向现有字符串的内容,是否有任何方法可以安全地访问它源自的父字符串的指针?例如,我可以做这样的事情吗?

std::string* hackyStringPointer = myCstring - 6; //Along with whatever pointer casting stuff may be needed

我担心的是,字符串的内容可能无法保证存储在某些或所有平台等的连续内存中。

4

4 回答 4

2

鉴于我知道 myCstring 指向现有字符串的内容,是否有任何方法可以安全地访问它源自的父字符串的指针?

不,没有办法从指向属于 a 的字符数据std::string*的指针中获取有效指针。const char*std::string

我从函数调用中收到了 const char*,但无法修改函数的参数列表

在这种情况下,您唯一的选择是,如果您可以将指向std::string自身的指针作为实际const char*指针传递,但这只有在调用您的函数的任何内容都不能以const char*任何方式解释时(当然也不是以空结尾的 C字符串),例如:

void doSomething(void (*func)(const char*), const char *data)
{
    ...
    func(data);
    ...
}
void myFunc(const char *myCstring)
{
    std::string* hackyStringPointer = reinterpret_cast<std::string*>(myCstring);
    ...
}

...

std::string myString = "Hello World!";
doSomething(&myFunc, reinterpret_cast<char*>(&myString));
于 2019-10-22T20:30:09.063 回答
1

您无法const char*将从std::string::c_str()中获得的 a转换为std::string*. 你不能这样做的原因是因为c_str()返回一个指向字符串数据的指针,而不是字符串对象本身。

如果你想得到std::string所以你可以使用它的成员函数,那么你可以做的就是包装myCstring在一个std::string_view. 这是一个非复制包装器,可让您将 c 字符串视为std::string. 为此,您需要类似的东西

std::string_view sv{myCstring, std::strlen(myCstring)};
// use sv here like it was a std::string
于 2019-10-22T20:44:10.293 回答
0

是的(似乎),尽管我同意如果我需要这样做,这可能表明我的代码通常需要重新修改。尽管如此,答案似乎是字符串指针位于 c_str() 返回的 const char* 之前的 4 个单词,并且我确实从属于字符串的 const char* 恢复了 string*。

    #include <string>
    #include <iostream>
    std::string myString = "Hello World!";
    const char* myCstring = myString.c_str();
    unsigned int strPtrSize = sizeof(std::string*);
    unsigned int cStrPtrSize = sizeof(const char*);
    long strAddress = reinterpret_cast<std::size_t>(&myString);
    long cStrAddress = reinterpret_cast<std::size_t>(myCstring);
    long addressDifference = strAddress - cStrAddress;
    long estStrAddress = cStrAddress + addressDifference;
    std::string* hackyStringPointer = reinterpret_cast<std::string*>(estStrAddress);

    cout << "Size of String* " << strPtrSize << ", Size of const char*: " << cStrPtrSize << "\n";
    cout << "String Address: " << strAddress << ", C String Address: " << cStrAddress << "\n";
    cout << "Address Difference: " << addressDifference << "\n";
    cout << "Estimated String Address " << estStrAddress << "\n";
    cout << "Hacky String: " << *hackyStringPointer << "\n";

    //If any of these asserts trigger on any platform, I may need to re-evaluate my answer
    assert(addressDifference == -4);
    assert(strPtrSize == cStrPtrSize);
    assert(hackyStringPointer == &myString);

其输出如下:

String* 的大小 4,const char* 的大小:4

字符串地址:15725656,C字符串地址:15725660

地址差异:-4

估计字符串地址:15725656

哈奇字符串:你好世界!

到目前为止它似乎有效。如果有人可以证明一个字符串与其 c_str() 之间的地址差异可以在同一平台上随时间变化,或者如果不能保证字符串的所有成员都驻留在连续的内存中,我会将我的答案更改为“否。”

于 2019-10-23T15:22:08.450 回答
-1

这个参考

返回的指针可能会因进一步调用修改对象的其他成员函数而失效。

您说您从函数调用中获得了 char*,这意味着您不知道同时字符串会发生什么,对吗?如果您知道原始字符串没有更改或删除(例如超出范围并因此被破坏),那么您仍然可以使用 char*。

但是,您的示例代码有多个问题。你想这样做:

std::string* hackyStringPointer = myCstring - 6;

但我认为你的意思是

char* hackyStringPointer = myCstring;

一,您不能将 char* 转换为 string*,其次您不想在 char* 开始之前进行。char* 指向字符串的第一个字符,您可以使用它来访问直到尾随 0 字符的字符。但是你不应该在第一个字符之前或后面的 0 字符之后,因为你不知道那个内存中有什么,或者它是否存在。

于 2019-10-22T20:36:19.137 回答