You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

字符数组指针拷贝地址异常及绕过类成员const限定符的问询

关于绕过const限定性的内存地址异常问题

C++代码示例

StringView.hh

#pragma once
#include <cstring>

class StringView {
public:
  const char* _begin = nullptr;
  const char* _end = nullptr;

  explicit StringView(const char* str) : _begin(str), _end(str + strlen(str)) {}
};

main.cpp

#include <iostream>
#include "StringView.hh"

int main() {
  char str[] = "cat";
  StringView sv(str);

  std::cout << str << '\n';

  void *pointer = reinterpret_cast<void *>(&sv);
//  *(char *) pointer = 'b'; // 我还想把它设置成整个字符串,但这样不行,如果是std::string就可以,但char*不行,或许char**可以?
//  std::cout << str << '\n';

  std::cout << "Pointer to StringView: " << pointer << "\n";
  std::cout << "String: " << (void *)str << "\n";
  std::cout << "String from StringView _begin: " << (void *)sv._begin << "\n";

  return 0;
}

未注释代码时的运行结果

cat
Pointer to StringView: 0xe25bffde0
String: 0xe25bffdf4
String from StringView _begin: 0xe25bffdf4

此时str和StringView::_begin指向同一地址,但取消注释*(char *) pointer = 'b';后,运行结果变为:

cat
cat
Pointer to StringView: 0x81491ffc50
String: 0x81491ffc64
String from StringView _begin: 0x81491ffc62

三者地址均发生变化,请问该现象的原因是什么?是否存在不使用const_cast即可绕过const限定的方法?


C语言代码示例

#include <stdio.h>
#include <string.h>

struct StringView {
  const char* _begin;
  const char* _end;
};

struct StringView create(const char *str) {
  struct StringView a = {str, str + strlen(str)};
  return a;
}

int main() {
  char str[] = "cat";
  struct StringView sv = create(str);

  printf("%s\n", str);

  void *pointer = (void *) &sv;
  *(char *) pointer = 'b';
  printf("%s\n", str);

  printf("Pointer to StringView: %p\n", pointer);
  printf("String: %p\n", (void *)str);
  printf("String from StringView _begin: %p\n", (void *)sv._begin);

  return 0;
}

注:我知道非对象内的const字符串存储在只读内存中,因此未将str声明为const char[],但仍出现内存地址变化的情况;且未使用std::string,因其重载赋值运算符会破坏const限定性。


问题解答

1. 地址异常的原因

你执行的*(char *) pointer = 'b';是直接修改了StringView对象本身的内存字节,而非修改_begin指向的字符串内容:

  • 64位系统中,StringView的两个const char*成员各占8字节,对象总大小为16字节。
  • pointer指向sv的起始地址,*(char*)pointer = 'b'修改的是_begin指针的第一个字节。原本_begin存储的是str的地址,修改后指针值被破坏,变成了错误地址,因此sv._begin的输出地址和原str地址不一致。
  • 至于StringView自身地址变化,是程序每次运行时栈内存布局的正常波动,和修改操作无直接关联,核心问题是_begin指针被篡改。

2. 不使用const_cast绕过const限定的方法

仅当const char*指向的是非const内存(比如你的_begin指向char[]类型的str)时,以下操作是合法的:

  • C++方式:将指针转换为char**,间接修改目标字符串:
    char** begin_ptr = reinterpret_cast<char**>(&sv._begin);
    **begin_ptr = 'b'; // 修改str的第一个字符
    
    或者直接转换指针后修改:
    char* mutable_str = reinterpret_cast<char*>(sv._begin);
    mutable_str[0] = 'b';
    
  • C语言方式:类似地转换指针类型修改:
    char** begin_ptr = (char**)&sv._begin;
    **begin_ptr = 'b';
    

注意:如果const char*指向的是真正的const字符串(比如const char* str = "cat"),修改其指向的内存属于未定义行为,可能导致程序崩溃或异常。


内容的提问来源于stack exchange,提问作者ashamedgap

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 15:44:51