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


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

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

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

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

А затем,

struct example *ptr = &s1;

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

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

*р->ул. выбирает, что стр точек; *р->ул.++ увеличивает str после обращения к тому, на что он указывает (так же, как *s++);

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

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

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

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

4 22

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 ) );

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

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

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

struct-or-union-specifier:
    struct-or-union identifieropt { struct-declaration-list }
    struct-or-union identifier

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

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

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

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

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


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

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

struct {
  int a;
  int b;
} p;

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

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