【问题标题】:Pointer Arithmetic in C [duplicate]C中的指针算术[重复]
【发布时间】:2014-10-09 18:27:32
【问题描述】:

我有以下代码。也许我还没有像我应该的那样理解指针算术,但为什么 int_pointer 递增 4 而不是 1? char_pointer为什么不加4而不是1?

 #include <stdio.h>

 int main() {
    int i;

    char char_array[5] = {'a', 'b', 'c', 'd', 'e'};
    int int_array[5] = {1, 2, 3, 4, 5};

    char *char_pointer;
    int *int_pointer;

    char_pointer = int_array; // The char_pointer and int_pointer now
    int_pointer = char_array; // point to incompatible data types.

    for(i=0; i < 5; i++) { // Iterate through the int array with the int_pointer.
        printf("[integer pointer] points to %p, which contains the char '%c'\n",
            int_pointer, *int_pointer);
        int_pointer = int_pointer + 1;
    }

    for(i=0; i < 5; i++) { // Iterate through the char array with the char_pointer.
        printf("[char pointer] points to %p, which contains the integer %d\n",
            char_pointer, *char_pointer);
        char_pointer = char_pointer + 1;
    }
 }

输出:

[integer pointer] points to 0xbffff810, which contains the char 'a'
[integer pointer] points to 0xbffff814, which contains the char 'e'
[integer pointer] points to 0xbffff818, which contains the char ' '
[integer pointer] points to 0xbffff81c, which contains the char '
[integer pointer] points to 0xbffff820, which contains the char ' '
[char pointer] points to 0xbffff7f0, which contains the integer 1
[char pointer] points to 0xbffff7f1, which contains the integer 0
[char pointer] points to 0xbffff7f2, which contains the integer 0
[char pointer] points to 0xbffff7f3, which contains the integer 0
[char pointer] points to 0xbffff7f4, which contains the integer 2

【问题讨论】:

  • char_pointer = int_array; 这很糟糕。我认为分配不兼容类型的指针是未定义的行为。
  • @ShafikYaghmour:OP 在指针分配期间混合类型,但这不会改变指针算术行为。尽管它违反了严格的别名。另一个问题是在后续循环迭代中取消引用int_pointer 时触发的越界数组访问。我错过了什么吗?
  • @jweyrich 此代码中有两种不同形式的未定义行为,如果不涵盖这些问题,则无法正确回答问题,因为代码不正确。
  • @ShafikYaghmour:没错,说得好。我将撤回我的投票并删除 dup 评论。对你的回答也 +1 :-)
  • char_pointer = int_array; -- 这不仅是未定义的行为,还是违反约束。基本上这是非法的;任何符合标准的编译器都必须发出诊断,尽管许多人(不幸的是,恕我直言)将其设为非致命警告。但是,如果您将其更改为 char_pointer = (char*)int_array;,则不再违反约束,但您可能会遇到未定义的行为,具体取决于您使用指针的方式。 int_pointer = char_array; 也一样,除了你也可能遇到对齐问题。

标签: c pointers


【解决方案1】:

未定义的行为

您拥有的是undefined behavior,首先您违反了strict aliasing rule,这基本上使得通过不同类型的指针访问对象是非法的,尽管允许通过char *访问。我将引用我的answer here,它更广泛地涵盖了这一点:

严格的别名规则使得访问对象是非法的 通过不同类型的指针,尽管通过 char 访问 * 被允许。允许编译器假设不同类型的指针不指向同一个内存并优化 因此。这也意味着代码调用了未定义的行为和 真的可以做任何事。

第二个不同的指针可能有不同的对齐要求,因此通过 int 指针访问您的 char 数组可能会违反此要求,因为 char 数组可能无法正确对齐 int。 draft C99 standard6.3.2.3 Pointers 部分中对此进行了介绍,其中说(强调我的):

指向对象或不完整类型的指针可以转换为 指向不同对象或不完整类型的指针。 如果结果 对于指向的类型,指针未正确对齐57), 行为未定义。

具有正确标志集的良好编译器在这里应该有很大帮助,使用 clang 和以下标志 -std=c99 -fsanitize=undefined -Wall -Wextra -Wconversion -pedantic 我看到以下警告 (see it live):

warning: incompatible pointer types assigning to 'char *' from 'int [5]' [-Wincompatible-pointer-types]
char_pointer = int_array; // The char_pointer and int_pointer now
             ^ ~~~~~~~~~

warning: incompatible pointer types assigning to 'int *' from 'char [5]' [-Wincompatible-pointer-types]
int_pointer = char_array; // point to incompatible data types.
            ^ ~~~~~~~~~~

在运行时我看到以下错误:

runtime error: load of misaligned address 0x7fff48833df3 for type 'int', which requires 4 byte alignment
0x7fff48833df3: note: pointer points here
00  e0 3e 83 61 62 63 64 65  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  6d 47 60 5a 1d 7f 00
             ^ 

指针算法

所以指针算法是基于被指向的类型的大小。否则,基本上是syntactic sugar for pointer arithmetic 的数组访问如何正常工作?您可以阅读更详细的说明 hererelated discussion here

【讨论】:

    【解决方案2】:

    在进行指针运算时,它会按照您尝试增加的大小递增。以此为例。

    int a[2];
    a[0] = 1;
    a[1] = 3;
    a = a + 1
    printf("%d\n",*a) \\ 3
    

    它需要向前移动被指向的东西的大小。总是对我有帮助的是首先将指针转换为 char 以使用字节。

    int a[2];
    a[0] = 1;
    a[1] = 3;
    a = (char)a + sizeof(int)*1
    printf("%d\n",*a) \\ 3
    

    这更容易理解,它会产生你所想的。

    【讨论】:

    • 我认为数组的名称是一个常量 ptr,您无法更改其值。在这里我认为“a = a + 1”行应该给出编译错误。
    【解决方案3】:

    这就是指针算法的工作原理:如果将指针加 1,则地址会增加指针类型的大小。因此,由于在您的机器中 int 是 4 个字节,递增 int 指针会增加 4 个字节的地址。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-20
      • 1970-01-01
      • 2012-07-27
      • 2014-04-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多