【问题标题】:How does the expression ( arr[i+1] - arr[i] ) produce a decimal number same as the difference in indices?表达式 ( arr[i+1] - arr[i] ) 如何产生与索引差异相同的十进制数?
【发布时间】:2018-07-23 15:23:00
【问题描述】:

我有一个字符串数组arr[5][8] = {...}(每个字符串都已声明),我试图了解arr[3] - arr[2] 的值是什么以及它的类型是什么。我不明白为什么要以字节为单位考虑地址之间的差异,因为当我打印这个时:printf("%d\n" , names[2] - names[1]) 我得到8。

为什么会这样?下面是一个完整的代码示例:

#include <stdio.h>     
int main()
{
    char names[5][8] = { "Miri", "Tali", "Ronit", "Avigail", "Shlomit" };
    printf("%d\n", names[2] - names[1]);
    system("pause");
    return 0;
}

输出为8。

8 恰好是从names[1] 到names[2] 的距离(以字节为单位)(每个字符串中有 8 个字符,每个字符为 1 个字节)。但是我输入了%d,并认为这个距离将以这些字节的十进制表示形式打印出来。换句话说,我认为结果是8*255,因为1个字节可以表示的最大值是255,而这里我有8个字节(chars)。

【问题讨论】:

  • “我不明白为什么要以字节为单位考虑地址之间的差异” - 如果不以字节为单位考虑,那还有什么?以比特、公里还是升为单位?为什么是 8 * 255 而不是 8 * 256?什么是 255?

标签: c arrays string


【解决方案1】:

char 数组names 的内存视图将如下所示:

       names
  100  +-+-+-+-+-+-+-+-+
       |M|i|r|i|0|0|0|0|
  108  +-+-+-+-+-+-+-+-+
       |T|a|l|i|0|0|0|0|
  116  +-+-+-+-+-+-+-+-+
       |R|o|n|i|t|0|0|0|
  124  +-+-+-+-+-+-+-+-+
       |A|v|i|g|a|i|l|0|
  132  +-+-+-+-+-+-+-+-+
       |S|h|l|o|m|i|t|0|
       +-+-+-+-+-+-+-+-+

//100, 108.. are addresses

names[2] 是 Ronit 和 names[1] 是 Tali。
现在,希望你明白为什么names[2] - names[1] 会给出8,如果没有,请尝试将names 数组维度8 更改为9:

char names[5][9] = ...

并检查结果。

【讨论】:

    【解决方案2】:

    在您的情况下,names[i] 是一个字符数组,类型为 char[8]。

                    +-----------------------------------------------------------+
    names [0]       |                                                           |
                    +-----------------------------------------------------------+
                    1000    1001    1002    1003    1004    1005    1006    1007
    
                    +-----------------------------------------------------------+
    names [1]       |                                                           |
                    +-----------------------------------------------------------+
                    1008    1009    1010    1011    1012    1013    1014    1015
    
                    +-----------------------------------------------------------+
    names [2]       |                                                           |
                    +-----------------------------------------------------------+
                    1016    1017    1018    1019    1020    1021    1022    1023
    

    所以,当你说names[2] - names[1] 时,基本上,你减去了两个数组成员,有 8 个元素。

    换句话说,您要减去两个指针,每个指针都是指向数组类型第一个元素的指针,每个指针包含 8 个元素。因此,差值为 8。

    这与指针本身指向的内存位置指针中存储的值无关,您正在对指针进行操作,而不是指针指向的值。指针算术规则将适用于此。

    也就是说,要打印指针减法的结果,你应该使用%td as conversion specifier, the type would be ptrdiff_t。

    引用C11,第 6.5.6 章

    当两个指针相减时,都指向同一个数组对象的元素, 或数组对象的最后一个元素;结果是 两个数组元素的下标。 [....]

    【讨论】:

      【解决方案3】:

      为了完全理解这一点,您需要知道内存是如何寻址的,这个程序是如何存储在内存中的,等等。有关更多信息,请参阅此 -

      Difference between word addressable and byte addressable

      要回答您的问题,请考虑由单个块组成的内存,其中每个块的长度为 1 个字节。所以——

      8 it's exactly a distance from names[1] to names[2] in bytes(There are 8 chars in every string, every char is 1 byte)
      

      是正确的,这就是您在这里得到 8 作为答案的原因。

      thought that this distance will be printed in the decimal representation of these bytes
      

      255 不是这些字节的十进制表示。相反,它是每个字节可以容纳的最大值 (2^8 - 1)。我希望这会有所帮助。

      【讨论】:

        【解决方案4】:

        您的代码具有未定义的行为,因为您将值的类型与printf() 转换中指定的类型不匹配。区别的类型是ptrdiff_t,但%d需要int类型的值。

        不幸的是,您的其余推理很难理解。一个字节的最大值与两个地址的差异无关。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-07-31
          • 2021-01-26
          • 1970-01-01
          • 1970-01-01
          • 2021-09-10
          • 2011-11-03
          • 1970-01-01
          相关资源
          最近更新 更多