前言
前几天有个刚刚上大一的小朋友突然找到我,说自己选修了一门课程《C 语言程序设计》,明明已经很努力了,可就是怎么也学不会,需要我的帮助。我问需要哪方面的帮助,他犹豫了一下,说现在也不知道。
我很理解他,想起自己上大学那会儿,第一次上机调试打印 Hello World,对着 TC 2.0 那种经典的蓝色,搞了三四个小时才搞定,至今还记着走出机房下楼时的喜悦。
代码里的每个单词、每个字母都认识,可在编程的世界里连起来就是不知道啥意思,这种无力感相信困惑着很多人。
你可能听过一些老司机上手一门新的编程语言可能只需要几个小时,也许时间会更短。不用怀疑,这事儿不神奇,人也都是普通人,只是因为有方法。
每个人用的方法不一样,我只说说我自己实践过的,主要包含以下几个方面:
- 什么是代码
- 什么是写代码
- 怎么学代码
- 代码的组成
- 怎么写代码
仅供参考,大家有其他想法的,欢迎随时交流。
写代码还是很有意思的,祝大家玩的愉快。
什么是代码 ?
代码有一个别名,叫做“语言”。我们都知道人和人之间交流的重要工具就是语言,既然代码被称作语言,它也应该是一种交流工具才对。没错,代码就是人和计算机交流的工具。人和人之间交流使用的语言是汉语、英语、日语等;人和计算机之间使用的语言是 C/C++、Java、Python等。
不同的是,人是一种智慧的生物,会有自己的思考,你让一个人去吃饭,这个人可能自己改去喝水;计算机只是一台死板的机器,它绝对不会违背人的意志,只会机械地执行。与其说人和计算机是交流,不如说是人向计算机下达命令,计算机严格按顺序执行,最后把结果反馈给人。
命令就是代码 !
什么是写代码 ?
写代码就是下命令 !
既然是下命令,我们就需要搞清楚两件事情:
有哪些命令? 机器支持的命令是有限的,我们需要知道一共有哪些命令,每一条命令可以做什么事情。
下哪些命令? 机器要做哪些事情,第一步做什么、第二步做什么、...、最后做什么。
代码就是命令的合集 !
怎么学代码 ?
抓大放小 ! 先牢牢地抓住主干,再慢慢地搞定枝叶。
我们人类使用的语言实在是太复杂了,同样的一个意思可以使用很多种方式来表达。
貌似天仙、仙女下凡、花容月貌、如花似玉、花颜月貌、玉洁冰清、冰雪聪明、明艳动人、沉鱼落雁、闭月羞花、...,这些词语都是说人长得漂亮的,我们只需要知道 好看 就够了。
孔已己说过回字有四种写法,我们只需要知道 回 就够了。
主流的编程语言也已经演化发展很多年,细枝末节的东西特别的多,同样的一个事情可以使用不同的命令来表达。一开始的时候,不要陷入到过多的细节里(枝叶),掌握核心的东西(主干)最重要,可能一个事情一个命令就足够了。
相比于成百上千页的经典著作,你需要的是十几页的简明教程。代码不是文章,不需要词藻华丽,简单、直接、有效更重要。
也不是说枝叶就不重要,只是说先从主干入手,理清脉络,然后再慢慢地向枝叶延展,这个事儿需要时间。
代码的组成
不管是哪种编程语言写出来的代码,剥离掉细节,基本的组成部分都是类似的,这些 组成 就是我们需要优先掌握的主干,我们就是使用这些主干来下命令的。
因为不同的编程语言要求的语法不一样,我们这里统一使用伪代码,大家理解意思即可。
变量
还记得上小学的时候学过的 x 和 y 么?
x = 1
y = 2
...
x = 11
y = 22
x 和 y 就是变量,它们可以存储一个值(1 或 2),而且它们的值可以随着计算过程发生变化(11 或 22)。
我们是在作业本或草稿纸上面写变量的,计算机则是在内存里存储变量的,每一个变量在内存里都有自己专属的空间存储对应的变量值。
变量是有类型的,变量的类型决定着计算机使用多少内存空间存储变量值,也决定着变量值的数值范围、精度或长度之类的。不同的编程语言支持的变量类型略有不同,即使是相同的类型,占用内存空间的大小可能也是不同的。
常见的变量类型:
- 整数(int)
- 小数(double)
- 字符串(string)
- 布尔(boolean)
int a = 1
double b = 2.0
string c = "abc"
boolean d = true
变量 a、b、c 和 d 分别被声明为整数类型、小数类型、字符串类型和布尔类型。变量的值可以发生变化,变量的类型是不允许变化的。
布尔类型是一种特殊的变量类型,它的值只有 true 和 false。
示例中的这些变量是使用变量类型符号(int/double/string/boolean)显式声明的,有些编程语言是不需要显式声明类型的,它会自动根据变量值推断出变量类型。
a = 1
b = 2.0
c = "abc"
d = true
你只需要记住三点:
- 变量是用来存储值的
- 变量是有类型的
- 变量的值是可以发生变化的
变量有什么用
变量可以用来存储各种各样的数据。比如我们要存储一个人的信息:身份证号、姓名、性别、年龄,就可以使用字符串类型的变量存储身份证号和姓名,使用整数类型的变量存储性别(0 表示男,1 表示女)和年龄。
常量
常量就是一种特殊的变量,常量的值不允许发生变化,仅此而已。
常量有什么用
常量可以用来存储那些不会发生变化的数据。比如我们要存储一个口号:为人民服务,就可以使用一个字符器类型的常量来存储。
数组
如果值的数目不多,我们可以像 变量 中描述的那样,逐个声明变量;如果值的数目有很多呢,我们也机械似的一个个的声明么?必须不用!
如果值有很多,这些值的类型又是一样的,就可以把它们打包存储到一个大块的内存空间里去。这个大块的内存空间也对应着一个变量,只不过这个变量存储的不是一个值,而是多个同类型的值。
我们把这种特殊的变量叫做 数组,根据存储值类型的不同,又可以细分为整数数组、小数数组或字符串数组。
int[] a = {1, 2, 3, 4, 5}
数组里存储着多个值,这些值是有编号的:第一个数、第二个数、...,我们可以使用编号读取数数组里特定位置的值,也可以使用编号往数组里的特定位置写入值。编号在编程语言里也称为下标,只不过它是从 0 开始的。
// 读取第一个数
a[0]
// 写入第二个数
a[1] = 22
数组有什么用
数组就是多个数据的集合,这些数据的类型是相同的。比如我们要存储很多人的信息,每一个人的信息包括身份证号、姓名、性别、年龄。我们可以分别创建四个数组:
- 用于存储身份证号的字符串数组
- 用于存储姓名的字符串数组
- 用于存储性别的整数数组
- 用户存储年龄的整数数组
这四个数组的大小是相同的。对于第一个人的信息:
他的身份证号存储到身份证号数组的第一个位置; 他的姓名存储到姓名数组的第一个位置; 他的性别存储到性别数组的第一个位置; 他的年龄存储到年龄数组的第一个位置;
第二个人的信息、第三个人的信息、...,以此类推。
运算符
我们已经知道,一个数据叫做变量,多个数据叫做数组。有了数据之后,如果想要对数据进行计算,还需要知道计算规则是什么,这个计算规则有个专用术语:运算符。
数据 + 运算符 = 表达式
赋值运算符
x = 1
= 就是赋值运算符,表示把 1 赋值给变量 x。
算术运算符
z = x + y
+ 就是算术运算符,表示 x 加 y。常见的算术运算符:
- 加(+)
- 减(-)
- 乘(*)
- 除(/)
- 取余(%)
比较运算符
z = x < y
< 就是比较运算符,表示 x 小于 y。常见的比较运算符:
- 大于(>)
- 大于或等于(>=)
- 小于(<)
- 小于或等于(<=)
- 等于(\=\=)
- 不等于(!=)
比较表达式的计算结果是布尔类型,即:true 或 false。
如果 x 小于 y,那么 z 为 true;否则,z 为 false。
逻辑运算符
e = a < b && c > d
&& 就是逻辑运算符,表示且。常用的逻辑运算符:
- 与(&&,也称作且)
- 或(||)
- 非(!)
逻辑运算表达式的计算结果也是布尔类型。
e = a < b && c > d
如果 a < b 为 true,而且 c > d 为 true,那么 e 为 true;否则,e 为 false。
e = a < b || c > d
如果 a < b 为 true,或者 c > d 为 true,即两者其中之一为 true,那么 e 为 true;否则,e 为 false。
e = !(a < b)
如果 a < b 为 true,那么 e 为 false;否则,e 为 true。
运算符有什么用
假设有一群人,
people_genders[] = {0, 1, 1, 0, ..., 1}
使用数组 people_genders 存储这群人的性别,我们需要统计人群中男女各有多少人。
使用变量 man 表示性别为男的人数,使用变量 woman 表示性别为女的人数,统计开始之前两个变量均赋值为 0,需要用到 赋值运算符:
man = 0
woman = 0
获取第一个人的性别,判断性别是否为男或女,需要用到 比较运算符:
// true 表示性别为男
people_genders[0] == 0
// true 表示性别为女
people_genders[0] == 1
如果性别为男,则男的人数加一;如果性别为女,则女的人数加一,需要用到 算术运算符:
man = man + 1
woman = woman + 1
依次获取其他人的性别,重复上述过程,直到最后一个人处理完成。
最后我们想知道男女的人数是否都大于10,需要用到 逻辑运算符:
man > 10 && woman > 10
结构
整体上代码都是从上到下按 顺序 执行的,有两种特殊情况:分支 和 循环。
分支
if (表达式1) {
// 代码1
...
} else if (表达式2) {
// 代码2
...
} else {
// 代码3
...
}
if /else 实现的代码称为分支代码块,这个代码块使用表达式拆分成若干个分支,从上到下依次判断表达式的值,哪个表达式的值为 true,就执行这个表达式对应的分支代码,其它分支代码都不会被执行。
如果表达式1为 true,那么执行代码1; 如果表达式2为 true,那么执行代码2; 如果都不是,那么执行代码3。
分支结构中的表达式可以是比较表达式或逻辑表达式。
if 只能有一个,else if 可以有零个或多个,else 可以有零个或一个。
分支有什么用
回忆一下前文性别统计的例子。
如果性别为男,则男的人数加一;如果性别为女,则女的人数加一。
就可以使用分支结构实现:
if (people_genders[0] == 0) {
// 性别为男
man = man + 1
} else {
// 性别为女
woman = woman + 1
}
循环
for (表达式1; 表达式2; 表达式3) {
// 代码
}
for 实现的代码称为循环代码块,这个代码块根据三个表达式的结果多次执行代码。
一般情况下,循环用于遍历数组:
表达式1:初始化下标,仅循环开始时执行一次; 表达式2:根据下标和数组长度判断是否继续循环,可以是比较表达式或逻辑表达式,每次运行代码之前执行一次,如果表达式的值为 true,则继续运行代码;否则,结束循环; 表达式3:下标增一,每次运行代码之后会执行一次;
int[] arr = {0, 1, 2, ..., 9}
for(int index = 0; index < arr.len; index++) {
arr[index]
}
index 是遍历数组 arr 的下标变量,循环开始时:
index = 0
第一次运行代码之前,执行表达式2:
index < arr.len
0 < 10 为 true,运行代码;
第一次运行代码之后,执行表达式3:
index++
index 的值为 1;
第二次运行代码之前,执行表达式2:
...
第十一次运行代码之前,执行表达式2:
index < arr.len
此时 index 的值为 10,10 < 10 为 false,结束循环。
arr.length 表示数组的长度。
可以使用 break 或 continue 结束循环或跳过循环。
数组有什么用
回忆一下前文性别统计的例子。
依次获取其他人的性别,重复上述过程,直到最后一个人处理完成。
就可以使用循环结构实现:
for (int index = 0; index < people_genders.len; index++) {
if (people_genders[index] == 0) {
// 性别为男
man = man + 1
} else {
// 性别为女
woman = woman + 1
}
}
函数
结果类型 函数名称(参数类型1 参数名1, ..., 参数类型N 参数名 N){
// 函数体
}
函数是一个特殊的代码块,它有三部分组成:
Input:输入参数,可以有零个或多个参数; Process:函数体,也就是调用函数时会执行的代码; Output:输出结果,可以有零个或一个;
简称:IPO。
int add(int a, int b) {
return a + b
}
调用函数:
int a = 1
int b = 2
int c = add(a, b)
如果一个代码的特别长,我们可以把这个代码按照逻辑拆分成若干片段,每个版本实现成一个函数,用若干个函数调用替换大片代码,代码结构会清晰很多。
如果一个代码片段在代码中多次出现,我们可以把这个代码片段实现成一个函数,把代码片段替换成函数调用,实现代码复用。
函数有什么用
回忆一下前文性别统计的例子。
我们可以把基于性别数组统计性别人数的代码片段实现成一个函数:
(int, int) count(int[] people_genders) {
int man = 0
int woman = 0
for (int index = 0; index < people_genders.len; index++) {
if (people_genders[index] == 0) {
// 性别为男
man = man + 1
} else {
// 性别为女
woman = woman + 1
}
}
return (man, woman)
}
调用函数:
int[] people_genders = {0, 1, 1, 0, ..., 1}
int man, woman = count(people_genders)
如果有多个人群需要统计性别,使用函数的方式可以使代码结构更简单、逻辑更清晰。
其它
掌握了一门语言的变量、常量、数组、运算符、结构和函数,可以说基本上就掌握了一门语言的核心。但是,这些也仅仅是一门语言的基础,如果你想应用到实际场景中解决具体问题,还需要扩展到线程、IO、网络通信之类的。
怎么写代码?
编程语言只是解决问题工具,人是关键!
写代码之前,你需要先在脑子里把解决问题的流程思考清楚,然后把这个流程转变成伪代码,确保这个流程可以跑的通,最后才是写具体的代码。
还是那个统计性别人数的例子,最好是先把统计的过程梳理清楚:第一步做什么、第二步做什么、...,在纸上把关键节点和处理流程(分支或循环)画一画、写一写,然后再动手写代码。
结语
写代码还是很有意思的,祝大家玩的愉快。