自我介绍
大家好,我是Loaf。
这是我的第一篇技术博客,还是以 “C 语言” 学习为主题。
我是一名 DBA,从事了多年数据库相关工作,我虽然是计算机专业出身,不过在大学里一行代码都没有写过,但是我一点都没有骄傲。
说起 Loaf 这个网名,我不知道是什么时候开始就存在于我的网络世界中,甚至此刻我都不知道这是什么意思,所以我特意查了一下:
按名词解释就是“一条面包”,按动词解释就是“游手好闲”?组合一下动名词就是“游手好闲的面包”?那就用这个吧。
之前写过几篇微信公众号,不过因为各种原因并没有坚持下来。随着工作年限的增加,感觉到了某种瓶颈,为提高自身的技术能力,虽然在看书学习,但对于底层原理性的东西,吸收率不是太好,所以我就想到了学习 “C语言”这门“古老”而又难入门的语言,我也相信一定能学好。借着这个势头,将开启我的“C语言之旅”,也决定坚持写博客。
今天是学习”C语言“的第一天,主要了解”C语言“是什么。
C 语言是什么?
简单来说,C 语言就是一门编程语言(好正确的废话)。但是这并不重要,在我的认知中,编程语言也好,数据库也罢,归根结底都是为了解决某个问题。
C语言最初是作为 Unix 系统的开发工具而发明。发明至今,虽有一定年限,不过在开发语言榜单上的热度,依旧是 TOP 5 的存在,而且我认为,想要彻底了解计算机底层原理,C语言是个很不错的切入点。
源文件
什么是源文件?
简单理解就是存储代码的文件,就叫源文件。
每种语言都有特定的文件后缀,方便编译器识别,常见的文件后缀:
- C语言源文件的后缀是
.c; - C++语言(C Plus Plus)源文件的后缀是
.cpp; - Java 源文件的后缀是
.java; - Python 源文件的后缀是
.py; - JavaScript 源文件后置是
.js。
编译和链接
C语言是一门编译型计算机语言,编写完代码保存的文件叫源文件,源文件是无法被计算机读取并运行的。因为计算机只识别二进制。所以需要把代码转换成计算机可以识别并能成功运行的程序。
在 Windows 中常见的如 .exe结尾的文件就叫可执行程序,双击即可运行。当然在 Linux 中并没有这种要求,Linux 一切皆文件,格式并不重要,但是为了可读性,规范文件后缀是有必要的。
那么从源文件到生成可执行程序,就要经过编译、链接这个过程。首先通过编译会把源文件转换成CUP可识别的二进制形式, 此时并没有生成可执行程序 .exe,而是生成叫做目标文件(Object file),不同的编译器产生的文件后缀会有所不同,如Visual C++生成的后缀为.obj;GCC 产生的目标文件后缀是.o。
目标文件经过链接后,就会生成可执行程序。
那么既然在编译阶段已经生成了CUP可以识别的二进制文件,为什么还要继续做链接呢?因为编译只是把我们写的代码转换成了CUP可以识别的二进制文件,但是一个程序运行,需要依赖库,系统库,系统函数等多个因素,所以需要在链接阶段继续把这些打包生成可执行程序。
结论就是,我们编写的代码想要执行,必须经过[编译-->链接]这个过程。
注:
每个源⽂件(.c)单独经过编译器处理⽣成对应的⽬标⽂件(.obj为后缀的⽂件)
多个⽬标⽂件和库⽂件经过链接器处理⽣成对应的可执⾏程序(.exe⽂件)
头文件
前面已经介绍了源文件、编译以及链接,那么接下来看一下头文件。
我还记得大学时学习C语言,上来第一件事情就是写一行代码:
#include <stdio.h>
当时根本就不知道这是什么,也没有去研究这是什么,为什么会在这里,他有什么作用,是不是必须的。。。:smile:
通过今天的学习才知道,这就是头文件。头文件以.h结尾。具体作用会在下面介绍。
我的第一个C语言程序
#include <stdio.h>
int main() //主函数
{
printf("Hello C\n");
return 0;
}
IDE 我使用的是 Visual Studio 2022;对于初学者来说,建议使用这个。VS 除了安装包大一点,只要安装成功就可以开始 C 语言编程之旅。
其他的一些 IDE 软件,可能需要做调试,并且安装插件才可以跑C语言代码。
代码运行成功,内心非常激动。
代码解释:
#include <stdio.h> //这就是头文件,作用就是引用C语言自带的一些库函数,否则我们无法使用类似`printf()`这类函数
int main() //主函数
{
printf("Hello C\n"); //打印函数,可将Hello C 打印纸屏幕,\n 为换行符
return 0; //潜规则,默认都会带上。
}
{ } 表示函数主体部分
main函数
main 是C语言的入口,不管有多少行代码,都是从main函数开始执行。
main函数也叫做主函数,我们使用 int 定义了main函数,所以函数执行结束时需要返回整形类型的值,所以 return 0 刚好对应。
- main 函数是主函数,也是函数的入口
- 在一个项目中,main函数必须有,且只有一个。
printf函数
代码中使⽤了 printf 函数,实现了在屏幕上信息的打印。
在之前的代码中,printf打印了字符串,其实printf也可以打印其他类型的数据
int n = 100; //定义并初始化变量
printf("%d\n", n); //printf打印整型
printf("%c\n", 'q'); //printf打印字符
printf("%lf\n", 3.14); //printf打印双精度浮点型
%d、%c是占位符,会被后边的变量代替。第一位表示占位符,第二位表示占位符类型;如%d表示整型,%c表示字符。
printf 函数打印需要包含stdio.h头文件。
关键字
C语⾔中有⼀批保留的名字的符号,⽐如: int 、 if 、 return ,这些符号被称为保留字或者关键字。
- 关键字都有特殊的意义,是保留给C语⾔使⽤的
- 程序员⾃⼰在创建标识符的时候是不能和关键字重复的
- 关键字也是不能⾃⼰创建的。
C语言中32个关键字:
auto break case char const continue default do double else enum ex
float for goto if int long register return short signed sizeof
struct switch typedef union unsigned void volatile while
参考:zh.cppreference.com/w/c/keyword
字符和ASCII编码
'a'、'b'、'c'、'd' 这一类都叫做字符,C语言中使用单引号括起来。单个字符打印可以使用%c占位符。
===ASCII 是“American Standard Code for Information Interchange”的缩写,翻译过来是“美国信息交换标准代码”===
我的理解,ASCII就类似字典表,因为计算机只是别二进制,所以将各种符号以及字幕锁对应的二进制转换成十进制数字存储,方便我们查阅。
ASCII编码表
- 字符A ~ Z的ASCII码值从65~90
- 字符a ~ z的ASCII码值从97~122
- 对应的大小写字符(a和A)的ASCII码值的差值是32
- 数字字符0 ~ 9的ASCII码值从48~57
- 换⾏ \n 的ASCII值是:10
- ==在这些字符中ASCII码值从0~31 这32个字符是不可打印字符,⽆法打印在屏幕上观察==
看一段代码:
int main()
{
printf("%c\n", 'Q');
printf("%c\n", 81);//这⾥的81是字符Q的ASCII码值,也是可以正常打印的
return 0;
}
执行结果:
打印所有字符展示:
int main()
{
int i = 0;
for (i = 32; i <= 127; i++)
{
printf("%c ", i);
if (i % 16 == 15) //模16等于15时换行,也就是每行输出16个字符后换行(不包括空格)
printf("\n");
}
return 0;
}
运行结果:
字符串和\0
"Hello C"就是字符串,它由双引号括起来。
字符串打印可以使用%s,也可以直接打印。
#include <stdio.h>
int main()
{
printf("%s\n", "hello C");
printf("hello c");
return 0;
}
\0 是结束标志,如printf()在打印过程中遇到\0,就会终止打印。==字符串的结尾隐藏了\0结束符。==
下面看一段代码:
#include <stdio.h>
int main()
{
char arr1[] = {'a', 'b', 'c'};//arr1数组中存放3个字符
char arr2[] = "abc"; //arr2数组中存放字符串
printf("%s\n", arr1);
printf("%s\n", arr2);
return 0;
}
运行结果如下:
第一行打印“abc”之后出现了乱码,这是因为字符后面没有\0结束符,所以会一直打印,直到在内存中匹配到\0为止。
第二行打印正常,因为提前提到过,字符串结尾隐藏了\0。
若开启调试模式,在监视界面将arr1、arr2放入进行下一步,会发现如下现象:
所以打印字符时,需要注意这一点。
转义字符
转义这个词,虽然没有写过代码,但是作为DBA也是听过很多次;按字面理解,就是转变原来的意思,在什么场景下需要使用转移?
比如我想打印\n这个字符串,代码如下:
#include <stdio.h>
int main()
{
printf("\n");
return 0;
}
运行结果如下:
发现什么都没有打印出来。这是因为C语言把\n作为换行标识去做了处理。
那么我们想将\n作为字符串打印出来,就要使其意思转变,这就是转义,代码如下:
#include <stdio.h>
int main()
{
printf("\\n"); //对\n进行转义,使其\n不再是换行标识
return 0;
}
运行结果如下:
常见的转义字符:
| 字符 | 解释 |
|---|---|
\? | 在书写连续多个问号时使⽤,防⽌他们被解析成三字⺟词,在新的编译器上没法验证了。 |
\' | ⽤于表⽰字符常量' |
\'' | ⽤于表⽰⼀个字符串内部的双引号 |
\\ | ⽤于表⽰⼀个字符串内部的双引号 |
\a | 警报,这会使得终端发出警报声或出现闪烁,或者两者同时发⽣。 |
\b | 退格键,光标回退⼀个字符,但不删除字符。 |
\f | 换⻚符,光标移到下⼀⻚。在现代系统上,这已经反映不出来了,⾏为改成类似于 \v 。 |
\n\ | 换⾏符。 |
\r | 回⻋符,光标移到同⼀⾏的开头。 |
\t | 制表符,光标移到下⼀个⽔平制表位,通常是下⼀个8的倍数。 |
\v | 垂直分隔符,光标移到下⼀个垂直制表位,通常是下⼀⾏的同⼀列。 |
\ddd | ddd 表示 1 ~ 3 个八进制的数字。 |
\xdd | dd 表示 2 个 十六进制数字。 |
转义参考:zh.cppreference.com/w/c/languag…
语句和语句分类
C 语言中的语句分为以下 5 类:
- 空语句
- 表达式语句
- 函数调用语句
- 复合语句
- 控制语句
空语句示例:
#include <stdio.h>
int main()
{
;//空语句
return 0;
}
表达式语句示例:
#include <stdio.h>
int main()
{
int a = 20;
int b = 0;
b = a + 5; //表达式语句
return 0;
}
函数调用语句示例:
#include <stdio.h>
int Add(int x, int y)
{
return x + y;
}
int main()
{
printf("hehe\n");//函数调⽤语句
int ret = Add(2, 3);//函数调⽤语句
return 0;
}
复合语句示例:
#include <stdio.h>
void print(int arr[], int sz) //函数的⼤括号中的代码也构成复合语句
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int i = 0;
int arr[10] = { 0 };
for (i = 0; i < 10; i++) //for循环的循环体的⼤括号中的就是复合语句
{
arr[i] = 10 - i;
printf("%d\n", arr[i]);
}
return 0;
}
最后,就是控制语句。控制语句用于控制程序的执行流程,以实现程序的各种结构方式。
C语言支持三种结构:顺序结构,分支结构以及循环结构。任何语句最终都可以归纳成这三种类型的结构。
控制语句分为九种,按以下三类区分:
- 条件判断语句或叫分支语句:
- 循环执行语句:
- 转向语句:
其实在上面的代码示例中,已经多次出现了控制语句。但这一部分好像不是今天学习的重点。:smile:
注释
我觉得注释没什么好说的,身为有多年工作经验的 IT 人士,对于注释那是又爱又恨。
写与不写,看心情吧。:smile:
小结
今天收获了第一篇博客。
了解了 C 语言,也写出了我的第一个 C 程序。
收获满满,睡觉!
###### End ######