C语言基础

简介

C语言是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发。C语言能以简易的方式编译、处理低级存储器。C语言是仅产生少量的机器语言以及不需要任何运行环境支持便能运行的高效率程序设计语言。尽管C语言提供了许多低级处理的功能,但仍然保持着跨平台的特性,以一个标准规格写出的C语言程序可在包括类似嵌入式处理器以及超级计算机等作业平台的许多计算机平台上进行编译。(来自百度百科)

编程的7个步骤

定义程序的目标

在动手写程序之前,要在大脑中有一个清晰的思路。要想让程序去做什么首先要自己明确自己想要什么,思考你的程序需要哪些信息,要进行哪些计算和控制,以及程序应该要报告什么信息。

设计程序

例如:用户界面是怎么样的?如何组织程序?目标用户是谁?等等。除此之外还要决定在程序(或者辅助文件)中如何表示数据,以及用什么方法处理数据。

编写代码

一般而言使用编辑器创建源代码文件,这个过程中要尽量对自己的代码添加上注释,编辑环境稍后再说。

编译

编译的细节取决于编程的环境,编译器就是把源代码转换成了可执行代码的程序。可执行代码是用计算机的机器语言表示的代码,这种语言由数字码表示的指令组成。

编译器还会检查c语言程序是否有效,如果有错误就会生成错误信息提示开发者。所以理解报错信息是开发者的一个重要的技能。

运行程序

一般来讲,可执行文件是可运行的程序,在常见环境下(包括Windows、Unix、Linux)可直接执行,或者使用相应命令等。

测试和调试程序

程序能成功跑起来就是个好兆头,但是有时候也会出现错误,俗称bug,查找并修复bug的过程就叫做调试。

维护和修改代码

如果程序有bug或者要扩展程序的功能的话就要修改程序。

大部分时候编程并非像描述的那样是一个线性的过程,往往要在很多骤之间反复,特别是找bug和修复。

磨刀不误砍柴工,最好养成先规划再动手编写代码的好习惯,最好的办法就是一定要养成写注释的好习惯。

编程机制

生成程序的过程依计算机环境的不同而大有不同,特别是Windows、Linux、MacOS之间。

用C语言编写程序时,编写的内容被储存在文本文件中,称为源代码文件,大部分环境下,源代码都是以.c作为后缀名的。小数点之前叫做基本名,之后叫做扩展名,加起来就是文件名。

目标代码文件、可执行文件和库

C语言的基本策略是,用程序把源代码文件转换为可执行文件,一般的实现通过编译和链接两个步骤完成这个过程。编译器把源代码转换成中间代码,链接器把中间代码和其他代码合并,生成可执行文件。C语言利用这种方法对程序进行模块化,可编译独立的模块。还可以将你编写的程序和预编译的库代码合并。

中间文件一般最常用的形式为:把源代码转换为机器码并把结果放在目标代码文件(目标文件),所以这并不是一个完整的程序,因为它只包含转换后的机器码并不能直接运行该文件。

启动代码的作用是程序和操作系统之间的接口。还有库函数,几乎所有的C语言程序都要使用C标准库中的函数。链接器的作用是把你编写的目标代码、系统的标准启动代码和库代码合并为一个文件,即可执行文件。

创建项目

我的开发环境为Windows10 1903 教育版、VisualStudio2017 Community,偶尔示例会使用WSL下的VIM编辑器和GCC编译器或者CentOS8,现在让我们来创建第一个C语言程序吧。

第一步

空项目

然后在源.cpp右键新建即可。

第一个程序当然是hello world啦:

1
2
3
4
5
6
7
8
9
#include<stdio.h> //头文件
int main(void) //主函数
{
int num;
num = 1;
printf("hello world \n"); //语句
printf("the num is %d", num);
return 0; /*返回值*/
}

输出结果:

Linux系统输出

VS2017输出

简单的来说,c程序分为头文件、主函数、语句、函数返回值。

  • 头文件:写代码的过程中并不是所有代码都由我们自己写的,在编译器中会实现留有很多的代码都是由前辈实现写好留下来的,而这些代码都会被封装为一个又一个的头文件,提供给开发者使用,比如上面那个例子的printf 语句
  • 主函数:C语言程序包含一个或多个函数,是基本模块。上述例子中包含一个名为main 的函数,圆括号表示main() 是一个函数名,int 表明函数返回一个整数,void 表示函数不带任何参数。
  • 注释:/* */// 都是注释,编译器会忽略掉注释的内容。
  • 函数体:花括号代表函数的开始与结束。
  • 声明:int num; 这个声明表示将使用一个名为num的变量,且该变量是整数类型。
  • 赋值:num = 1; 意思是把值1赋给num变量
  • 调用函数:printf("hello world"); 这是调用了printf() 函数,在屏幕上输出hell world的信息,\n 代表换行,%d, num 代表把变量num的值输出,%d告诉计算机用什么形式在那个位置输出num的值。
  • 返回值:return 0; 简单来看就是代表main函数结束。

