【问题标题】:Accessing a char* through a pointer通过指针访问 char*
【发布时间】:2013-08-09 11:13:45
【问题描述】:

这是我的问题。

我有一个定期修改 char* 的类。

还有另一个类,需要能够读取这个值。所以我想将 char* 传递给第二个类的构造函数,以便它可以在需要时检查值。

让我举一个我对另一个参数的实现示例,它是布尔类型:

在A类中:

bool f_valid = false; // global

m_eventCatcher.addProxy(porting::shared_ptr<CallbackProxy>(new handleCall(&f_valid))); 

在 B 类中:

struct handleCall 
{
    bool* m_dataValid;

    handleCall(bool* result) 
    {
        // saving the pointer to the boolean that I want to change
        m_dataValid = result; 
    }

    method()
    {
        if (smth) 
        { 
            (*m_dataValid) = false;
        }
    }
};

到目前为止一切顺利 - 这似乎有效。两个类都可以更改和访问此布尔值。

现在我需要用 char* 做同样的事情(我不能使用字符串,所以我想这是存储短文本的最佳方式,比如 url 地址?)。

这就是我写的:

A 类:

const char* f_url = "blah blah"; // global

m_eventCatcher.addProxy(porting::shared_ptr<CallbackProxy>(new handleCall2(&f_url)));

C类:

struct handleCall2 
{
    char ** m_url;

    handleCall2(char** url)
    {
        // saving the pointer to the char*
        m_url= url;
        std::cout << (*m_url) << std::endl; // prints out url fine
    }

    method() 
   {
        std::cout << (*m_url) << std::endl; // by this time the value has been changed by ClassA, and I print out some rubbish - symbols, squares, etc.
    }
};

我猜问题是因为字符串变了,它的地址也变了?我真的很困惑 - 谁能告诉我发生了什么,在这种情况下我应该怎么做?

更新:

看起来问题在于我如何修改 char*:

f_url = "new text"; // works fine

f_url = fileUrl.c_str(); // doesn't work! I get rubbish in the value when I try to access it from ClassB

strcpy(m_url, fileUrl.c_str()); // I also removed const from the variable and tried this - got a crash "access violation using location" :(

还有其他方法可以将字符串的值写入 char * 吗?

【问题讨论】:

  • 哦,还有一件事:std::string 在处理字符串方面比原始指针要好得多。
  • “现在我需要对char* 做同样的事情(我不能使用字符串,[...])。” .但是,我想知道为什么你不能使用std::string
  • 您使用的 C++ 编译器 不是 会向您发出关于发送地址 const char * 并将其存储在 char ** 中的警告/错误??跨度>
  • 如果你不能使用std::string,那么std::vector呢?是的,一个向量完全能够保存一个字符串,它只是不能轻松地进行“字符串”操作,但仍然可能比原始指针更好。
  • 在 C++ 中,结构是成员默认公开的类。

标签: c++ c pointers char-pointer


【解决方案1】:

我认为访问char * 没有任何问题。

我编写了一个示例代码,它对我有用。可能是您的问题:

顺便说一句,这是我的代码供您参考:

#include <iostream>

class ClassThatPrints
{
private:
    const char **m_url;

public:
    ClassThatPrints(const char ** url)
    {
        m_url = url;
        std::cout << (*m_url) << std::endl;
    }

    void PrintAfterModify(void)
    {
        std::cout << (*m_url) << std::endl;
    }
};

class ClassThatModifies
{
private:
    const char *m_charPointer;
    ClassThatPrints *m_ClassThatPrints;
public:
    ClassThatModifies()
    {
        m_charPointer = "this is the original string";
        std::cout << "Printing before modification:" << std::endl;
        m_ClassThatPrints = new ClassThatPrints(&m_charPointer);
    }

    ~ClassThatModifies() {
        delete m_ClassThatPrints;
    }

    void ModifyStringAndPrint(void)
    {
        m_charPointer = "this is a modified string";
        std::cout << "Printing after modification:" << std::endl;
        m_ClassThatPrints->PrintAfterModify();
    }
};

int main()
{
    ClassThatModifies objClassThatModifies;
    objClassThatModifies.ModifyStringAndPrint();

}

