数组中的矛盾指针

时间:2016-04-13 03:44:01

标签: c arrays pointers

我在C中遇到了一些“怪异”的行为,至少是我没想到的。请考虑以下代码行:

int arrayB[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
printf("%d\n", (arrayB+1)[1]);

此工作正常,因为(arrayB + 1)[1]转换为*(arrayB+1 +1),这是arrayB的第三个元素(因此它会按预期打印3个)

但是,请考虑下面的代码,我在其中初始化一个名为arrayA的2D数组(包含5个10个整数的数组,每个{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

int ** arrayA = malloc(sizeof(int *) * 5);
for (int i = 0; i < 5; i++) {
    arrayA[i] = malloc(sizeof(int) * 10);
    for (int j = 0; j < 10; j++) {
        arrayA[i][j] = j;
    }
}

printf("%d\n", *(arrayA+1)[2]);

此代码不会发出警告,并声称*(arrayA+1)[2]是int类型。但是..它似乎应该是(因为数组下标比解引用运算符具有更高的优先级),*(arrayA+1)[2]转换为类型为*(arrayA+3)的{​​{1}},因为int *是一个arrayA,更进一步说,这是允许的:

int **

但这怎么可能?好像我正在为*(arrayA+1)[2] = 1;分配int ...这通常会引发警告。

3 个答案:

答案 0 :(得分:3)

  

似乎...... *(arrayA+1)[2]会转换为*(arrayA+3)

不,你放弃了**(arrayA+1)[2]转换为**(arrayA+3),这确实是int

答案 1 :(得分:0)

我们讨论int ** arrayA(2D)。

arrayA是int **,所以arrayA + x也是int **。

* arrayA或arrayA [i]是int *,是一个线性数组(1D)。

所以,*(arrayA + 1)[2],任何优先级都是值而不是地址。

答案 2 :(得分:-1)

除了指针修正,你可以自由地声明一个指向指针指向的指针(例如int **arrayA;),并分配指针,然后分配内存和将块分配给每个单独的指针,在处理每行中固定数量的元素时不需要这样做。您可以简单地声明一个指向数组的指针 - 类型(例如int (*arrayA)[10];并分配一次。例如:

#include <stdio.h>
#include <stdlib.h>

#define ASZ 5

void *xmalloc (size_t s) {
    void *memptr = malloc (s);
    if (memptr == 0) {
        fprintf (stderr, "xmalloc() error: virtual memory exhausted.\n");
        exit (EXIT_FAILURE);
    }
    return memptr;
}

int main (void) {

    int i, j;
    int (*arrayA)[ASZ] = xmalloc (sizeof *arrayA * ASZ);

    for (i = 0; i < ASZ; i++) {
        for (j = 0; j < ASZ; j++) {
            arrayA[i][j] = j+i;
        }
    }

    for (i = 0; i < ASZ; i++) {
        if (!i) putchar ('\n');
        for (j = 0; j < ASZ; j++) {
            printf (" %2d", arrayA[i][j]);
        }
        putchar ('\n');
    }

    printf("\n *(arrayA+1)[2] = %d\n\n", *(arrayA+1)[2]);

    free (arrayA);

    return 0;
}

(不要忘记验证你的内存分配。使用像xmalloc这样的帮助可以让生活更轻松。

示例使用/输出

$ ./bin/arr2dderef

  0  1  2  3  4
  1  2  3  4  5
  2  3  4  5  6
  3  4  5  6  7
  4  5  6  7  8

 *(arrayA+1)[2] = 3

不要忘记在Linux上使用内存错误检查程序验证内存使用情况,例如valgrind,并且在不再需要内存时不要忘记释放内存。 (是的,它会在exit上自动释放,但现在养成了占用每个字节的习惯,以后你会为自己省去很多悲伤。

$ valgrind ./bin/arr2dderef
==28392== Memcheck, a memory error detector
==28392== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==28392== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==28392== Command: ./bin/arr2dderef
==28392==

  0  1  2  3  4
  1  2  3  4  5
  2  3  4  5  6
  3  4  5  6  7
  4  5  6  7  8

 *(arrayA+1)[2] = 3

==28392==
==28392== HEAP SUMMARY:
==28392==     in use at exit: 0 bytes in 0 blocks
==28392==   total heap usage: 1 allocs, 1 frees, 100 bytes allocated
==28392==
==28392== All heap blocks were freed -- no leaks are possible
==28392==
==28392== For counts of detected and suppressed errors, rerun with: -v
==28392== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)