【问题标题】:Why "&" operator is not used in first Code? [duplicate]为什么在第一个代码中不使用“&”运算符? [复制]
【发布时间】:2013-11-04 22:24:52
【问题描述】:

我对 C 编程语言非常陌生。现在我正在学习记忆和指针。我正在阅读和阅读,但我不明白何时使用指针,何时不使用。只需查看以下代码即可。在我的第一个代码中,为什么我们不在 "scanf("%2s", card_name)" 这一行上使用 "&" 运算符?在我的第二个代码中,为什么我必须在“scanf("%i", &decks);" 上使用“&”运算符 我整晚都明白了。现在我来这里是为了得到一些很好的提示来理解其中的区别..

代码 1

#include <stdio.h>
#include <stdlib.h>
int main(){
    char card_name[3];
    int count=0;
    while (card_name[0]!='X') {
        int val=0;
        puts("Enter The Card Name:");
        scanf("%2s", card_name);
        switch (card_name[0]) {
            case 'K':
            case 'Q':
            case 'J':
                val=10;
                break;
            case 'A':
                val=11;
                break;
            case 'X':
                continue;
            default:
                val= atoi(card_name);
                break;
        }

        if (val<2||val>11) {
            puts("sorry this is not valid");
                break;
            }
            if (val>=2&&val<=10) {
                count++;
                printf("Then value is %i And The Count is %i\n", val, count);
                break;
            }
        }
    }
}

代码 2

#include <stdio.h>
int main() {
    int decks;
    puts("Enter a number of decks"); 
    scanf("%i", &decks);
    if (decks < 1) {
        puts("That is not a valid number of decks");
        return 1; }
    printf("There are %i cards\n", (decks * 52));
    return 0; 
}

【问题讨论】:

  • card_name 是一个数组,因此名称 card_name 已经指向一个内存位置,而不是一个“值”。 scanf 接受输入并将其放在传递的内存地址中。使用int,您需要指定地址,但数组在某种意义上已经是地址。
  • card_name 是一个数组。在评估数组表达式时,在大多数但不是所有上下文中,它会隐式转换为指向其第一个元素的指针。请参阅this answercomp.lang.c FAQ 的第 6 节。
  • @BenjaminGruenbaum 请不要教初学者数组是地址,因为它是有害的。正确声明“它被隐式转换为指针”应该不需要太多时间。
  • @BenjaminGruenbaum 挑剔正确的术语,正确的术语不是 decay,标准中没有,而是 convert
  • @BenjaminGruenbaum 标准所说的(强调我的):(C99,6.3.2.1p3)“除非 [...],类型为“类型数组”的表达式是 转换 为类型为“类型指针”的表达式,该表达式指向数组对象的初始元素,并且不是左值。”

标签: c


【解决方案1】:

您偶然发现的可能是关于 C 语言最微妙的事情:数组标识符衰减为指针的事实。当你写

char card_name[3];

您定义了一个由三个字符组成的数组。这很简单,card_name 的类型写成char ()[3]

难以掌握的部分是card_name 几乎在所有上下文中都会衰减为指向该数组第一个元素的指针,因此几乎所有提及card_name 的类型都将是char*几乎 就好像地址获取运算符被隐含地应用于任何提及数组名称。因此,当您将card_name 传递给scanf() 时,实际上是在传递一个指向其第一个元素的指针,而scanf() 使用此指针来存储名称。

另一方面,当你对整数做同样的事情时,就没有指针衰减这样的事情了。代码的行为与您期望的完全一样,每当您使用名称 decks 时,您都会获得整数的 ,而不仅仅是它的地址。这就是为什么你必须明确地从decks获取地址。

【讨论】:

    【解决方案2】:

    尝试理解间接指针级别。 Scanf 总是将 1 级指针作为参数。

    数组声明如下:

    char name[4];
    

    name 是 1 级对象。当作为参数传递时,数组衰减为指针:

    void f(char* name) { ... }
    

    其他 1 级对象:

    int* p1;
    double* d1;
    

    这些是 2 级对象:

    int** p2;
    double** d2;
    

    和0级:

    int p0;
    double d0;
    

    因此,级别是声明中的星数(或 [])。 这可以通过使用 * 和 & 在代码中进行修改。 * 取消引用指针并将级别降低 1。但 & 则相反 - 它将级别增加 1。

    所以使用上面的scanf,我们会:

    scanf("%i%i%i", &p0, p1, *p2);
    scanf("%lf%lf%lf", &d0, d1, *d2);
    

    在哪里 &p0 是级别 0 + 1 用于 & 总共 1 p1 已经是 1 *p2 是 2 - 1 级 * 总共 1

    【讨论】:

      猜你喜欢
      • 2020-12-07
      • 2019-04-16
      • 2019-10-10
      • 1970-01-01
      • 2013-10-08
      • 1970-01-01
      • 2019-07-04
      • 2010-11-26
      • 2013-02-20
      相关资源
      最近更新 更多