通过指针访问 char*

Posted

技术标签:

【中文标题】通过指针访问 char*【英文标题】:Accessing a char* through a pointer 【发布时间】: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++ 中,结构是成员默认公开的类。 【参考方案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,它会为您处理内存管理。 (这是最简单的解决方案!)

【讨论】:

以上是关于通过指针访问 char*的主要内容,如果未能解决你的问题,请参考以下文章

尝试从常量 char * 类型的指针复制数据时出现“超出内存访问”错误。为啥?

为啥我仍然可以在字符串范围之外访问 std::string::c_str() 返回的 char 指针? [复制]

如何访问存储在char数组中的整数?

取消引用已删除的指针总是会导致访问冲突?

初始指针

给定一个指向内存地址的未知指针访问结构 - C