跳转到内容

C 语言入门/C 语言入门程序

来自维基教科书,自由的教学读物

这是一个简单的 C 程序,用于计算球体的体积

/* sphere.c */

#include <stdio.h>                  /* Include header file for printf. */

#define PI 3.141592654f             /* Define a constant. */

static float sphere(float);         /* Function prototype. sphere is given internal linkage with the keyword
                                        'static' since it isn't used outside of this translation unit. */

int main(void)                      /* Main function. */
{
	float volume;               /* Define a float variable. */
	float radius = 3;           /* Define and initialize variable. */
	
	volume = sphere(radius);    /* Call sphere and copy the return value into volume. */
	printf( "Volume: %f\n", volume );  /* Print the result. */
	return 0;
}

static float sphere(float rad)             /* Definition of a volume calculating function. */
{ 
	float result;               /* "result" is defined with an automatic storage duration and block scope. */
	
	result = rad * rad * rad;
	result = 4 * PI * result / 3;
	return result;              /* "result" is returned to the function which called sphere. */
}

在这个程序中可以观察到的第一个特点是注释用 "/*" 和 "*/" 括起来。注释几乎可以放在任何地方,因为编译器会忽略它们。另一个明显的特征是程序中的单个语句以 ";" 结束。忘记 ";" 或在不需要的地方添加 ";" 是常见的 C 编程错误。代码行通过使用花括号 ("{ }") 分组为块。

C 语言区分大小写。所有 C 语言关键字都小写。程序变量和函数名称可以使用任何大小写,但按照惯例应使用小写。"常量"(稍后会讨论)按照惯例使用大写。

并非 C 程序中的所有行都是可执行语句。上面显示的一些语句是 "预处理指令"。

C 语言编译是一个多阶段过程。为了创建一个程序,C 语言编译器系统会执行以下步骤

  • 它将源文件文本通过 "C 预处理器"。它所做的只是对源文件执行各种文本操作,例如 "宏扩展"、"常量扩展"、"文件包含" 和 "条件编译",这些内容将在后面解释。预处理器的输出是用于实际编译的二级源文件。您可以将 C 预处理器视为一种特殊的自动 "文本编辑器"。
  • 接下来,它将二级源文件通过编译器本身,编译器实际上将源代码语句转换为它们的二进制等价物。也就是说,它从源文件创建一个 "目标文件"。
  • 但是,目标文件仍然无法执行。如果它使用 C 库函数,例如上面的示例中的 "printf()",则库函数的二进制代码必须与程序目标文件合并或 "链接"。此外,需要将一些寻址信息链接到目标文件,以便它可以在目标系统上加载和运行。

这些链接任务由 "链接器" 执行,链接器将一个或多个目标文件链接到二进制库文件,以创建一个可以实际运行的 "可执行" 文件。

C 语言有大量的库和库函数。C 语言本身只有很少的语句,因此它的许多功能都是通过库调用实现的。

意图用于 C 预处理器而不是 C 编译器本身的命令以 "#" 开头,被称为 "预处理指令" 或 "元命令"。上面的示例程序中有两个这样的元命令

  #include <stdio.h>

  #define PI 3.14

第一条语句 "#include <stdio.h>" 只是在编译之前将文件 "stdio.h" 的内容合并到当前程序文件中。"stdio.h" 文件包含使用标准 I/O 库所需的声明,该库提供 "printf()" 函数。

顺便说一句,"stdio.h" 文件或 "头文件" 只包含声明。库的实际代码包含在单独的库文件中,这些库文件在链接时添加。如果需要,可以创建使用自定义声明加载的自定义头文件,然后如下包含在程序中

   #include "mydefs.h"

尖括号 ("< >") 不用于自定义头文件。它们只用于定义与 C 编译器一起提供的默认头文件(在 Unix/Linux 系统上,这些文件位于目录 "/usr/include" 中)。

C 程序由一个或多个函数组成。上面的程序包含两个用户定义的函数 "main()" 和 "sphere()",以及 "printf()" 库函数。

在编写独立程序时,"main()" 函数是必需的。它定义了程序运行时自动执行的函数。所有其他函数将直接或间接由 "main()" 调用。

