В чем разница между массивами в квадратных скобках и массивами указателей? - PullRequest
15 голосов
/ 17 февраля 2012

Как эксперт не на C / C ++, я всегда рассматривал квадратные скобки и массивы указателей как равные.

т.е.:

char *my_array_star;
char my_array_square[];

Но я заметил, что при использовании в структуре / классеони не ведут себя одинаково:

typedef struct {
   char whatever;
   char *my_array_star;
} my_struct_star;

typedef struct {
   char whatever;
   char my_array_square[];
} my_struct_square;

В строке ниже отображается 16, whatever занимает 1 байт, my_array_pointer занимает 8 байт.Из-за заполнения общий размер структуры равен 16.

printf("my_struct_star: %li\n",sizeof(my_struct_star));

В строке ниже отображается 1, whatever занимает 1 байт, my_array_pointer не учитывается.

printf("my_struct_square: %li\n",sizeof(my_struct_square));

Играя вокруг, я заметил, что квадратные скобки используются как дополнительное пространство в структуре

my_struct_square  *i=malloc(2);

i->whatever='A';
i->my_array_square[0]='B';

перенос строки отображает A:

printf("i[0]=%c\n",((char*)i)[0]);

перенос строки отображает B:

printf("i[1]=%c\n",((char*)i)[1]);

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

Ответы [ 2 ]

25 голосов
/ 17 февраля 2012

Массивы и указатели не ведут себя одинаково, потому что они не одинаковы вообще, просто кажется, что так.

Массивы представляют собой группу смежных элементов, в то время как указательis ... well ... указатель на один элемент.

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

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

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

#include <stdio.h>

static void fn (char plugh[]) {
    printf ("size = %d\n", sizeof(plugh)); // will give char* size (4 for me).
}

int main (void) {
    char xyzzy[10];
    printf ("size = %d\n", sizeof(xyzzy)); // will give 10.
    fn (xyzzy);

    return 0;
}

Другая вещь, которую вы найдете, заключается в том, что, в то время как вы можете plugh++ и plugh-- удовлетворять свои сердца (до тех пор, пока вы не разыграете внемассив), вы не можете сделать это с массивом xyzzy.

В ваших двух структурах есть существенная разница.В версии указателя у вас есть фиксированный размер указателя внутри структуры, которая будет указывать на элемент вне структуры.

Именно поэтому она занимает место- ваш 8-байтовый указатель выровнен по 8-байтовой границе следующим образом:

+----------------+
| 1 char variable|
+----------------+
| 7 char padding |
+----------------+
| 8 char pointer |
+----------------+

С «неограниченным» массивом у вас есть внутри структуры, и вы можете сделать этонастолько большой, насколько вы хотите - вам просто нужно выделить достаточно памяти при создании переменной.По умолчанию (т.е. согласно sizeof) размер равен нулю:

+----------------+
| 1 char variable|
+----------------+
| 0 char array   |
+----------------+

Но вы можете выделить больше места, например:

typedef struct {
   char whatever;
   char my_array_square[];
} my_struct_square;

my_struct_square twisty = malloc (sizeof (my_struct_square) + 10);

дает вам переменнуюtwisty, который имеет whatever символ и массив из десяти символов, называемый my_array_square.

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

5 голосов
/ 17 февраля 2012

Элемент my_array_square - это то, что называется «гибким» элементом массива. Такие массивы без указанного размера могут появляться только в конце структуры, и они не влияют на ее размер. Цель состоит в том, чтобы вручную выделить оставшееся пространство для столько элементов, сколько вам нужно. В противном случае размер массива определяется во время компиляции.

Шаблон использования такой структуры будет следующим:

my_struct_square *s = malloc(sizeof(my_struct_square) + 5 * sizeof(char));
...
s->my_array_square[4]; // the last element of the array

Во всех других случаях размер массива должен быть известен во время компиляции. Даже тип массива совпадает с его размером, то есть int a[20] имеет тип int[20], а не просто int[].

Кроме того, важно понимать разницу между массивами и указателями. @paxdiablo достаточно хорошо это охватил.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...