【问题标题】:How can I declare a Pointer to a struct in C?如何在 C 中声明指向结构的指针?
【发布时间】:2021-12-03 00:37:34
【问题描述】:

我了解到可以通过 3 种不同的方式声明指针:

int* a;
int *b;
int * c;

我更喜欢:

int* a;

在声明指向结构的指针时,这样写是否正确:

struct Card {
   int a;
};
struct Card my_card = { 3, 7 };
struct Card* p = &my_card; 
(*p).a = 8; 

我很困惑,因为我发现的所有地方都声明如下:

struct Card *p = &my_card;

提前致谢。

【问题讨论】:

  • 空格可以省略你甚至可以通过以下方式声明一个指针 struct Card*p = &my_card;

标签: c pointers structure declaration


【解决方案1】:

如果T 是某个类型说明符,则可以通过以下任何方式声明指向T 类型对象的指针

T*p;
T* p;
T *p;
T * p;

例如,如果 Tint *,则指针声明可能如下所示

int **p;
int ** p;
int * *p;
int * * p;

同样的方式你可以声明一个指向结构的指针

struct Card*p = &my_card;
struct Card* p = &my_card;
struct Card *p = &my_card;
struct Card * p = &my_card;

注意你可能会写

T ( *p );

但你不能写

( T* ) p;

还有另一个微妙之处。如果你会写例如

int* p1, p2

那么变量p1 的类型为int *,而变量p2 的类型为int 而不是int *

但如果你会写

typedef int * T;

当在这个声明中

T p1, p2;

这两个变量的类型都是int *

【讨论】:

    【解决方案2】:

    你把空格放在哪里都没有关系。 struct Card* pstruct Card *p 同等有效;只是你喜欢哪一种风格的问题。

    我同意第二种形式更常见,但最重要的是您在整个代码中始终使用一种形式。您的老板/老师/其他开发人员也可能有指定使用哪种形式的编码风格标准。

    【讨论】:

      【解决方案3】:

      IMO int *aint* a 更有意义。在 C 中,*a 可以读作“a 的内容”,所以int *a 可以读作“a 的内容是一个整数”,就像int a 读作“a”一样一个整数'。正如其他答案所清除的那样,空格在这里并不重要 - 它们对编译器都是一样的。

      这种写法在声明多个指针变量(如int *a, *b)时也更有意义。编写 int* a, b 并期望 ab 都是 int 指针很容易出错。

      【讨论】:

        【解决方案4】:

        就编译器而言,

        T *a;
        T* a;
        T*a;
        T      *      a;
        

        all 的意思完全相同——都被解释为T (*a)a 的类型为“指向T”的指针)。在这种情况下,空格并不重要。对于您的 struct 类型,struct Card *pstruct Card* p 执行完全相同的操作,并且都被解释为 struct Card (*p)

        从句法上讲,* 总是绑定到 声明符(更多内容见下文)。这意味着像

        这样的声明
        T* a, b;
        

        被解释为

        T (*a), b;
        

        并且仅将a 声明为指向T 的指针-b 是常规T。这是我建议反对使用T* p 样式的众多原因之一(我将在下面给出更多理由)。

        在 C 中,声明有两个主要部分 - 声明说明符序列(类型说明符、structunionenum 说明符、存储类说明符、类型限定符等.) 后跟以逗号分隔的声明符列表。在像

        这样的声明中
        static unsigned long int a[10], *p, f(void);
        

        声明说明符是static unsigned long int,声明符是a[10]*pf(void)

        声明器引入了被声明事物的名称(apf)以及有关该事物的数组、指针和函数的信息。每个项目的类型完全由声明说明符和声明符的组合指定。

        声明符的结构与代码中表达式的结构相匹配——如果你有一个指向int的指针数组并且你想访问一个特定的int值,你需要对数组进行索引并且取消引用使用一元 * 运算符的结果:

        printf( "%d\n", *ap[i] );
        

        表达式*ap[i]的类型为int,所以ap数组的声明是

        int *ap[N];
        

        声明符*ap[N] 匹配表达式*ap[i] 的结构。

        在声明中,*[]() 运算符仅用于指示类型 - 您实际上并没有取消引用或索引或调用任何内容。但是,它们确实遵循与表达式中相同的优先级规则。后缀运算符的优先级高于一元运算符,因此[]()* 之前“绑定”:

        T *a[N];    // parsed as *(a[N]) -- a is an array of pointers
        T *f(void); // parsed as *(f(void)) - f is function returning a pointer
        

        要声明指向数组或函数的指针,您必须将* 运算符与数组或函数表达式显式分组:

        T (*a)[N];    // a is a pointer to an array
        T (*f)(void); // f is a pointer to a function
        

        现在对于这个答案的编辑部分(你可以随意忽略)......

        随着时间的推移,我越来越反对T* p 风格的指针声明。它是 C++ 程序员的首选风格,但你越想它就越没有意义,而且根据我的经验,它只会导致问题

        其声明的目的——强调变量的“指针性”——是虚假的。您不能通过将其声明为来强调变量的“数组性”

        T[N] a; // syntax error
        

        或“功能”为

        T(void) f; // syntax error
        

        因为后缀[]() 运算符的操作数af不是T。同样,在像

        这样的声明中
        T* p; // parsed as T (*p);
        

        一元* 运算符的操作数p不是T。而* 运算符是一元(前缀),而不是后缀,所以T* 看起来是错误的无论如何。因为它是一元的,并且因为空格无关紧要,T* p 会按预期工作,但是当你这样做时,你有点忽略了语言的规则。

        如果没有别的,它与声明指向数组的指针或指向函数的指针不一致:

        T (*ap)[N];     // ap is a pointer to an N-element array of T
        T (*fp)(void);  // fp is a pointer to a function returning T
        

        并声明一个指向指针数组的指针,例如

        T* (*ap)[N];    // ap is a pointer to an array of pointers to T
        

        很丑,只是表示思维混乱,就像我之前说的,你不能在数组或函数声明中遵循这个约定:

        T[N] a;    // syntax error
        T(void) f; // syntax error
        

        如果你使用它,你会不可避免地搞砸并写

        T* a, b;
        

        当你打算写作时

        T *a, *b;
        

        现在,不可避免 对反对意见的回应是将单独的声明放在单独的行中:

        T* a;
        T* b;
        

        是的,每行有一个声明有很多很好的理由,但解决不良做法并不是其中之一。将这些声明写成

        T *a;
        T *b;
        

        改为。

        【讨论】:

          猜你喜欢
          • 2020-04-30
          • 1970-01-01
          • 1970-01-01
          • 2011-02-08
          • 2021-12-17
          • 2021-07-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多