C указатель на массив/массив значений указателей

В чем разница между следующими объявлениями:

int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);

Каково общее правило для понимания более сложных объявлений?

Ответ 1

int* arr[8]; // An array of int pointers.
int (*arr)[8]; // A pointer to an array of integers

Третий - тот же, что и первый.

Общее правило приоритет оператора. Это может стать еще более сложным, поскольку указатели на функцию попадают в изображение.

Ответ 2

Используйте программу cdecl, как предложено K & R.

$ cdecl
Type `help' or `?' for help
cdecl> explain int* arr1[8];
declare arr1 as array 8 of pointer to int
cdecl> explain int (*arr2)[8]
declare arr2 as pointer to array 8 of int
cdecl> explain int *(arr3[8])
declare arr3 as array 8 of pointer to int
cdecl>

Это работает и наоборот.

cdecl> declare x as pointer to function(void) returning pointer to float
float *(*x)(void )

Ответ 3

Я не знаю, имеет ли оно официальное имя, но я называю это Right-Left Thingy (TM).

Начните с переменной, затем идите вправо, влево и вправо... и т.д.

int* arr1[8];

arr1 - массив из 8 указателей на целые числа.

int (*arr2)[8];

arr2 - это указатель (блок скобок справа налево) в массив из 8 целых чисел.

int *(arr3[8]);

arr3 - массив из 8 указателей на целые числа.

Это должно помочь вам со сложными объявлениями.

Ответ 4

int *a[4]; // Array of 4 pointers to int

int (*a)[4]; //a is a pointer to an integer array of size 4

int (*a[8])[5]; //a is an array of pointers to integer array of size 5 

Ответ 5

Ответ за последние два также можно вычесть из золотого правила в C:

Декларация следует за использованием.

int (*arr2)[8];

Что произойдет, если вы разыграете arr2? Вы получаете массив из 8 целых чисел.

int *(arr3[8]);

Что произойдет, если вы возьмете элемент из arr3? Вы получаете указатель на целое число.

Это также помогает при работе с указателями на функции. Чтобы взять пример sigjuice:

float *(*x)(void )

Что происходит, когда вы разыскиваете x? Вы получаете функцию, которую вы можете вызвать без аргументов. Что происходит, когда вы это называете? Он вернет указатель на float.

Однако приоритет оператора всегда сложный. Однако использование круглых скобок также может быть путаным, поскольку декларация следует за использованием. По крайней мере, для меня интуитивно arr2 выглядит как массив из 8 указателей на ints, но на самом деле это наоборот. Просто привыкает. Причина достаточно, чтобы всегда добавлять комментарий к этим объявлениям, если вы спросите меня:)

изменить: пример

Кстати, я просто наткнулся на следующую ситуацию: функцию, которая имеет статическую матрицу и которая использует арифметику указателя, чтобы увидеть, находится ли указатель строки вне границ. Пример:

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

#define NUM_ELEM(ar) (sizeof(ar) / sizeof((ar)[0]))

int *
put_off(const int newrow[2])
{
    static int mymatrix[3][2];
    static int (*rowp)[2] = mymatrix;
    int (* const border)[] = mymatrix + NUM_ELEM(mymatrix);

    memcpy(rowp, newrow, sizeof(*rowp));
    rowp += 1;
    if (rowp == border) {
        rowp = mymatrix;
    }

    return *rowp;
}

int
main(int argc, char *argv[])
{
    int i = 0;
    int row[2] = {0, 1};
    int *rout;

    for (i = 0; i < 6; i++) {
        row[0] = i;
        row[1] += i;
        rout = put_off(row);
        printf("%d (%p): [%d, %d]\n", i, (void *) rout, rout[0], rout[1]);
    }

    return 0;
}

Вывод:

0 (0x804a02c): [0, 0]
1 (0x804a034): [0, 0]
2 (0x804a024): [0, 1]
3 (0x804a02c): [1, 2]
4 (0x804a034): [2, 4]
5 (0x804a024): [3, 7]

Обратите внимание, что значение границы никогда не изменяется, поэтому компилятор может оптимизировать это. Это отличается от того, что вы изначально хотели бы использовать: const int (*border)[3]: объявляет границу как указатель на массив из 3 целых чисел, которые не будут изменять значение до тех пор, пока существует переменная. Однако этот указатель может указывать на любой другой такой массив в любое время. Вместо этого мы хотим такого поведения для аргумента (потому что эта функция не меняет ни одного из этих целых чисел). Декларация следует за использованием.

(стр.с.: не стесняйтесь улучшать этот образец!)

Ответ 6

typedef int (*PointerToIntArray)[];
typedef int *ArrayOfIntPointers[];

Ответ 7

Я думаю, мы можем использовать простое правило.

example int * (*ptr)()[];
start from ptr 

"ptr является указателем на" пойдите направо..its ")" теперь идите налево его a "(" выходите направо "()" так "к функции, которая не принимает аргументов" go left "и возвращает указатель" go right "to массив "go left" из целых чисел "

Ответ 8

Как правило, правильные унарные операторы (например, [], () и т.д.) предпочитают более левые. Таким образом, int *(*ptr)()[]; будет указателем, который указывает на функцию, которая возвращает массив указателей на int (как можно быстрее получить правильные операторы, когда вы выйдете из скобки)

Ответ 9

Вот как я его интерпретирую:

int *something[n];

примечание о приоритете: оператор индекса массива ('[]') имеет более высокий приоритет, чем оператор разыменования ('*').

Итак, здесь мы будем применять '[]' до '*', делая утверждение эквивалентным:

int *(something[i]);

Обратите внимание на то, как декларация имеет смысл: int num означает (num) is (int), int *ptr или int (*ptr) означает, (значение в ptr) является an (int), что делает ptr указателем на int.

Это можно прочитать как (значение (значение в i-м индексе чего-то)) является целым числом. Итак, (значение в i-м индексе чего-то) является (целым указателем), что делает что-то целым целым указателем.

Во втором,

int (*something)[n];

Чтобы понять это утверждение, вы должны быть знакомы с этим фактом:

примечание о представлении указателя массива: somethingElse [i] эквивалентно * (somethingElse + i)

Итак, заменив somethingElse на (* something), мы получим * (* something + i), который является целым числом в соответствии с объявлением. Итак, (* something) дал нам массив, который делает что-то эквивалентное (указатель на массив).

Ответ 10

Я предполагаю, что вторая декларация вводит в заблуждение многих. Вот простой способ понять это.

Позволяет иметь массив целых чисел, т.е. int B[8].

Пусть также имеет переменную A, которая указывает на B. Теперь значение в равно B, то есть (*A) == B. Следовательно, A указывает на массив целых чисел. В вашем вопросе arr похож на A.

Аналогично, в int* (*C) [8], C является указателем на массив указателей на integer.

Ответ 11

В указателе на целое число, если указатель увеличивается, он переходит в следующее целое число.

в массиве указателя, если указатель увеличивается, он переходит к следующему массиву