程序详解

#include指令和头文件

1
#include<stdio.h>

这是程序的第一行,它的作用相当于把stdio.h 文件的所有内容都输入该行所在的位置。这行代码是一条c预处理指令,编译器在编译前会对代码做一些准备工作,就是预处理。

所有的c编译器软件包都提供stdio.h文件,该文件中包含了供编译器使用的输入和输出函数,标准输入和输出头文件。

最重要的一点,在Linux系统中可以使用man 命令来调出各个头文件的使用手册和文档,例如man stdio

main()函数

一般来说c程序一定从main函数开始执行,圆括号用于识别main是一个函数,intmain() 函数的返回类型,返回给操作系统。一般情况下,圆括号内包含传入函数的信息。

注释就不多详细说了,略过。

花括号、函数体和块

花括号标记着函数体的开始和结束,一定要注意,花括号还可以用于把函数中的多条语句合并为一个单元或者块。

声明

1
int num;

声明是C语言最重要的特性之一。声明的作用有两个:第一,在函数中有一个名为num的变量,第二,int表示num变量是一个整数。int是一种数据类型,编译器使用这些信息为num变量在内存中分配存储空间,分号在C语言中是大部分语句和声明的一部分。

int是C语言的一个关键字,表示一种最基本的C语言数据类型。num是一个标识符,也就是一个变量、函数或者其他实例的名称。声明把特定标识符与计算机内存中的特定位置的信息类型或数据类型。

在C语言中所有变量都必须先声明才能使用。

简单程序

多条声明

1
int num1, num2;

或者:

1
2
int num1;
int num2;

乘法

例如:

1
2
3
num = 2 * 5;
//或者使用变量
num = 2 * var;

多个函数

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<stdio.h>
void butler(void); //ANSI/ISO C函数原型
int main(void)
{
printf("i will summon the butler function.\n");
butler();
printf("yes bring me some tea and writeable DVDs.\n");
return 0;
}
void butler(void) //函数定义开始
{
printf("you rang,sir?\n");
}

输出结果:

结果

butler 在程序中出现了三次,第一次是函数原型,告知编译器在程序中要使用该函数。第二次以函数调用出现在main中。第三次出现在函数定义中,函数定义即是函数本身的源代码。

C90新增了函数原型,旧式的编译器可能无法识别。函数原型是一种声明,告知编译器正在使用某函数,也叫做函数声明。函数原型也指明函数的属性。

要注意的是,butler 什么时候被执行,并不取决于它在程序中的位置,即使把它放在main之前也不会影响程序执行,无论main函数在哪个位置,都是从main开始执行。

C语言的标准建议,要为程序中的所有函数提供函数原型。例如stdio.h就是为printf函数提供函数原型。

调试程序

程序的错误叫做bug,调试和修改错误的过程叫做debug。

错误示范:(数字是指数)

1
2
3
4
5
6
7
8
9
10
#include<stdio.h>
int main(void)
{
int n, int n2, int n3;
n = 5;
n2 = n * n;
n3 = n2 * n2;
printf("n = %d, n squard = %d, n cubed = %d\n", n, n2. n3)
return 0;
}

语法错误

不遵循C语言语法规则的就是语法错误,第四行就是典型的语法错误,变量声明应该如下:

1
int n, n2, n3;

或者:

1
2
3
int n;
int n2;
int n3;

还有就是printf() 语句最后面没有结束的分号

语义错误

如果语法没有问题,但是编译器还是报错了,那应该考虑是语义错误,例子中的n3 = n2 * n2; n的三次方显然不会等于n的平方乘以n的平方,但是语句的语法并没有问题,这就是语义错误。

程序状态

程序状态是程序的执行过程中某给定点上的所有变量值的集合。

查看程序的运行状态可以一步一步的推算查看每个变量的状态,但是这样过于繁琐。

定位语义错误的另一种方法是:在程序中的关键点插入额外的printf() 语句,以监视制定变量值的变化,通过查看值得变化来了解程序的执行情况。

检测程序状态还有一种方法就是使用调试器,调试器可以让你一步一步运行程序并检查程序的值。

关键字和保留标识符

关键字是C语言的词汇。它们对C而言比较特殊,不能用它们作为标识符(如,变量名)。许多关键字用于指定不同的类型,如int 。还有一些关键字(如,if )用于控制程序中语句的执行顺序。

auto extern short while
break float signed _Alignas
case for sizeof _Alignof
char goto static _Atomic
const if struct _Bool
continue inline switch _Complex
default int typedef _Generic
do long union _Imaginary
double register unsigned _Noreturn
else restrict void _Static_assert
enum return volatile _Thread_local

如果使用关键字不当(如,用关键字作为变量名),编译器会将其 视为语法错误。