前瞻性声明如何运作?

时间:2014-12-23 05:29:53

标签: c visual-studio-2012 recursion forward-declaration

我理解在main之前声明factorial。但是,当阶乘公式出现之后,主要如何计算答案呢?

#include <stdio.h>

long long factorial(int);

int main()
{
    int n;
    long long f;

    printf("Enter a number and I will return you its factorial:\n");
    scanf_s("%d", &n);

    if (n < 0)
        printf("No negative numbers allowed!\n"); //prevent negative numbers
    else
    {
        f = factorial(n);
        printf("The factorial of %d is %ld\n", n, f);
    }

    return 0;
}

long long factorial(int n)
{
    if (n == 0)
        return 1;
    else
        return (n * factorial(n - 1));
}

4 个答案:

答案 0 :(得分:4)

  

但是,当阶乘公式出现之后,怎么能主要计算答案呢?

首先 - main不计算答案;这是你的factorial功能为你做的。在编写程序时,我还需要了解3个步骤:

  1. 您将代码写入文件。
  2. 您编译文件并且编译器检查语法错误,在此阶段没有进行代码计算仅仅是词法分析。
  3. 然后链接发生。如果收到链接器错误,则表示您的代码编译正常,但无法找到所需的某些函数或库。这发生在我们称之为链接阶段并将阻止生成可执行文件。许多编译器同时执行编译和链接阶段。
  4. 然后当你实际运行你的代码时 - 当计算发生时,即在运行时,代码的控制流进入factorial函数。使用Debugger查看此内容。

    以下图片来自Compiling, Linking and Building C/C++ Applications

    enter image description here

    来自Wiki

      

    在计算机编程中,前向声明是声明   标识符(表示实体,如类型,变量,常量,   或<函数)程序员还没有完成   定义 ....   这对于单程编译器和单独编译器特别有用   汇编。前向声明用于需要的语言   使用前的声明;这样的相互递归是必要的   语言,因为不可能定义这样的功能(或数据   结构)在一个定义中没有前向引用:其中一个   必须首先定义函数(分别是数据结构)。它是   也可用于允许灵活的代码组织,例如,如果一个   希望将主体放在顶部,并在下面调用函数   它

    所以基本上main函数根本不需要知道factorial的工作原理。

答案 1 :(得分:1)

它以这种方式工作:让我们举一个例子来找到3的阶乘

递归:

enter image description here

因为0的阶乘为1且1的阶乘也是1,所以你可以像

那样写
if(n <= 1)
     return 1;

答案 2 :(得分:1)

  

但是,当阶乘公式出现之后,怎么能主要计算答案呢?

C程序执行的顺序仅部分取决于文本的显示顺序。

例如,查看您正在使用的printf函数。这根本不会出现在你的程序中;它位于与您的程序相关联的库中。

前向声明使得它(从翻译单元中的那一点)知道预期存在这样一个具有特定名称,参数和返回值的函数。

简单的答案是您的C程序在开始执行之前从头到尾进行处理。因此,在调用main时,C编译器已经看到并处理了factorial函数。

将地址分配给已编译的factorial函数,该地址为&#34; backpatched&#34;在程序链接时进入编译的main函数。

根本需要前向声明的原因是C是一种老式语言,最初设计为允许一次通过编译。这意味着编译器&#34;转换为转换单元中较早的函数,在看到后面的函数之前进行编译和发出。要正确编译对稍后出现的函数的调用(或者,通常出现在其他地方,就像在另一个翻译单元中一样),必须公布一些关于该函数的信息,以便在那时知道它。

答案 3 :(得分:1)

由于在main函数中编译器看到此f = factorial(n);函数时,编译器不知道它的含义。它不知道函数的定义位置,但它确实知道函数接收的参数是正确的,因为它是一个用户定义的函数,在main函数之后有definition

因此应该有一些方法告诉编译器我正在使用名为factorial的函数,该函数返回带有long longint参数的prototype;因此,您在main()之前定义了factorial函数。

无论何时调用函数prototype,编译器都会使用函数/*function prototyping is not required*/ long long factorial(int n) { //body of factorial } int main() { ... f=factorial(n); ... } 进行交叉检查,并确保正确的函数调用。

如果在main之前定义函数,则不需要函数原型。

不需要功能原型设计的示例情况:

factorial

这里,编译器知道{{1}}的定义;在main中调用它之前,它知道返回类型,参数类型和函数名称。