Что означает этот указатель определения структуры типа (в C)?

В главе 6 K&R декларация упоминается следующим образом:

struct{
    int len;
    char *str;
} *p;

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

struct example{
    int a;
    ...
}s1;

а потом,

struct example *ptr = &s1;

Итак, упоминается, что ptr указывает на пример структуры типа, а не только на структуру.

Также особый интерес представляло это:

* p-> str извлекает все, на что указывает str; *p->str++ увеличивает str после доступа к тому, на что он указывает (точно так же как *s++);

Я не мог понять, что p в первую очередь, следовательно, не приращение и разыменование также.

Что здесь происходит?

Заранее спасибо!

PS Я новичок здесь, поэтому любые отзывы о формате вопроса также будут оценены.

4 ответа

Решение

struct ключевое слово работает как расширенная версия typedefза исключением того, что вы создаете сложный пользовательский тип (называемый структурой) вместо того, чтобы создавать псевдонимы для существующего типа. Если у вас есть только одна вещь, которая должна использовать объявленный тип, вам не нужно указывать явное имя для типа.

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

Один из возможных вариантов использования для такого объявления - когда вы создаете заголовок для внешней библиотеки, возможно, такой, которая даже не написана на C. В этом случае тип структуры может быть непрозрачным или неполным, и вам просто нужно иметь удобную ссылку на некоторые его части. Анонимная структура не позволяет вам легко размещать ее самостоятельно, но позволяет вам взаимодействовать с ней через указатель.

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

struct example { ... } s1, *ptr;

В таком случае, struct example *ptr = &s1; было бы просто ptr = &s1;,

Еще более распространенным явлением является использование анонимных структур с typedefсоздать собственные имена типов, которые не включают struct ключевое слово. Ваш второй пример может быть переписан как

typedef struct { ... } example, *pexample;
example s1;
pexample ptr; // alternatively example *ptr;
ptr = &s1;

Обратите внимание, что тип s1 является example и не struct example в этом случае.

Для начала рассмотрим следующую простую программу

#include <stdlib.h>
#include <stdio.h>
#include <string.h> 

int main(void) 
{
    struct {
        int len;
        char *str;
    } *p;

    p = malloc( sizeof( *p ) );

    p->str = "Hello Nihal Jain";
    p->len = strlen( p->str );

    while ( *p->str ) putchar( *p->str++ );
    putchar( '\n' );

    free( p );

    return 0;
}

Его вывод

Hello Nihal Jain

Так что в этой декларации

    struct {
        int len;
        char *str;
    } *p;

там объявлен указатель типа безымянной структуры. Сам указатель не инициализирован. Вы могли бы написать, например,

    struct {
        int len;
        char *str;
    } *p = malloc( sizeof( *p ) );

Для этой простой программы имя структуры не требуется, потому что ни объявление объекта типа структуры не присутствует или не требуется в программе.

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

Согласно стандарту C структура или объединение объявляются как

структура или всесоюзные спецификаторы:
    идентификатор структуры или объединенияopt {список-объявления-структуры}
    идентификатор структуры или объединения

Видно, что идентификатор является необязательным, если существует список struct-объявление. Таким образом, безымянная структура может использоваться как спецификатор типа.

Еще один пример с использованием перечислений. Вы можете объявить перечислители без объявления типа перечисления. Например

enum { EXIT_SUCCESS = 0, EXIT_FAILURE = -1 }; 

Вы можете использовать перечислители, которые имеют тип int без объявления объекта типа перечисления, если в программе нет такого требования.

Также другим использованием (анонимных структур) будет использование их внутри союзов или других структур, которые в основном ограничивают использование этой структуры этим конкретным родительским объединением или структурой, а не чем-то еще, что весьма полезно с точки зрения программиста, поскольку взгляд на Подобный код предоставляет нам информацию о том, что он используется локально в контексте структуры или объединения внутри него - не более того. (также спасает нас от именования).


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

Пример:-(комментарий Старка: как его использовать?)

struct {
  int a;
  int b;
} p;

scanf("%d",&p.a);

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

Другие вопросы по тегам