三天学会C语言编程|下篇
前面两篇文章(《三天学会C语言编程|上篇》和《三天学会C语言编程|中篇》)对C语言进行了基本的介绍,通过这两篇文章基本上就可以编写简单的C语言程序。本篇作为最后一篇,将介绍C语言中最为复杂的部分,也就是控制语句、指针和复合数据类型等内容。
控制语句
通过上面的知识只能写从上往下依次执行的程序。显然这个不能满足实际开发的需求,比如有的时候我们要根据不同的情况执行不同的代码,或者需要重复执行相同的代码等场景。C语言中有多中控制语句,实现对程序不同流程的控制,下面我们以例子的形式进行介绍。
#include <stdio.h> /*这个函数实现成绩的转换,如果大于等于90分则打印“优秀”, 如果在80到90之间,则打印“良好”,如果在70-80之间则打印“中等”, 如果在60到70之间则打印“及格”,否则打印“不及格”。*/ int print_score(unsigned int score) { /* if 是C语言的判断语句,用于判断是否执行后面的代码。 * 在if关键字后是具体的判断条件表达式,表达式需要 * 用括弧包括。*/ if ( score > 100 ) { /* 如果条件判断后执行的代码是多行,则需要有{作为执行体的头。 */ return -1; /*由于成绩不会大于100,因此这里返回-1,表示错误*/ } /* 如果条件判断后执行的代码是多行,则需要有}作为执行体的尾。 * 如果只有一行代码则不需要{和}两个字符*/ /* 下面进行分类打印 */ if ( score >= 90 ) { /* 语句块标识符{不一定要另起一行,可以与if在同一行。*/ printf("优秀 "); } else if ( score >= 80 ) { /* 语句 else if 表示另外一种情况。 如果上面符合条件,则不会执行本行。*/ printf("良好 "); } else if ( score >= 70 ) { printf("中等 "); } else if ( socore >= 60 ) { printf("中等 "); } else { /* else后面可以没有if语句,这样该语句不进行任何判断。如果前面都不满足条件,则到最后执行该语句。*/ printf("不及格 "); } return 0; //返回0表示执行成功 } /*上面实现了程序的分支控制,也就是不同的条件执行不同的代码。还有一种情况是需要不断执行某一项重复的计算。这时就需要用到循环语句。 下面这个函数执行连续整数的累加和,也就是从begin按1递增,一直到end的累加和。比如从5开始一直到9,也就是5 + 6 + 7 + 8 + 9。下面看看如何用循环语句实现这个功能。*/ int sum(int begin, int end) { int index = 0; int result = 0; /* 循环的关键字是for, 后面()里面的是控制语句。括弧是必须的。括弧内用分号“;”将控制语句分为3部分。第一部分进行初始化,只执行一次;第二部分进行条件判断,每次执行,如果符合条件则执行循环体({}内,这个在单行的情况下可以省略)内的内容,否则跳出循环;最后一个则执行一些额外的运算。上面三部分任何一个都可以为空,三者也可同时为空,但分号不能省略。 */ for (index = begin; index <= end; index++) { /* 这个是开始字符,同判断语句,这里不做过多解释*/ result = result + index; } return result; } /* C语言中还有另外一个关键字实现循环控制,那就是while语句。*/ int sum2(int begin, int end) { int index = 0; int result = 0; /*想必大家已经找到规律了,while循环也是关键字后面是括弧,然后是循环体。 while语句在括弧中只有一个条件判断,如果满足条件则执行循环体,如果不满足则从循环退出。*/ index = begin; while(index <= end) { result = result + begin; index ++; } } int main(void) { int score = 80; print_score( score ); sum(1, 5); sum2(1, 5); }
本文作为入门级教程并没有介绍全部的循环语句,但作为入门已经够用了。后续再详细介绍更多的用法。
指针
指针给了我们更大的权限,可以让我们直接操作系统的内存。但是指针也是C语言中最为复杂的部分,也是饱受诟病的部分。只是由于指针的存在使得C语言开发的软件出现问题的复杂度更大,也更难解决。凡事有利有弊,废话少说,我们看看什么是指针。
简单的理解,指针其实就是内存的地址。由于我们要访问内存,内存肯定要有个编号,这样我们才知道访问哪里的内存。有人可能会说,你不是在前面说通过变量名称进行访问吗?是的,但是变量名称只是在我们编程层面使用内存的方式,真正到操作系统层面都是通过内存的地址进行访问的。
了解了指针的概念之后,那我们现在谈一下什么是指针变量。我们知道变量是存储数据的,从名称上可以推测出来指针变量就是存储指针的。没错,指针变量就是存储指针的变量,也就是存储内存地址的变量。
图1 变量与指针变量示意图
为了便于说明什么是指针及指针变量,我们通过图1进行。假设我们有一个整形变量age,其中的值是0x12345,数据存储在0x1000(这里是为了便于说明,实际位置值的格式大概类似这样,0x7ffc6a95fb14)的位置。
现在我们想用另外一个变量(比如名称为age_tmp)将该变量的地址保存起来,而且可以通过age_tmp访问age变量中的内容,那该怎么办?没错,就是定义一个指针变量。如图1所示,age_tmp就是这个指针变量,它在0x0800的位置,其内部存储的值是age的地址。好了,废了半天话,那具体怎么编写代码呢?下面我们通过一个例子说明。
#include <stdio.h> int main(void) { int age = 0x12345; int *age_tmp; /* 这里是定义一个指针类型的变量,仔细看一下在变量名称前有个星号(*),这个代表变量是指针变量。这里定义的是整形指针变量,我们可以定义任何类型的指针变量。通常,某种类型的指针变量只能存储该类型变量的指针(地址)。 */ age_tmp = &age; /*这里是将变量age的地址赋值给指针变量age_tmp,注意看age前面有个与符号(&),这个是取变量地址的意思。*/ printf("age value: 0x%x ", age); /*打印变量的值*/ printf("age address: %p ", &age); /*打印变量age的地址*/ printf("age_tmp value: %p ", age_tmp); /* 打印指针变量的值*/ printf("age_tmp address: %p ", &age_tmp); /* 打印指针变量的地址*/ }
如下是程序执行后的结果,可以看出值的关系与图1是完全一致的。
age value: 0x12345 age address: 0x7ffd64adf68c age_tmp value: 0x7ffd64adf68c age_tmp address: 0x7ffd64adf690
好了,关于指针的相关内容就先介绍到这里,关于指针足够专门写一本书了。
复合数据类型
结构体
C语言最为厉害的地方在于可以支持复合数据类型,所谓复合数据类型就是可以将集中数据类型进行组合封装,形成另外一个新的数据类型。实现这种强大功能的名称叫做结构体,结构体通过struct关键字实现,并用{}界定结构体的内容。下面我们看一个具体的例子。
#include <stdio.h> /*下面是结构体的定义,需要关键字struct,后果是结构体的名字。*/ struct new_type { /*结构体具体内容有左大括弧开始。*/ int number; /*成员变量的第一根我们平时定义变量一样 */ long age; float score; }; /*结构体的具体内容以右大括弧结束,注意后面还有一个分号。*/ int main(void) { struct new_type var_name; /* 如何使用新的变量类型,定义方式与普通变量一样,只是需要有struct关键字。 */ var_name.number = 12; /* 对新类型变量成员赋值的方法,中间用点符号(.)连接变量名称和成员名称。 */ var_name.age = 15; var_name.score = 96.5; printf("score: %f ", var_name.score); }
结构体同样也可以有指针类型,本文暂时不做介绍。这部分内容我们后续专门介绍。
数组
从名称上也可以看出来,数组是指一组数。数组是用来存储一系列数据,而且是一系列相同类型的数据。
图2 数组变量示意图
如图2所示,我们假设一个整型的数组变量,名称为new_array,由图可以看出其数据在内存总会依次存放。这样有个有点,我们知道该变量的首地址,就能知道后续其它成员的地址,因此也就可以直接访问。下面我们通过实例解释一下。
#include <stdio.h> int main(void) { int new_array[4]; /* 数组的定义通过在变量名称后面根一对中括号确定,中括号里面的整数是该数组的大小,也即存储几个成员。*/ printf("first member: %d ", new_array[0]); /* 数组的访问也是通过在变量名称后面跟一个中括弧,其里面的整数表示要访问哪一个成员,需要注意的是数组的成员是从0开始的,表示第一个成员。另外,这里没有对成员进行初始化就进行访问,因此内容是随机的。 */ new_array[0] = 1; /*成员初始化的方法*/ new_array[1] = 2; printf("first member: %d ", new_array[0]); /* 初始化后再次访问 */ }
下面是运行后的结果:
first member: 4195840 first member: 2
数组可以是任何类型的上面只是数组的基本用法。数组可以一开始就初始化,也可以结合指针使用。
总结
到今天本文就算结束了,学完这些基础知识只能算刚抬起脚迈进门槛,另外一只脚还在外面呢。后面需要学习的内容还多着呢。
本文最后给大家推荐2本入门的教程《C语言入门经典》和,首先声明并非广告,本文提供电子版下载,电子版下载地址请执行如下两步获取:
1) 转发本文
2) 私信本号,发送 1213
第一本书是编程语言先驱者Ivor Horton的经典之作,是C语言方面最畅销的图书品种之一。本书集综合性、实用性为一体,是学习C语言的优秀入门教材,在世界范围内广受欢迎,口碑极佳。而且译者也是计算机领域的专家,值得作为入门级的教程。
第二本书可以作为进阶阅读,里面有很多C语言的高级特性。