【问题标题】:My char pointer points to invalid value after being cast from int*从 int* 转换后,我的 char 指针指向无效值
【发布时间】:2013-06-29 17:24:00
【问题描述】:

我正在学习 C 编程语言,我刚刚开始学习带指针的数组。我对这个问题有疑问,我希望输出必须是 5 但它是 2,谁能解释一下原因?

int main(){
   int arr[] = {1, 2, 3, 4, 5};
   char *ptr = (char *) arr;
   printf("%d", *(ptr+4));
   return 0;
}

【问题讨论】:

  • 如果有人对这个问题投了反对票,那么请提及您的评论,这对我来说很难,希望对其他人不会...... :)
  • 你有一个“int”数组,但有一个“char”指针。
  • +1 在您的公告中 :)
  • 顺便说一句,你会期望你的输出是 5,而不是 4:*ptr 指向数组的第一个元素,即 1,在它之后的四个元素你有 5. 5如果你定义了int *ptr = (int *) arr;
  • 我建议将此问题的主题更改为更有用的内容。这个问题将来可能会被问到。我建议 我的 char 指针在从 int* 投射后指向有效值“或类似的东西。我会编辑这个问题,但赞成票太多,我不想搞砸这么受欢迎的问题。

标签: c arrays pointers


【解决方案1】:

假设 int 为 32 位(4 字节)的小端架构,int arr[] 的各个字节如下所示(低地址处的最低有效字节。所有值均为十六进制):

|01 00 00 00|02 00 00 00|03 00 00 00|04 00 00 00|05 00 00 00
char *ptr = (char *) arr;

现在,ptr 指向第一个字节 - 因为您已转换为 char*,所以它被视为 char 数组:

|1|0|0|0|2|0|0|0|3|0|0|0|4|0|0|0|5|0|0|0
 ^
 +-- ptr

然后*(ptr+4)访问char数组的第五个元素,返回对应的char值:

|1|0|0|0|2|0|0|0|3|0|0|0|4|0|0|0|5|0|0|0
         ^
         +-- *(ptr + 4) = 2

因此,printf() 打印出2

Big Endian 系统上,每个int 中的字节顺序颠倒,导致

|0|0|0|1|0|0|0|2|0|0|0|3|0|0|0|4|0|0|0|5
         ^
         +-- *(ptr + 4) = 0

【讨论】:

  • 你混合你的字节序,小字节序在最低的内存位置有最低的。
  • 您对printf() 处理这种情况的描述不正确。它将第 5 个字符的值作为整数,而不是指向相同的指针。此外,正如 Joachim 所说,您的字节序被颠倒了。
【解决方案2】:

这是因为char 的大小是一,int 的大小是四。这意味着将4 添加到ptr 会使结果指向int 数组中的第二个条目。

如果您在大型 endian 系统上编译此代码,您将改为打印 33554432。

【讨论】:

  • 我以为字节序只适用于浮点数。您是否建议整数的行为方式相同?我不太确定。
  • 只要有一个使用超过 1 个字节的类型,就有一个问题是存储字节的顺序。
  • @Bathsheba Endianess绝对是一个整数问题。
  • @JoachimPileborg +1 - 我记得我总是把他们搞砸了:D
  • ... 而且,我认为您一开始是对的:在大端上,结果应该为零,因为您以char 访问第五个字节,而这个字节为零...对不起...
【解决方案3】:
int main(){
 int arr[] = {1,2,3,4,5};
 char *ptr = (char *) arr;
 printf("%d",*(ptr+4));
 return 0;
}

arr 的每个 case 都有 sizeof(int) 大小(在您的实现中可能是 4)。

由于ptr 是指向char 的指针,所以pointer arithmetic 使ptr + 4 指向&arr[0] 之后的4 个字节,可能是&arr[1]

在内存中,它看起来像这样:

Address | 0 1 2 3 | 4 5 6 7 | ...
Value   |  arr[0] |  arr[1] | ...

【讨论】:

    【解决方案4】:

    在生产代码中绝对不建议您这样做,但对于在学习过程中理解指针、强制转换等绝对是很好的,因此您的示例非常棒。那么,为什么你得到 2。这是因为你的数组是一个整数数组,取决于你的架构有不同的大小(在你的情况下,sizeof(int) 是 4)。您将 ptr 定义为 char 指针,char 的大小为 1 字节。指针算术(这就是您在编写ptr+4 时所做的)适用于指针引用的对象的大小,在您的情况下适用于字符。因此,ptr+4 距离数组的开头 4 个字节,因此位于 int 数组的第二个位置。这就对了。试试ptr+5,你应该得到0。

    【讨论】:

      【解决方案5】:

      在 32 位平台上,int 的大小是 char 的四倍。当您将 4 添加到 ptr 时,您将 ptr 指向的大小 的 4 倍添加到 ptr(它本身就是一个内存位置)。这恰好是int 数组中第二个元素的地址。

      在 64 位平台上,int 的大小是char倍;你的输出会很不一样。

      长话短说,您的代码不可移植,(另请参阅 Joachim Pileborg 的 re endianness 答案)但解开很有趣。

      【讨论】:

      【解决方案6】:

      由于您将 int* 转换为 char*,因此 ptr[0] = 1, ptr[4] = 2, ptr[8] = 3, ptr[12] = 4 , ptr[16] = 5 和所有其他等于 0。ptr+4 指向 ptr 数组中的第 4 个元素。所以结果是 2。

      【讨论】:

      • 这取决于系统的字节序。你没有解释为什么它会这样工作以及为什么它在你的机器上是正确的。
      【解决方案7】:
      int main(){
       int arr[] = {1,2,3,4,5};
       char *ptr = (char *) arr;
       printf("%d",*(ptr+4));
       return 0;
      }
      

      想象arr 存储在地址100(完全是哑地址)。所以你有了: arr[0] 存储在地址 100。 arr[1] 存储在地址 104 处。(由于类型为 int,所以是 +4) arr[2] 存储在地址 108 中。 arr[3]存储在地址112等处。

      现在你正在做char *ptr = (char *) arr;,所以ptr = 100(与arr 相同)。 下一条语句很有趣,特别是 printf 的第二个参数:*(ptr+4)。 请记住ptr = 100。所以ptr + 4 = 104,与arr[1] 相同的地址!所以它会打印arr[1]的值,即2。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-06-08
        • 2017-02-12
        • 2021-10-07
        • 2015-09-10
        • 2017-09-03
        • 2020-10-21
        • 1970-01-01
        • 2023-03-08
        相关资源
        最近更新 更多