大家好,从这一期开始,我来给大家分享C语言的相关知识,本期首先给大家介绍一些C语言的基本概念,希望大家能够有所收获。
一:C语言是什么
人和人日常交流使用的是自然语言,如汉语、英语、法语......
人和计算机交流使用的是计算机语言。
人们通过计算机语言写程序,给计算机下达指令,让它去完成我们想要的工作。
目前已知已经有上千种计算机语言,C语言就是众多计算机语言中的一种,当然C++/Java/Go/Python都是计算机语言。
二:C语言的历史和辉煌
C语言最初时作为Unix操作系统的开发工具而发明的,可以认为当时发明C语言就是为了写Unix。
Unix操作系统最初是由汇编语言写的,但是汇编语言太难精通了,因此丹尼斯里奇发明C语言,并和肯汤普森使用C语言将Unix重写。

C语言一直以来一直是排行榜的前五名。
https://www.tiobe.com/tiobe-index/
三:编译器的选择-VS2022
1. 编译和链接(初识)
C语言是一门编译型的语言,我们用C语言写的代码都是文本文件,计算机只能够执行二进制文件,是看不懂文本文件的,因此,我们写的C语言代码必须要经过编译器的翻译和链接器的链接,生成二进制的可执行文件,才能被计算机执行。

C语言代码是放在 .c 为后缀的文件中的,要想得到最终运行的可执行程序,中间要经过编译和链接两个过程。

注意:每一个源文件(.c文件)单独经过编译器处理生成对应的目标文件(.obj文件)
多个目标文件和库文件经过链接器处理生成对应的可执行程序(.exe文件)

2. 编译器的对比
C语言是一门编译型的计算机语言,需要依赖编译器将计算机语言转换成机器能够识别二进制指令
接下来对比一下常见的C语言编译器和集成开发环境。
这里首先要区分一下编译器和集成开发环境:
集成开发环境(IDE)是用于提供程序来发环境的应用程序,一般集成了代码编辑器、编译器、调试器、和图形化界面等工具。可以进行编写代码、分析代码、编译代码、调试代码......
编译器仅仅是用来编译代码的。
比如:msvc、clang、gcc 就是一些常见的编译器,VS2022、XCode、DevC++、Clion......一些常见的集成开发环境。
比如:微软的VS2022(VS系列)集成了msvc,苹果的XCode继承了clang。


VS2022 集成了MSVC(安装包较大一些,安装简单,无需多余的配置,使用起来很方便)
XCode 集成了clang(苹果电脑上的开发工具)
CodeBlocks 集成了gcc(这个工具比较小众,需要配置环境,不太推荐)
DevC++ 集成了gcc(小巧,但是过于简单,对于代码风格的养成不好,一些竞赛选手使用)
Clion 是默认使用CMake,编译器是可以配置的(工具收费,暂时不推荐使用)
整体考虑,推荐使用VS2022的社区版学习C语言,免费,使用方便,工作中常见。
3. VS2022 的优缺点

四:VS项目和源文件头文件介绍
在VS上写代码,我们是需要创建项目的,直接新建项目就可以了。
在项目中就可以添加源文件和头文件。
C语言把 .c 为后缀的文件称为源文件,把 .h 为后缀的文件称为头文件。

五:第一个C语言程序
cpp
#include <stdio.h>
int main()
{
printf("hello C\n");
return 0;
}
在 VS2022 上运行代码的快捷键:Ctrl + f5
六:main 函数

七:print 和库函数


八:C语言关键字
C语言中有一批保留的名字的符号,比如:int、if、return,这些符号被称为保留字或者关键字
关键字都有特殊的意义,是保留给C语言使用的。
程序员自己在创建标识符的时候是不能和关键字重复的。
关键字也是不能自己创建的。
C语言的32个关键字如下:

注:在C99标准中加入了 inline、restrict、_Bool、_Complex、_Imaginary 等关键字。
大家有兴趣可以去了解一下,但是使用的最多的还是上面的 32 个。
注:https://en.cppreference.com/w/c/keyword.html(C语言全部的关键字介绍)
九:字符和ASCII编码
在键盘上可以敲出来各种字符,如:a,q,@,#等,这些符号都被称为字符,C语言中字符(不代表所有语言的字符都是这样)是用单引号括起来的,如:'a','b','@'。
计算机是不认识字符的,它只能识别二进制的信息。计算机中所有的数据都是以二进制的形式存储的,那么这些字符在内存中分别以什么样的二进制存储的呢?如果我们每一个人自己给这些字符中的每一个字符编一个二进制序列,这个叫做编码,为了达成共识,不引发歧义,后来美国国家标准协会(ANSI)出台了一个标准ASCII编码,C语言中的字符就遵循了ASCII编码的方式。
参考:ASCII表:https://en.cppreference.com/w/cpp/language/ascii.html
我们并不需要记住所有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 个字符是不可打印字符,无法在屏幕上观察
单个字符的打印可以使用 %c 控制格式:
cpp
#include <stdio.h>
int main()
{
printf("%c\n", 'Q');
printf("%c\n", 81);//这⾥的81是字符Q的ASCII码值,也是可以正常打印的
return 0;
}
可打印字符展示:
cpp
#include <stdio.h>
int main()
{
int i = 0;
for (i = 32; i <= 127; i++)
{
printf("%c ", i);
if (i % 16 == 15)
printf("\n");
}
return 0;
}

十:字符串和\0
C语言中使用双引号括起来的一串字符表示字符串,如:"abcdef"。
字符串的打印格式使用**%s,也可以直接打印如下。**
cpp
#include <stdio.h>
int main()
{
printf("%s\n", "hello C");
printf("hello c");
return 0;
}
注意:C语言的字符串末尾会隐藏放置一个\0字符,表示字符串的结束标志。
所以我们使用 printf() 打印字符串或者 strlen() 求字符串的长度,遇到 \0 后就自动停止了。
验证:

cpp
#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;
}

printf 打印字符串时会找\0,找不到,就不会停,因此会打印出乱码。最终停下来是因为在内存的其他未知找到了\0,但这是无法预期的。
解决方案:在字符数组后后动添加上一个\0就可以了。

十一:转义字符
转义字符,顾名思义,就是改变原有字符的意思。来达到一些效果,比如我们常见的\0,\n
\ 让 n 的意思发生了转变,n 本来是一个普通的字符,被 \ 转义为换行的意思。
关于转义字符我们首先要了解,然后要能在字符串中识别出来。
C语言中像这样的转义字符还有很多,比如:

演示代码:
cpp
int main()
{
printf("abcdnef\n");
printf("abcd\nef\n");
printf("(are you ok\?\?)\n");
// printf("%c\n", ''');
printf("%c\n", '\'');
printf("%s\n", "abc");
// printf("%s\n", """);
printf("%s\n", "\"");
return 0;
}
cpp
int main()
{
printf("c:\test\ddd\test.c\n");
printf("c:\\test\\ddd\\test.c\n");
printf("\a"); // 仔细听,有声音
printf("abcdef\b");
//getchar(); // 读取一个字符
printf("x");
getchar();
return 0;
}
cpp
int main()
{
printf("abcdef\r");
getchar();
return 0;
}
cpp
int main()
{
printf("a\taa\taaa\taaaa\taaaaa\txx");
return 0;
}
下面两种特殊的转义字符可以理解为字符的 8 进制或者 16 进制表示。


这些ASCII码值是可以自己写代码验证的,大家可以下去自己验证。
cpp
int main()
{
printf("%c\n", '\130');
printf("%c\n", '\77');
printf("%c\n", '\x30');
return 0;
}
最后给出一个练习题,来检验一下学习成果:(答案是18!!!)