C 函数的调用方法是简单地指定它的名称,并在后面的括号中包含任何参数,参数之间用逗号分隔。在上面的程序中,"printf()" 函数的调用方法如下

   printf( "Volume: %f\n", volume );

此调用提供了两个参数。第一个—"Volume: %f\n"——提供文本和一些格式化信息。第二个—"volume"——提供一个数值。

函数可以返回也可以不返回值。"sphere()" 函数返回一个值,因此它的调用方法如下

   volume = sphere( radius );

函数使用 "return" 关键字返回值。在 "sphere" 的情况下,它使用以下语句返回球体的体积

   return result;

C 程序中的所有变量都必须 "声明",方法是指定它们的名称和类型。示例程序为 "main" 例程声明了两个变量

   float volume;
   float radius = 3;

——以及 "sphere" 例程中的一个变量

   float result;

"volume"、"radius" 和 "result" 的声明指定了一个浮点变量。该声明允许在需要时在声明时初始化变量,在本例中,声明 "radius" 并为其赋值 "3"。

所有这三个声明都定义了块级作用域的变量。具有块级作用域的变量只存在于声明它们的块中。可以在不同的块中声明同名的变量,而不会相互干扰。还可以声明具有文件级作用域的变量,这些变量可以由所有函数共享,方法是在翻译单元的所有块之外声明它们。默认情况下,所有具有文件级作用域的标识符都被赋予外部链接。只有使用关键字 "static" 才能将标识符赋予内部链接。像这样的声明

extern int a;

将 "a" 识别为一个 int,其存储在其他地方定义;最好是在另一个翻译单元中。

   /* global.c */

   #include <stdio.h>

   void somefunc( void );
   int globalvar;

   void main()
   {
     extern int globalvar;
     globalvar = 42;
     somefunc();
     printf( "%d\n", globalvar );
   }

   void somefunc( void )
   {
     extern int globalvar;
     printf( "%d\n", globalvar );
     globalvar = 13;
   }

除了变量声明之外,上面的示例程序还包含函数声明或 "函数原型",它允许 C 编译器对程序中对函数的调用进行检查,并在调用不正确时发出错误

   float sphere(float);

函数原型声明函数返回的值的类型(如果它不返回值,则类型将为 "void"),以及要为函数提供的参数。

最后,"printf()" 库函数为程序提供文本输出功能。可以使用 "printf()" 函数打印简单的消息,如下所示

   printf( "Hello, world!" );

——显示文本

   Hello, world!

请记住,"printf()" 不会自动添加 "换行符",以允许后续 "printf()" 在下一行显示中打印。例如

   printf( "Twas bryllig " );
   printf( "and the slithy toves" );

——打印文本

   Twas bryllig and the slithy toves

必须添加换行符 ("\n") 以强制换行。例如

   printf( "Hello,\nworld!" );

——给出

   Hello,
   world!

这些示例只打印预定义的文本常量。可以在字符串中包含 "格式代码",然后在字符串后面加上一个或多个变量,以打印它们包含的值

   printf( " Result = %f\n", result );

这将打印类似的内容

   Result = 0.5

"%f" 是格式代码,它告诉 "printf" 打印一个浮点数。举另一个例子

   printf( "%d times %d = %d\n", a, b, a * b );

——将打印类似的内容

   4 times 10 = 40

"%d" 打印一个整型数量。可以在参数列表中包含数学或字符串表达式和函数。

为了简单地打印一段文本,有一个更简单的函数 "puts()",它显示指定的文本并自动追加一个换行符

   puts( "Hello, world!" );

仅仅为了好玩,让我们看看在 ANSI 之前的 C 语言版本中,我们的示例程序会是什么样子

   /* oldspher.c */

   #include <stdio.h>
   #define PI 3.141592654

   float sphere();        /* Parameters not defined in function prototype. */

   main()
   {
     float volume;
     int radius = 3;

     volume = sphere( radius );
     printf( "Volume: %f\n", volume );
   }

   float sphere( rad )
   int rad;               /* Parameter type not specified in function header. */
   { 
     float result;

     result = rad * rad * rad;
     result = 4 * PI * result / 3;
     return result;
   }

以下部分详细阐述了本节概述的原理。

华夏公益教科书