【C语言入门】C语言的组成结构(基础完整篇)!

C是一种具备模块化设计的命令式编程语言,具备简约、直观的设计风格,与相对清晰、简单的语言结构。编程

在谈C的语言结构以前,须要先解释一些基本元素的含义。编程语言

1、表达式

表达式是一个或多个变量、常量、函数与运算符按照特定规则的组合,表达式根据特定的优先级与运算符进行计算并返回一个值。模块化

注意:单个变量、常量或函数名也是一个表达式。函数

如下面表达式为例:学习

var = fn(1) + 5优化

其中var、fn、一、5都是表达式,其返回值为自身的值;fn(1)也是一个表达式,返回函数调用的返回值;fn(1) + 5也是一个表达式,返回算术运算的结果;var = fn(1) + 5也是一个表达式,返回赋值号左边的值,此例中此值被丢弃。spa

特别地,调用返回值为void类型的函数将返回一个void类型的值,但此值没法被使用,只能丢弃。设计

一、完整表达式

若是一个表达式不是其余表达式的子表达式,则称这个表达式为“完整表达式”。3d

如下面几个语句为例:指针

var = 1 + 2;

fn(var + 1);

if (var + 1) ;

    ✪ 表达式语句中的整个表达式为完整表达式,如上面的var = 1 + 2和fn(var + 1),但第二行的var + 1不属于完整表达式。(函数调用其实是运算符()对函数指针和参数进行运算)

    ✪ if、while、switch括号中的表达式以及for括号中的每一个份量都是完整表达式,因此第三行的var + 1是完整表达式。

 

2、反作用

除了返回值之外对程序形成的其余影响称为反作用。好比修改变量的值,执行I/O操做等。

对于以下表达式:

var = 5

表达式的返回值为5,反作用为将5赋值给变量var。

而对于如下表达式:

1 + 2

表达式返回3,没有反作用。

一般提及“反作用”,老是以为可有可无或尽可能避免,但对于命令式编程语言来讲,反作用才是程序执行的主要目的。

好比咱们调用printf函数,咱们一般并不关心它的返回值,而是须要它把特定的字符输出到屏幕,而标准输出正是这个函数的反作用。

 

3、语句

语句是C的基本执行单元,语句不返回结果,仅执行反作用。语句可分为简单语句和复合语句。

在C语言中,“;” 不是分隔符(for语句中的 “;” 除外),而是大部分语句的结尾。

申明不属于语句,由于申明一般不产生反作用,即便有时候会产生反作用(如初始化),但仍不将其视为语句,申明也以“;”结尾。

C有5种语句:

    ✪ 表达式语句

    ✪ 跳转语句

    ✪ 选择语句

    ✪ 循环语句

    ✪ 标签语句

 

一、简单语句和复合语句

简单语句指内部不包含其余语句的语句。如表达式语句和跳转语句。最简单的语句是只有一个 “;” 的空语句。

复合语句的定义与简单语句相反,即其内部有其余语句。

将几个语句用 {} 括起来就造成了复合语句“块”,最简单的复合语句是空块 {}。

复合语句能够进行屡次复合,好比块能够嵌套,复合语句的子语句能够是其余复合语句。

C语言没有else if关键字,这种语法结构只是将上一个if语句的else部分复合了另外一个if语句,将他们写在一块儿是为了使代码更简洁。

二、表达式语句

表达式语句为一个完整表达式后跟一个分号构成的语句。若表达式为空,就构成了空语句。

表达式语句是最简单也是最多见的语句。如下语句都是表达式语句:

;

1 + 2;

var = 5;

printf("hello, world\n");

三、跳转语句

跳转语句用于改变代码的执行顺序。跳转语句包括continue、break、return、goto语句。

四、选择语句

选择语句是复合语句,其做用是根据特定表达式的值对程序执行进行跳转。如if、if else、switch语句。

五、循环语句

循环语句是复合语句,其做用是根据特定表达式的值让一部分代码反复执行屡次,如while、dowhile、for语句。循环语句也能够经过选择语句和跳转语句实现。

六、标签语句

在其余语句前加上标签便是标签语句。标签语句是复合语句,能够在任何语句(包括标签语句)前添加标签。

由于申明不是语句,因此不能在申明前添加标签。对于下面的代码,gcc给出以下错误提示:

lable:

    int var = 0;

error: a label can only be part of a statement and a declaration is not a statement

case 标签是一种特殊的标签,其标志是在标签前的case关键字。case标签只能在switch语句中使用,case标签容许且只容许标签名使用整数,而且把标签的做用域限定在当前的switch语句中。

标签是语句的一部分,而不仅是个记号,因此块末尾不能是标签。

好比下面语句:

switch (var) {

case 1:

case 2:

case 3:

    ;

}

最后的分号是不能够省略的,空语句复合case 3标签造成标签语句,而后又复合case 1和case 2,因此这个块内只有一条完整的复合语句。

 

4、C语言结构

C语言代码文件包括源文件和头文件,源文件能够进行编译和连接,头文件通常经过预处理指令包含到源文件中使用。

