Я всегда думал, что в C массивы, определенные как-то так int array[13] = {0};
это на самом деле то же самое, что int*
, то есть память выделяется на стеке, и где-то там есть локальная переменная array, указывающая на кусок памяти под 13 интов. И я думал, что единственная разница между массивом и указателем это то, что для массива переопределен оператор sizeof
, и соответственно компилятор статически знает его размер.
Сегодня я учился работать в gdb, рассматривал там всякие значения и адреса переменных, и тут конфуз у меня случился. Есть переменная fptr ptrs[3] = { NULL, get_wisdom, put_wisdom };
, остановился я в gdb на брейкпоинте, и пишу
(gdb) print ptrs
$12 = {0, 0x804857e <get_wisdom>, 0x8048627 <put_wisdom>}
И думаю: «хмм, странно, почему этот gdb по умолчанию печатает массив/указатель как массив? Пробую print /a ptrs
- не получается. Ну ладно, думаю я, видимо в gdb так переопределен принт для массивов, определенных как массивы, и /a
почему-то не работает, ну да и хрен с ним.
Пробую затем
(gdb) print &ptrs
$13 = (fptr (*)[3]) 0x804a0d4
и думаю: „ага, почему-то чтобы мне получить значение указателя ptrs, надо написать &
- странно плохо сделали тупо, а теперь я хочу получить адрес собственно переменной ptrs, а не ее значение:
(gdb) print &&ptrs
A syntax error in expression, near `&&ptrs'.
А оно не работает. Ну тут я начинаю понимать, что что-то здесь нечисто, и возможно я неправильно понимаю C-шные массивы. Иду и создаю на тест программу:
#include <stdio.h>
int main() {
int array[5] = {0};
printf("array = %p\n", array);
printf("&array = %p\n", &array);
};
запускаю ее, а оно выдает
array = 0xbffff530
&array = 0xbffff530
Мамочки, думаю я, так что же, когда в Си объявляешь массив как массив, то он на самом деле не указатель, там нет никакой переменной в памяти, хранящей этот адрес, а есть лишь кусок памяти под 13 или сколько там элементов на стеке, и компилятор статически знает его адрес и при индексации прибавляет к нему сдвиг? И соответственно можно получить лишь адрес этого куска памяти, и этот адрес нигде как переменная не хранится. И соответственно переприсвоить массиву указатель на что-то другое нельзя.
array = calloc(6, sizeof(int));
//a.c: In function ‘main’:
//a.c:7: warning: incompatible implicit declaration of built-in function ‘calloc’
//a.c:7: error: incompatible types in assignment
или
printf("&&array = %p\n", &&array);
// какая-то там ошибка про label'ы, видимо && в C для гоуту используется? не знаю
Вот так я узнал сильно новую для себя вещь про C. Надеюсь, еще через пару лет не найду какой-нибудь нежданчик например в аргументах функций как массивах (вместо указателей) или в чем-нибудь еще.
А вообще мне непонятно, нафиг они так сделали? По-моему если бы были только указатели, без массивов, то было бы проще и удобнее. Ну конечно какая-нибудь там конструкция типа sizeof пускай работает, чтобы можно было статически размер их получать.