Подтвердить что ты не робот

Разница между "указателем на int" и "указателем на массив int"

int main()
{
    int (*x)[5];                 //pointer to an array of integers
    int y[6] = {1,2,3,4,5,6};    //array of integers
    int *z;                      //pointer to integer

    z = y;
    for(int i=0;i<6;i++)
        printf("%d ",z[i]);

    x = y;
    for(int i=0;i<6;i++)
        printf("%d ",(*x)[i]);

    return 0;
}

Оба вышеуказанных printfs печатают числа с 1 по 6.
Если оба " указателя на массив целых чисел" и " указатель на целое число" могут сделать то же самое, имеют ли они одно и то же внутреннее представление?
EDIT: этот код дает предупреждения при компиляции, как указано в ответах ниже, однако он корректно печатает значения и времени на моей машине x86_64, используя gcc

4b9b3361

Ответ 1

Во-первых, ваш код не будет компилироваться. Массив имеет тип int[6] (6 элементов), а указатель имеет тип int (*)[5]. Вы не можете заставить этот указатель указывать на этот массив, потому что типы разные.

Во-вторых, когда вы инициализируете (назначаете) такой указатель, вы должны использовать & в массиве: x = &y, а не просто x = y, как в вашем коде.

Я предполагаю, что вы просто набрали код вверх, вместо копирования вставки реального кода.

В-третьих, о внутреннем представлении. Как правило, на практике вы должны ожидать, что все указатели данных будут использовать одно и то же внутреннее представление. Более того, после указанных выше присвоений (если они написаны правильно) указатели будут иметь одинаковое числовое значение. Разница между int (*)[5] и int * существует только на концептуальном уровне, то есть на уровне языка: типы разные. Это имеет некоторые последствия. Например, если вы увеличиваете ваш z, он перейдет к следующему члену массива, но если вы увеличите y, он перепрыгнет через весь массив и т.д. Таким образом, эти указатели на самом деле не "делают то же самое" ".

Ответ 2

Короткий ответ: есть разница, но ваш пример испорчен.

Длинный ответ:

Разница в том, что int* указывает на тип int, но int (*x)[6] указывает на массив из 6 ints. На самом деле в вашем примере

x = y;

- это undefined ** поведение, вы знаете, что это два разных типа, но в C вы делаете то, что хотите. Я просто использую указатель на массив из шести целых чисел.

Возьмите этот модифицированный пример:

int (*x)[6];                 //pointer to an array of integers
int y[6] = {1,2,3,4,5,6};    //array of integers
int *z;                      //pointer to integer
int i;

z = y;
for(i = 0;i<6;i++)
    printf("%d ",z[i]);

x = y; // should be x = &y but leave it for now!

for(i = 0;i<6;i++)
    printf("%d ",x[i]); // note: x[i] not (*x)[i]

Во-первых,

1 2 3 4 5 6

Будет напечатан. Тогда мы доходим до x[0]. x [0] - не что иное, как массив из 6 ints. Массив в C является адресом первого элемента. Таким образом, адрес y будет напечатан, а затем адрес массива next в следующей итерации. Например, на моей машине:

1 2 3 4 5 6 109247792 109247816 109247840 109247864 109247888 109247912

Как вы можете видеть, разница между последовательными адресами - это не что иное, как:

sizeof(int[6]) // 24 on my machine!

Таким образом, это два разных типа указателей.

** Я думаю, что это поведение undefined, пожалуйста, не стесняйтесь исправить мой пост, если он не прав.

Ответ 3

Надеемся, что этот код поможет:

int main() {

    int arr[5] = {4,5,6,7,8};        
    int (*pa)[5] = &arr;
    int *pi = arr;

    for(int i = 0; i< 5; i++) {
        printf("\n%d %d", arr[i], (*pa)[i]);    
    }

    printf("\n0x%x -- 0x%x", pi, pa);
    pi++;
    pa++;
    printf("\n0x%x -- 0x%x", pi, pa);
}

печатает следующее:

4 4
5 5
6 6
7 7
8 8
0x5fb0be70 -- 0x5fb0be70
0x5fb0be74 -- 0x5fb0be84 

