【问题标题】:Why difference between 2 address is not multiple of element size为什么2个地址之间的差异不是元素大小的倍数
【发布时间】:2022-01-06 01:57:58
【问题描述】:

我不明白为什么 var 来了 6,它是如何计算的

#include <iostream>
using namespace std;
  
int main()
{
    char *A[] = { "abyx", "dbta", "cccc"};
    int var = *(A+1) - *A+1;
    cout << "1: " << (*(A+1)) << "\n";
    cout << "2: " << (*A+1) << "\n";
    cout << "char: " << var << "\n";
    cout << &A[0][1] - &A[1][0] << std::endl;
}

【问题讨论】:

  • 这两个项目不是*(A+1)*A+1 - 这两个项目是*(A+1)*A,所以差异是5(不是6),因为每个字符串中有5 个字符(不要忘记每个字符串末尾的 '\0'。
  • 好问题。对此的全面分析并非易事——您也处于未定义行为的边缘。我无法回答,因为我整晚都和可怜的孩子一起熬夜!
  • 数组元素之间的距离是&amp;A[1] - &amp;A[0] 或等价的A + 1 - A,这显然是1。你减去的是数组元素的值,而不是它们的位置。 (如果你改用int 的数组,问题可能会变得更清楚。)

标签: c++ pointers pointer-arithmetic chararray


【解决方案1】:

首先,此代码不是格式良好的 C++。你所拥有的是一个 pointers 数组,其中每个指针都保存一个字符串文字的地址。因为指针是非常量的,而字符串字面量是常量,所以任何明智的 C++ 编译器至少应该发出警告。

但无论如何,你所拥有的是一个在内存中可能看起来像这样的数组(在 64 位系统上):

// char *A[] = { "abyx", "dbta", "cccc" };

        01234567
       +--------+
0x0000 | A[0]   | ----> address of "abyx\0"
       +--------+
0x0008 | A[1]   | ----> address of "dbta\0"
       +--------+
0x0010 | A[2]   | ----> address of "cccc\0"
       +--------+

数组中的每个单元格都有一个指针值。它指向内存中的某个位置,指向您的程序存储这些字符串文字的位置。为了预示,你不知道它是在哪里做的,也不知道它们是如何排列的。

让我们比较一下它是否被定义为一个固定大小的 char 值数组:

// char B[][5] = { "abyx", "dbta", "cccc" };

        01234567
       +--------+
0x0000 |abyx~dbt| (the value '~' denotes a NUL byte)
       +--------+
0x0008 |a~cccc~?|
       +--------+

您的编译器似乎完全是偶然(并且绝不保证),像第二个示例一样在内存中安排了字符串文字,因此您最终得到了类似的结果:

char B[][5] = { "abyx", "dbta", "cccc" };
char *A[] = { B[0], B[1], B[2] };

让我们暂时把它放在一边(但请记住)并谈谈您的var 计算:

int var = *(A+1) - *A+1

您已将这些内容与空格组合在一起,但您需要注意,同一嵌套级别的加法和减法运算符将从左到右进行计算。如果我添加一个荒谬的括号来说明评估的顺序,实际上是这样的:

int var = ((*(A+1)) - (*A)) + (1);

所以它的作用是取指针A[1],减去指针A[0],然后加1。因为纯粹是运气,这些指针是由你的编译器排列的,就像数组B一样,然后你得到5 - 两个以 NUL 结尾的字符串指针之间的字符差,加 1,即 6。

如果你真的想从*(A+1) 中减去值*A+1,那么你需要把它放在括号中:

int var = *(A+1) - (*A+1);  // equivalent to *(A+1) - *A - 1

但是,由于您对不相关的指针进行算术运算的方式,结果值仍然不能保证。

让我们回过头来看看为什么我会费尽心思提取一些内存并与其他名为B 的数组进行比较。两个原因:

  1. 为了说明您的程序中使用的这些字符串文字的地址是不可预测的(因此,指针算术具有未定义的行为)

  2. 显示该数据的一种可能表示形式(如果您按照我定义 B 的方式定义 A可以明确表示)并确保您了解字符串在内存中以 NUL 结尾(意味着分配了一个额外的字符)。

希望这能消除一些困惑。

【讨论】:

  • 不错的答案。要是我能借你一天就好了!
猜你喜欢
  • 2017-10-16
  • 2014-10-20
  • 2013-03-27
  • 2017-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多