Разница между "указателем на 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
Ответы
Ответ 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
.