源文件由预处理指令、申明、类型定义、函数定义和注释组成。

预处理指令和注释能够出如今源文件的任何位置而不影响其功能,而申明和类型定义的位置决定了其做用域。

申明有时会伴随定义,定义必定会包含申明。

函数定义由返回值类型、函数名、参数列表和语句块组成。语句只能出如今函数定义内部。

C源文件必须有且只能有一个main函数,C89规定,main函数的返回值必须为int类型,若是程序正常终止,应返回0。

标准的main函数应写为 int main(void); 或 int main(int argc, char const *argv[]); 。

 

5、序列点

C语言经过序列点控制反作用的执行。在该点处以前的求值的全部的反作用已经发生,在它以后的求值的全部反作用仍未开始。

序列点的存在必定程度上保证了程序按照预期执行,但仍存在一些未定义的行为。

C中的序列点不多,由于C追求效率,更少的序列点能够给编译器更多优化的空间。

注意:C中有不少符号同时承担多种功能,在不一样语境下扮演不一样的身份。

 

C的序列点包括:

一、&& 与 || 运算符

&& 与 || 运算符会先对左边的表达式求值并执行反作用。

对 && 运算符来讲,只有当左边表达式的值为1时才对右边的表达式求值并执行反作用。

这是对程序的一种优化,由于根据“与”逻辑,若是左边表达式的值为0,则总表达式的值定为0,无需对右边表达式进行计算。根据这一特性,能够写出更加符合人类逻辑的代码。

if (var != 0 && 3 == 100 / var) {}

若是没有此序列点,则可能会出现0作除数的错误。

|| 运算符同理,只有当左边表达式的值为0时才对右边的表达式求值并执行反作用。

二、逗号运算符

“,” 在C语言中有不少用途,在某些地方它是分隔符,在某些地方它是运算符。好比如下表达式:

var = 1, var = 2

这里的 “,” 不是分隔符,而是运算符。此逗号运算符的两边是两个赋值表达式,逗号表达式先对左边的表达式求值并执行反作用,此时var的值被修改成1,以后对右边的表达式求值并执行反作用,var的值被修改成2,最后,逗号表达式返回右边表达式的值,即2。

逗号表达式的特性可使两个表达式像两个表达式语句那样执行,适合用在须要用表达式代替语句块的地方,如 for 语句的括号内。

三、三元运算符 ? : 中的 ?

在 ? 前的表达式求值并执行反作用后,才判断返回其后哪一个表达式的值。而且,若是肯定返回某个表达式的值,则不会对另外一个表达式求值或执行反作用。

? : 表达式的这个特性使其行为与if else表现一致。

四、完整表达式的末尾

完整表达式的末尾也是一个序列点,这保证了表达式语句的反作用按照其书写顺序执行。

同时,根据前面对完整表达式的定义,if、while、switch括号中的表达式以及for括号中的每一个份量都是完整表达式,这些表达式的反作用也都会在语句其余部分开始前执行。

五、函数调用与返回

函数调用时参数列表中的逗号不是表达式,而是分隔符。

参数列表的求值顺序是未定义的,好比 fn(a++, b--),a++和b--的求值顺序是未知的,取决于编译器。

此处的序列点表现为在进入函数前,全部表达式的反作用都已经完成;函数返回时,返回值已经拷贝到调用处。

六、初始化末尾

由于初始化是申明的一部分,不属于语句或表达式,因此不能套用表达式的说法,但其表现是相似的。

以下申明:

int var = 5;

在分号前已经完成反作用,即把var初始化为5。

七、初始化列表中的逗号分隔符

初始化列表中的逗号是分隔符而不是运算符。

初始化列表中的表达式按照从左到右的顺序求值并执行反作用。

以下代码:

int var = 0;

int array[] = { var++, var++, var++ };

八、申明中的逗号分隔符

申明中的逗号是分隔符而不是运算符。

以下代码:

int a = 0;

int b = a++, c = a++;

b、c分别被初始化为0、1。

并且,在逗号前的变量已经申明完成,逗号后的则否则。

以下代码:

int a = 0, b = a; //Correct

int c = d, d = 0;  //Error

在申明b前,a已经申明并初始化完成,因此能够用a初始化b。而在申明c时尚未申明d,因此初始化会报错。

由于缺乏序列点,C会产生不少未定义的行为。最典型的例子是:

int var = 0;

var = var++;

根据优先级,表达式var = var++的值是肯定的,然而赋值和自增反作用的执行顺序是未定义的,因此var的值是未知的。若是用gcc编译这段代码,var的值为0,比较符合预期;但在VC++中,var的值为1。

因此咱们应避免在表达式中同时使用某一变量和它的自增表达式。


 

最后,无论你是转行也好,初学也罢,进阶也可,若是你想学编程~

【值得关注】个人 C/C++编程学习交流俱乐部!【点击进入】

问题答疑,学习交流,技术探讨,还有超多编程资源大全,零基础的视频也超棒~

相关文章
相关标签/搜索