Мой вопрос: почему второй не указатель?
Потому что он объявляет массив. В двух других случаях у вас есть указатель, который ссылается на данные, которые живут где-то еще. Однако объявление вашего массива объявляет массив данных, который живет там, где он объявлен. Если вы объявили это внутри функции, то данные умрут, когда вы вернетесь из этой функции. Наконец, char *fun[4]
будет массивом 4
указателей - это не будет указатель на символ. В случае, если вы просто хотите указать на блок из 4 символов, то вполне достаточно char*
, не нужно указывать, что есть ровно 4
символов, на которые нужно указать.
Первый способ, который создает объект в куче, используется, если вам нужны данные, чтобы жить от них до соответствующего вызова free
. Данные переживут возврат из функции.
Последний способ просто создает данные, которые не предназначены для записи. Это указатель, который ссылается на строковый литерал - он часто хранится в постоянной памяти. Если вы напишите в него, то поведение не определено.
Я понимаю, что делают указатели, но я не понимаю, в чем их смысл (не каламбур).
Указатели используются, чтобы указывать на что-то (конечно, не каламбур). Посмотрите на это так: если у вас есть ряд предметов на столе, и ваш друг говорит «выберите второй предмет», то этот предмет волшебным образом не дойдет до вас. Вы должны схватить это. Ваша рука действует как указатель, и когда вы возвращаете руку обратно к вам, вы разыменовываете этот указатель и получаете предмет. Ряд элементов можно рассматривать как массив элементов:
И почему получается, что указатель на struct или int всегда является массивом?
item row[5];
Когда вы делаете item i = row[1];
, вы сначала указываете рукой на первый предмет (получаете указатель на первый), а затем продвигаетесь, пока не окажетесь у второго предмета. Затем вы берете руку с элементом обратно к себе :) Итак, синтаксис row[1]
не является чем-то особенным для массивов, а скорее является особенным для указателей - он эквивалентен *(row + 1)
, и при использовании создается временный указатель такой массив.
В чем разница между A и B? А это «имя тега», но что это? Когда я использую что? То же самое для перечислений.
typedef struct car
{
...
};
Это недействительный код. Вы в основном сказали: «определите тип struct car { ... }
для ссылки по следующему обычному идентификатору», но вы упустили возможность сообщить ему идентификатор. Два следующих фрагмента эквивалентны, насколько я могу видеть
1)
struct car
{
...
};
typedef struct car car;
2)
typedef struct car
{
...
} car;
В чем разница между А и В? А это «имя тега», но что это? Когда я использую что? То же самое для перечислений.
В нашем случае идентификатор car
был объявлен два раза в одной и той же области видимости. Но объявления не будут конфликтовать, потому что каждый из идентификаторов находится в различном пространстве имен . Два вовлеченных пространства имен - это обычное пространство имен 1060 * и пространство имен тегов . Идентификатор тега необходимо использовать после ключевого слова struct , union или enum , в то время как обычному идентификатору ничего вокруг него не нужно. Возможно, вы слышали о функции POSIX stat
, интерфейс которой выглядит следующим образом
struct stat {
...
};
int stat(const char *path, struct stat *buf);
В этом фрагменте кода stat
также регистрируется в двух вышеупомянутых пространствах имен. struct stat
будет ссылаться на структуру, и просто stat
будет ссылаться на функцию. Некоторым людям не нравится всегда начинать идентификаторы с struct
, union
или enum
. Они используют typedef
для введения обычного идентификатора, который также будет ссылаться на структуру. Конечно, идентификатор может быть одинаковым (оба раза car
) или отличаться (один раз A
, другой раз B
). Это не важно