22

在 K&R 第 6 章中,声明如下:

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

4 回答 4

12

关键字的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;

请注意,在这种情况下,类型s1example而不是。struct example

于 2017-11-01T19:11:10.403 回答
3

对于初学者,请考虑以下简单程序

#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-declaration-list }
    结构或联合标识符

可以看出,如果存在 struct-declaration-list,则标识符是可选的。因此,未命名的结构可以用作类型说明符。

使用枚举的另一个例子。您可以在不声明枚举类型的情况下声明枚举数。例如

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

int如果程序中没有这样的要求,您可以使用具有该类型的枚举器,而无需声明该枚举类型的对象。

于 2017-11-01T19:31:04.893 回答
2

(匿名结构)的另一种用途是在联合或其他结构中使用它们,这基本上将该结构的使用限制为特定父联合或结构而不是其他任何东西,这从程序员的角度来看非常有用,因为查看像这样的代码它为我们提供了它在其内部结构或联合的上下文中本地使用的信息——仅此而已。(也使我们免于命名)。


此外,如果您使用此匿名结构,您将无法分配它的一个实例,而不是已经存在的实例。

示例:-(斯塔克的评论:如何使用它?)

struct {
  int a;
  int b;
} p;

scanf("%d",&p.a);
于 2017-11-01T19:14:28.433 回答
0

如果您需要一个临时的、一次性使用的结构(或联合)定义,在声明它的范围之外将无用,您将使用所谓的匿名或未命名的结构和联合。这使您不必在使用它之前声明结构,并且在复杂类型的情况下,声明内部类型,例如这里

于 2017-11-01T19:24:54.160 回答