UPDATE: Вы можете заметить, что указатель на целое увеличивается на 4 байта (размер 32 битного целого), тогда как указатель на массив целых чисел увеличивается на 20 байт (размер int arr [5], т.е. Размер 5 int по 32 бит каждый). Это демонстрирует разницу.

Ответ 4

Чтобы ответить на ваш вопрос из заголовка, из comp.lang.c FAQ: Так как ссылки массива распадаются на указатели, если arr является массивом, что разница между arr и & arr?

Однако код, который вы опубликовали, имеет другие проблемы (вы назначаете y, а не &y - x), а y - это 6-элементный массив, но *x - это 5 -элементный массив, оба из которых должны генерировать предупреждения компиляции).

Ответ 5

Кто знает - этот код демонстрирует поведение undefined:

printf("%d ",(*x)[i]);

Ответ 6

Надеюсь, что этот код поможет.


#include <stdio.h>
#include <stdlib.h>
#define MAXCOL 4
#define MAXROW 3

int main()
{      
      int i,j,k=1;
      int (*q)[MAXCOL];      //pointer to an array of integers

      /* As malloc is type casted to "int(*)[MAXCOL]" and every 
         element (as in *q) is 16 bytes long (I assume 4 bytes int), 
         in all 3*16=48 bytes will be allocated */

      q=(int(*)[MAXCOL])malloc(MAXROW*sizeof(*q)); 

      for(i=0; i<MAXROW; i++)
        for(j=0;j<MAXCOL;j++)
          q[i][j]=k++;


      for(i=0;i<MAXROW;i++){
        for(j=0;j<MAXCOL;j++)
          printf(" %2d ", q[i][j]);
        printf("\n");         
      } 
}

Ответ 7

#include<stdio.h>

int main(void)
{
    int (*x)[6];                 //pointer to an array of integers
    int y[6] = {11,22,33,44,55,66};    //array of integers
    int *z;                      //pointer to integer
    int i;

    z = y;
    for(i = 0;i<6;i++)
        printf("%d ",z[i]);
    printf("\n");

    x = &y;

    for(int j = 0;j<6;j++)
        printf("%d ",*(x[0]+j));

    return 0;
}

//ВЫВОД::

11 22 33 44 55 66

11 22 33 44 55 66

Указатель на массив лучше всего подходит для многомерного массива. но в приведенном выше примере мы использовали один размерный массив. поэтому во втором цикле цикла мы должны использовать (x [0] + j) с * для печати значения. Здесь x [0] означает 0-й массив. И когда мы пытаемся напечатать значение с помощью printf ( "% d", x [i]); вы получите 1-е значение 11, а затем некоторое количество мусора из-за попытки доступа к первой строке массива и т.д.

Ответ 8

Следует понимать внутреннее представление (*x)[i]. Внутренне он представлен как *((*x)+i), который не что иное, как i-й элемент массива, к которому указывает x. Это также способ иметь указатель, указывающий на 2d-массив. Количество строк не имеет значения в массиве 2d.

Например:

int arr[][2]={{1,2},{3,4}};
int (*x)(2);
x=arr; /* Now x is a pointer to the 2d array arr.*/

Здесь x указывает на массив 2d, имеющий 2 целочисленных значения во всех столбцах, и элементы массива сохраняются смежно. Таким образом, (*x)[0] будет печатать arr[0][0] (что равно 1), (*x)[1] будет печатать значение arr[0][1] (которое равно 2) и так далее. (*x+1)[0] будет печатать значение arr[1][0] (в этом случае 3) (*x+1)[1] будет печатать значение arr[1][1] (в этом случае 4) и т.д.

Теперь массив 1d можно рассматривать как ничего, кроме массива 2d, имеющего только одну строку с таким количеством столбцов.

int y[6] = {1,2,3,4,5,6};
int (*x)[6];
x =y;

Это означает, что x является указателем на массив, имеющий 6 целых чисел. Таким образом, (*x)[i], эквивалентный *((*x)+i), напечатает значение индекса я y.