【讨论】:

  • 你是对的 - 这确实有效!我当时做的一切都是正确的,问题一定出在其他地方……
  • 好吧,但是这段代码与问题中解释的不同。他说他在修改指针的值,你只是在你的“修改方法”中分配了一个新的指针,这是一个很大的不同,你修改是一个合法的操作,同时修改那个地址的字符的值(这就是他的解释听起来对我来说是绝对不正确的。
【解决方案2】:

如果你有这样的事情:

void addHandler() {
    const char* f_url = "blah blah";
    m_eventCatcher.addProxy(porting::shared_ptr<CallbackProxy>(new handleCall2(&f_url)));
}

void doStuff() {
    addHandler();
    m_eventCatcher.callProxy();
}

那么问题是当 addHandler 返回时 f_url 超出范围。 如果是这种情况,那么你的 bool 版本也有问题,(*m_dataValid) = false; 覆盖了其他一些数据。

【讨论】:

  • 不,f_url 和 bool 并没有超出范围——它们是在所有方法之外的类内部定义的。
【解决方案3】:
const char* f_url = "blah blah";

这个声明意味着你有一个指向常量字符串的指针。所以你不能这样做

strcpy(f_url, "hello world"); // copy to the preallocated place

但你可以

f_url = "hello world"; // do pointer assignment

如果你有下一种情况:

class ClassA {
const char* f_url = "blah blah";
public: 
    void method() {
        f_url = "hello world";
    }
};

class ClassB {
    char** m_url;
public:
    void print() {
        cout << (* m_url); // m_url points to a string, allocated on the stack of ClassA::method()
    }
};

请记住,字符串"hello world" 分配在ClassA::method() 的堆栈上。当ClassA::method() 退出时,该指针不再有效。解决我接下来提出的问题:

class ClassA {
static const int max_path = 256; 
char f_url[max_path];
public: 
    void method() {
        strcpy(f_url, "hello world");
    }
};

class ClassB {
    char** m_url;
public:
    void print() {
        cout << (* m_url);
    }
};

【讨论】:

  • 我没有使用 strcpy
  • grrr 再次按下输入太早。那么您建议如何将 char[] 发送到 ClassB 以及如何将其存储在 char** 中?...
  • 只需重用您已有的代码。 char[] 与 char* 相同。
  • 当我尝试将 f_url(即 char f_url[256])传递给需要 const char**(新处理程序(&f_url);)的函数时,出现编译错误:'无法转换参数 3 从 'char (*)[256]' 到 'const char **'
  • 如果您不更改 f_url 指针,那么您可以将 char* 传递给 new_handler 构造函数。并将指针作为 m_url 存储在 ClassB 中。
【解决方案4】:
const char* f_url = "blah blah"; // global

也许你误解了这条线? const 限定符是当你放置它时,指的是它左边的关键字。 允许将其作为第一个关键字,但只有这样,它才指的是它的权利;) 所以你的声明说: (const char) *f_url 所以它是一个指向 const char 的指针。 我猜(我不知道你在那个类中修改它的值的方式是什么)你自己得到它,为什么修改 const char 值可能会以垃圾输出结束,不是吗? 我建议您将其声明为

char *const f_url = "blah blah";

这是

char (* const) f_url

所以 f_url 是一个指向可修改区域的常量地址值。 但即使这样也没有多大意义,因为“blah blah”是一个常量内存区域的地址,所以你不能修改 ("blah blah")[count] = 任何东西; 无论如何。

所以你应该这样做

char *const f_url = ThisIsACharArray[count];

并访问 char 数组,也就是关于 f_url 的字符串。

或者对你来说更好的方法,就像我猜的那样,只是将 const 保留在声明之外并由你自己分配可修改的内存;)

【讨论】:

    【解决方案5】:

    字符串实际上并未存储在f_url 中。该字符串存储在其他地方f_url 是指向该其他地方的指针。

    如果你这样做:

        f_url = "new text"; // works fine
    

    当你的程序被编译时,它会在其中的某处包含字符串"new text"f_url 将指向那个 - 指向程序本身中间的一些内存。


        f_url = fileUrl.c_str(); // doesn't work! I get rubbish in the value when I try to access it from ClassB
    

    fileUrl 是一个 std::string。 fileUrl 有自己的指向字符串的指针,c_str 返回。由于fileUrl 负责管理此字符串,因此当fileUrl 超出范围时,内存可能会被重用于其他用途 - 它不知道您仍在使用该内存。


        // I assume you meant f_url here, not m_url
        strcpy(f_url, fileUrl.c_str()); // I also removed const from the variable and tried this - got a crash "access violation using location" :(
    

    这取决于f_url 实际指向的内容。如果f_url 指向程序中间的一些内存(如f_url = "blah blah";),那么这将崩溃。通常,这表明存在错误,因此操作系统不会允许您这样做。

    如果允许,这可能会发生:

    char *s = "hello world";
    strcpy(s, "abracadabra");
    
    printf("hello world"); // prints "abracadabra"
    


    您需要做的是获取自己的内存块来保存字符串,并在完成后释放它:

    f_url = new char[fileUrl.length() + 1];
    strcpy(f_url, fileUrl.c_str());
    
    // when you don't need the string any more
    delete [] f_url;
    

    或:

    f_url = strdup(fileUrl.c_str());
    
    // when you don't need the string any more
    free(f_url);
    

    或者只是将f_url 设为std::string,它会为您处理内存管理。 (这是最简单的解决方案!)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-11-26
      • 2021-12-11
      • 1970-01-01
      • 1970-01-01
      • 2011-02-03
      • 1970-01-01
      相关资源
      最近更新 更多