Char 数组通过指针复制时具有不同的地址

问题描述 投票:0回答:1

我想做的是欺骗类成员变量的常量性。所以我有以下代码:

“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'; // I would also like to set it to a whole string, but that doesn't work, it would work if it was std::string, not char *, maybe char ** would work?
//  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

因此该字符串和 StringView 中的字符串具有完全相同的地址。这种情况在 cmake 和 gcc 上都会发生,但 main.cpp 中的指针却不会。这是为什么?

当我取消注释代码行时,我得到:

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

现在这 3 个地址都有不同的地址。这是为什么?有什么办法可以欺骗这个,这样我就可以通过 const 限定符而不使用明显的

const_cast<>()
?这在 c 中也不起作用(使用结构、删除显式、使用 printf 等)。

我知道不在对象中的 const 字符串(例如 StringView sv)存储在与变量内存不同的只读内存中。就像在全局变量/静态变量空间中一样,这就是为什么我将 str 设置为 const char[] 的原因,并且它仍然位于其他一些内存中,该内存会根据我是否更改该内存和其他内容而发生变化。 另外,我没有使用 std::string,因为它有一个重载的运算符 =,这会破坏 const-ness,因为在这种情况下它是不同的。

默认情况下 _begin 和 _end 应该是私有的,我只是将它们公开以检查地址。

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;
}
c++ pointers constants memory-address
1个回答
0
投票

在这些声明中

char str[] = "猫"; StringView sv(str);

指针 str 指向的字符串文字占用其自己的内存范围,而对象 sv 也拥有自己的内存范围。因此这些陈述

std::cout << "Pointer to StringView: " << pointer << "\n";

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

输出不同内存范围的地址。

本声明

*(char *) pointer = 'b';

仅调用未定义的行为。

© www.soinside.com 2019 - 2024. All rights reserved.