【问题标题】:Why dereference a reference in C? Using & next to *为什么取消引用 C 中的引用?在 * 旁边使用 &
【发布时间】:2020-04-11 06:04:44
【问题描述】:

我查看了 thisthisthisthis 等等。

问题是

EdX 上的基本 C 编程 MOOC 展示了当结构通过指针传递时,如何访问函数内的结构成员。 为什么他们在*旁边使用&???

他们显示:scanf("%lf", &(*studptr).aveGrade);

为什么不在scanf中使用studptr.aveGrade

(撇开单独的问题,“为什么要使用 scanf”)

(被要求提供完整示例)

void readStudent(struct student *studptr) {
    print("\nEnter a new student record: \n");
    printf("First name: ");
    scanf("%s", (*studptr).firstName);
    printf("Last name: ");
    scanf("%s", (*studptr).lastName);
    printf("Birth year: ");
    scanf("%d", &(*studptr).birthYear);
    printf("Average grade: ");
    scanf("%lf", &(*studptr).aveGrade);
}

【问题讨论】:

  • 是否有意,前两个scanf() 没有&
  • @RobertS-ReinstateMonica — 是的,输入是字符串,因此不需要 &。 (更准确地说,虽然不太简洁,成员 firstnamelastname 几乎可以肯定是 char 的数组,因此以书面形式传递它们传递了 char *,这正是 %s 所期望的。添加 & 将传递一个char (*)[n],其中n 是数组的大小——一种非常不同的类型。)
  • @JonathanLeffler 非常感谢乔纳森。当您将scanf()` 的输入分配给结构的成员时,我不知道这种情况。因此,当achar 的数组时,这种编码技术等效于scanf("%s",array);,而& 是多余的,即使不是无效的,因为array 已经指向数组的第一个元素,这是操作所必需的。
  • @RobertS-ReinstateMonica — 是的,情况基本相同。使用& 在技术上是不正确的(正如我所说),因为传入的指针类型不正确。在实践中,您通常会侥幸逃脱,但它正式是 UB(未定义的行为),应该不惜一切代价避免 UB(并且少输入一个字符是非常小的成本)。
  • 它不是下一个,因为中间有一个括号。检查运算符优先级,您会发现. 的优先级高于&

标签: c pointers scanf pass-by-reference ampersand


【解决方案1】:

在片段中:

scanf("%lf", &(*studptr).aveGrade);

& 运算符的应用就像有括号一样:

scanf("%lf", &((*studptr).aveGrade));

没有充分的理由使用(*ptr).member 而不是ptr->member;确实,显式间接表示法更冗长,当存在操作链时更是如此:

(*(*(*ptr).ptrmember).altptr).member

对比:

ptr->ptrmember->altptr->member

所以,代码应该是:

scanf("%lf", &studptr->aveGrade);

是的,两者是“等价的”,但箭头符号是惯用的 C 而另一个不是。

【讨论】:

  • 谢谢,我可以看出这个 MOOC 已经过时和/或迂腐
【解决方案2】:

因为& 不是指(*stupdtr),它指的是(*studptr).aveGrade. 运算符具有更高的优先级。

【讨论】:

  • 这么多好答案!但这是第一个也是最简洁的答案,谢谢大家!
【解决方案3】:

这两个符号指的是不同的东西。

& 正在使用aveGrade 成员的地址。

* 遵循 studptr 以获得一个结构。


如果由我决定,我会使用箭头运算符来编写指向结构的指针:

scanf("%lf", &studptr->aveGrade);

如果您希望括号澄清:

scanf("%lf", &(studptr->aveGrade) );

【讨论】:

  • '括号澄清'可能对新手程序员有用,但使用它们强调“新手”。我不能推荐他们。 YMMV——显然是这样。
【解决方案4】:

为什么不在 scanf 中使用 studptr.aveGrade?​​p>

正如你写的studptr是一个指针,所以这个表达式studptr.aveGrade是无效的。

studptr->aveGrade( *studptr ).aveGrade 都是正确的写法

所以scanf的调用可以写成这样

scanf("%lf", &studptr->aveGrade);

或喜欢

scanf("%lf", &(*studptr).aveGrade);

考虑到

&(*studptr).aveGrade

( &*studptr).aveGrade

是不同的表达方式。

第一个表达式可以用更多的括号重写,例如

& ( ( *studptr ).aveGrade )

【讨论】:

    【解决方案5】:

    确实,当& 紧接在* 之前时,两者会相互抵消。然而,这不是这里发生的事情:

    &(*studptr).aveGrade
    

    查看每个运算符:

    • * 运算符应用于括号表达式中的studptr
    • 给定(*studptr). 运算符的优先级高于&,因此接下来应用它
    • 然后将& 应用于 (*studptr).aveGrade)

    所以& 为您提供studptr 指向的aveGrade 成员的地址。如果没有括号,&* 将取消,并且您会收到语法错误,因为 studptr 是指向结构的指针,而不是结构。

    【讨论】:

      【解决方案6】:

      在结构中,aveGradedouble,所以如果你想访问它,你需要使用 & 符号将 studptr 取消引用到 aveGrade。所以在scanf中使用(*studptr).aveGrade是很荒谬的。

      【讨论】:

      • 感谢您的回答,但我认为如果您阅读其他答案,您会明白为什么这个结构并不荒谬——只是过时了。 @Johnathon Leffler 的回答 stackoverflow.com/a/59396315/3255525 解释了为什么 -> 是更好、更被接受的做法。
      • @JimLohse 是的,我知道箭头运算符比这种方式更受欢迎。在 mooc 中也应该首选他们关于箭头运算符的内容。
      猜你喜欢
      • 2011-02-24
      • 2011-10-02
      • 2021-12-25
      • 2016-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多