У меня есть следующий код

#include <stdio.h>
int main(void) {
    int arr[] = {10,20,30,40};
    int* ptr = arr;
    printf("%d\n",sizeof(arr));
    printf("%d",sizeof(ptr));
    return 0;
}

На выходе

16
4

Размер указателя в C равен 4. 'arr' также является указателем на целое число, но его размер оказывается равным 16, что является произведением размера одного элемента и количества элементов. С другой стороны, если я сохраню тот же указатель в другой переменной-указателе, его размер станет 4. Это очень сбивает с толку. То же самое произойдет, если я попытаюсь отправить arr в качестве аргумента функции, а затем распечатать размер arr в этой функции. Как C обрабатывает указатель на массив?

1
shafeeq 5 Сен 2014 в 17:10

4 ответа

Лучший ответ

'arr' также является указателем на целое число

Нет, это не так. arr - это массив. Размер массива - это размер элемента, умноженный на количество элементов. Если бы это был указатель, его размер был бы таким же, как и у любого другого указателя.

Как C обрабатывает указатель массива?

C обрабатывает указатели на массивы так же, как и все остальные указатели. Однако в вашем коде нет указателей на массивы, только указатель на int (ptr).

5
sepp2k 5 Сен 2014 в 13:16

Указатель - это просто адрес памяти, поэтому в 32-битных системах он всегда равен 4 байтам. В зависимости от среды это 4 или 8 байтов в 64-битных системах.

В вашем примере нет настоящей путаницы. arr - это массив из 4 32-битных целых чисел, то есть 16 байтов. Он «обрабатывается» или «передается» как указатель на первый int, int*, поэтому вы можете скопировать его в другие переменные этого типа либо явно, либо как параметр. В этот момент больше нет связи с исходным массивом, и это просто указатель - 4 байта в вашей системе.

Лучший способ взглянуть на это - это предположить, что существует неявное преобразование из int[] в int*, как и из char в int.

3
Niels Keurentjes 5 Сен 2014 в 13:15
  • Когда вы сделаете sizeof(arr), вы получите размер массива, равный number of elements * size of int.
  • Когда вы сделаете sizeof(ptr), вы получите размер указателя, равный size of int.

Это очень сбивает с толку. То же самое произойдет, если я попытаюсь отправить arr в качестве аргумента функции, а затем распечатать размер arr в этой функции.

Когда вы отправляете массив, подобный этому foo(arr), вы фактически отправляете базовый адрес arr. И когда мы передаем адрес переменной функции, она сохраняет адрес в указателе. И снова, если вы попытаетесь получить размер arr, вы получите размер указателя.

1
ani627 5 Сен 2014 в 13:47

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

int a[5]; //real array. NOT a pointer
sizeof(a); // :)

Однако к тому времени, когда массив превратится в указатель, sizeof даст размер указателя, а не массива.

int a[5];
int * p = a; // assigning address of the array to pointer
sizeof(p); // :(

Он всегда будет возвращать 4 байта в 32-битной системе и 8 байта в 64-битной системе!

Массивы превращаются в указатели при передаче в функцию и продолжают сохранять длину массива в системе типов.

Когда вы передаете массив функции, он распадается на указатель. Таким образом, функция sizeof вернет размер int *

Поэтому, когда вы передаете массив функции, вам также необходимо передать количество элементов:

void function (size_t sz, int *arr) { ... }
:
{
    int x[20];
    function (sizeof(x)/sizeof(*x), x);
}
0
Sathish 5 Сен 2014 в 13:28