注意:\t 本身算是一个字符,对齐到4或8个字符的整数倍是它转义之后的效果。
\128不能转移成为 1 个字符,8 进制表示中只能出现数字 0~7.
\1 转义后算是一个字符
转义字符参考:https://en.cppreference.com/w/c/language/escape.html
十二:语句和语句分类
C语言代码是由一条一条的语句构成的,C语言中的语句分为如下几类:
1. 空语句
空语句是最简单的,一个分号就是一条语句,空语句。
cpp
#include <stdio.h>
int main()
{
;//空语句
return 0;
}
空语句,一般出现的地方是:这里需要一条语句,但是这个语句不需要做任何事,就可以写一个空语句。
2. 表达式语句
表达式语句就是在表达式的后面加上分号。如下所示:
cpp
#include <stdio.h>
int main()
{
int a = 20;
int b = 0;
b = a + 5; //表达式语句
return 0;
}
3.函数调用语句
函数调用的时候,也会加上分号,就是函数调用语句。
cpp
#include <stdio.h>
int Add(int x, int y)
{
return x+y;
}
int main()
{
printf("hehe\n");//函数调⽤语句
int ret = Add(2, 3);//函数调⽤语句
return 0;
}
4. 复合语句
复合语句其实就是代码块,成对括号中的代码就构成一个代码块,也被称为复合语句。
cpp
#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;
}
5. 控制语句
控制语句用于控制程序的执行流程,以实现程序的各种结构方式(C语言支持三种结构:顺序结构、选择结构、分支结构),它们由特定的语句定义符组成,C语言有九种控制语句。
可以分为以下三类:
5.1. 条件判断语句也叫分支语句:if 语句、switch 语句;
5.2 循环执行语句:do while 语句、while 语句、for 语句;
5.3 转向语句:break 语句、goto 语句、continue 语句、return 语句;
后期会一一介绍,这里先做了解。
总结:
cpp
// 语句和语句分类
//int main()
//{
// ;// 空语句
// 3 + 4;//表达式语句
// printf("hehe"); // 函数调用语句
// {}//复合语句
// // 控制语句
// // if switch for while break continue goto
//
// return 0;
//}
十三:注释
当我们写的程序变得复杂后,好的注释可以帮助读者理解程序。
注释通常用于概述算法,确定变量的用途,或者理解复杂难懂的代码段。
总的来说,注释就是对代码的说明,编译器会忽略注释,因此注释对于程序的行为或性能无影响。
但是,虽然编译器会忽略注释,但是程序员不会,好的注释可以帮助我们更好的理解代码,但是不要写错误的注释,也尽量不要过度注释,不要写没有必要的注释。
当然不写注释可能会让后期阅读代码的人抓狂。
**写注释一定程度上反映了程序作者的素质,**建议大家写必要的注释,在未来找工作的时候,写代码时留下必要的注释也会给面试官留下更好的印象。
C语言有两种注释方法:注释界定符注释通常用于多行注释,而双斜线注释常用于半行或单行注释
1. /**/ 的形式
第一种方法是将注释放在/*...*/之间,内部可以分行。注释界定符注释
这种注释以/*开始,以*/结束,可以注释掉除*/以外的任何内容,包括换行符。
编译器会将落在/*和*/之间的内容全部当作注释。
cpp
/* 注释 */
/*
这是⼀⾏注释
*/
int fopen(char* s /* file name */, int mode);
/**/:这种注释方式不支持嵌套注释。
比如,请看下面的场景:

第一个/*向后寻找到第一个*/就认为注释结束了,最后的那一个*/没有匹配。
我们通常要在调试期间注释掉一些代码,由于这些代码可能包含界定符注释,因此可能出现嵌套错误。最好的方式就是用单行注释注释掉代码段的每一行。

/**/:这种注释方式千万不能忘记写结束符号*/,否则很容易出错。

上面程序本来想在第一行和第四行加两个注释说明,结果第一行忘记写了*/,就导致注释结果和我们预期不符。
**代码风格培养:**当注释界定符要跨越多行注释时,最好能显示指出其内部的程序行都属于多行注释的一部分,我们所采用的风格是,注释内的每行都以一个(*星号)开头,从而指出整个范围都是多行注释的一部分。
cpp
/*
*简单主函数:
*读取两个数,求它们的和
*/
int main()
{
int a = 0, b = 0;
scanf("%d %d", &a, &b);
printf("%d", a + b);
return 0;
}
2. // 的形式
第二种方法是将注释放在//之后,从//开始向后,这一行全部注释。这是C99标准新增的语法。
单行注释
cpp
// 这是⼀⾏注释
int x = 1; // 这也是注释
注意:不管是哪一种注释,都不能放在双引号里面。
双引号里面的注释符号,会被当作字符串的一部分,解释为普通符号,失去注释的作用。
cpp
printf("// hello /* world */ ");
上面示例中,双引号里面的注释符号,都会被视为普通字符,失去注释的作用。
特别注意:编译时,注释会被替换成一个空格,而不是什么都没有。
有这样一个问题:下面程序能否正常编译???

最后给大家留一个问题,检验一下学习成果:

好的,这一期的分享就到这里了,如果你看到了这里,别忘了一键三连~~~
谢谢大家,期待我们下一次相见。

