C语言基础知识篇
2026/8/3 10:11:02 网站建设 项目流程

目录

1.引言

2.第一个C语言程序详解

2.1.从源代码到可执行程序的过程

2.2.main 函数

2.3.printf 函数

2.4.scanf 函数

3.数据类型与变量

3.1.数据类型

3.2.sizeof 操作符

3.3.变量的命名规则与关键词

3.4.全局变量与局部变量

3.5.字符与字符串

3.6.转义字符

4.scanf 与 printf 详解

4.1.printf 的占位符与格式控制

4.2.printf 的返回值

4.3.scanf 的读取特性与格式控制

4.4.scanf 的返回值

5.结语


1.引言

在第一篇博客中我们已经尝试书写了第一个C语言程序,那么本篇博客就从这个简单的程序开始带领大家正式进入C语言的世界。

2.第一个C语言程序详解

2.1.从源代码到可执行程序的过程

如下图,这个程序的主要功能就是在屏幕上打印 Hello World ! ,当时我们是直接点击绿色小箭头来运行程序的。不过程序的实际运行需要经历编译,链接,运行三个过程。我们点击顶部导航栏的生成,选择生成解决方案,再看底下的输出栏,可以看到有一个xxx.exe文件生成。这是因为计算机运行依靠的是二进制机器码,所有储存在计算机里面的数据都是以二进制形式保存的,所以想让计算机运行我们的源代码之前需要通过编译链接形成一个计算机能理解的 .exe可执行文件。如果想要查看这个文件,我们可以右击解决方案,选择在文件资源管理器中打开文件夹,然后找到X64文件夹一直进来就能看到 .exe文件。此时我们再来回来点击绿色箭头运行程序,就能在屏幕上打印出我们想要的结果了。那么可能有小萌新会有疑惑,之前点击绿色箭头也能直接跑出结果,为什么还要多此一举?那是因为现在的编译器已经在绿色箭头里内置了编译链接指令,当我们点击绿色箭头时编译器会先检查一下代码是否进行了编译链接,然后再运行程序,所以本质上是绿色箭头一口气完成了编译链接与运行程序。尽管随着编译器的迭代,我们使用工具越来越方便,但知识的学习还是需要我们去理清楚来龙去脉。

2.2.main 函数

那么当我们了解了源代码是怎么运行的之后,我们再回来看这个源代码,上篇博客说了一个基础的C语言程序由头文件引入,主函数,主函数内的执行语句与主函数的返回语句四部分构成,这其实是C语言的语法规则规定的,就像我们学习英语要学习英语的语法一样。首先 mian 函数是一个程序的入口,所有的C语言程序都是从 main 函数开始的,所以main函数也可以叫主函数,其次 main 函数是唯一的,一个项目中仅能存在一个 main 函数,即使有多个 .c文件。main 函数前的int 是函数的返回值类型,意味着这个函数结束时必须返回一个 int 类型的值,所以 main 函数的最后有 return 0 ,虽然 C99 标准之后编译器在运行程序前会自动补充 return 0,但还是自己手动补充好,养成一个良好的写代码习惯是一个程序员必备的,关于习惯问题,本篇博客的后续部分也会提及。

2.3.printf 函数

printf 函数是一个库函数,起作用就是在屏幕上打印我们所要的结果,而在使用库函数之前需要调用包含该库函数的头文件,printf 函数的头文件就是 stdio.h,所以在 main 函数的前面写上 #include <stdio.h>。那么什么是库函数?为了提升程序员写代码的效率,C语言标准对那些常用的函数做了规定,不同的厂商在自家编译器里根据标准实现这些函数,然后封装进函数库里,基于C语言标准的函数库也叫标准库,这些库里的函数就叫库函数,而一个系列的库函数一般都声明在同一个头文件里,所以在使用库函数前需要先调用对应的头文件。更多的库函数及对应头文件查询请看这里:https://cplusplus.com/reference/clibrary

2.4.scanf 函数

那么既然 printf 是输出类型的库函数,有没有输入类型的库函数?有的,scanf 就是输入类型的库函数,两者都包含在 stdio.h 这个头文件里。此时我们对原先的代码做一点改动,就能得到下面这个既有输入又有输出的代码了。但是当我们去运行时会发现报错了,这是为什么?我们前面说了,不同的厂商基于C语言标准在编译器里实现库函数,虽然标准一致,但实际实现过程中会有偏差,这边编译器所提供的 scanf_s 是 VS 独有的,考虑到代码的通用性,我们最好还是使用 scanf。那如何解决报错问题?我们只需要将划红线的话复制下来,配上 #define 丢到整个程序的最前面就行了,此时再去运行就不会报错了。 如果想要一劳永逸,这边建议可以下载一个叫 Everything的查找工具,下载链接在这里:https://www.voidtools.com/zh-cn/downloads/。搜索 newc++file.cpp 这个文件,然后下方文件右击打开路径,将文件复制到桌面后右击选择打开方式,在记事本中打开,将刚刚程序最前面的那一整句话(#defi...INGS)复制黏贴到记事本上然后保存,将桌面上的文件剪切黏贴回文件原本所在位置,选择替换,这样每次创建.c文件时就会自动带上这句话。

3.数据类型与变量

3.1.数据类型

在刚刚那个新代码中除了 scanf,还多了int a = 0; 这条语句,那这条语句是在做什么?这里涉及到数据类型与变量的定义,我们分开来讲,先讲数据类型。我们在生活中通常会见到不同的数字,当我们问一个人的年龄时,会得到一个整数,但当我们问一件物品的价格时,这时可能得到的是一个小数。那么在C语言中也是一样,存在不同的数据类型,主要可分为内置类型与自定义类型,关于自定义类型后续博客会讲到,今天先了解内置类型。内置类型有字符型( char ),整型( short,int,long,long long ),浮点型( float,double,long double )及布尔型( _Bool ),C语言既然给出了这么多类型,那么我们怎么知道应该使用什么类型?在我们下载过的Everything 里面搜索 limits.h 这个文件,然后下方任意一个右击打开路径,将文件复制到桌面后右击选择打开方式,在 VS 中打开就能看到整型数据类型的定义,右击任意一个选择转到定义,就能在下方输出栏查看具体的范围。如果搜索 float.h 文件,按同样的方法就能知道浮点型的数据范围。在了解了C语言的数据类型和对应类型的数据范围后,我们就可以根据实际需要去选择不同的数据类型。

3.2.sizeof 操作符

不同的数据类型有不同的取值范围,那么不同的数据类型也有自己的长度,如果要计算数据类型的长度,就需要用到 sizeof 操作符。操作符是C语言中对于执行操作数据的符号的统称,被操作符操作的数据叫操作数。sizeof 的计算结果是 size_t 类型,属于无符号整型,打印格式是%zu,sizeof 的操作数除了数据类型外,还能是变量或是表达式。当操作数是变量时,sizeof 所求的结果实际上是这个变量对应的数据类型。当操作数是表达式时,最后的结果根据表达式的类型来得出大小,同时表达式不参与任何运算。

3.3.变量的命名规则与关键词

讲完了数据类型就要来讲变量创建了。C语言中把经常变化的值称为变量,而不变的值称为常量。受C语言规则影响,变量在命名时需要遵循以下规则:1.只能由数字,字母及下划线组成,且不能以数字开头;2.变量名的最大长度不能超过63个字符;3.变量名是区分大小写的;4.变量名不能和关键字重复。那什么是关键字?像前面提及的 int,char 等字样的单词,这些在C语言程序中拥有特殊含义的单词统称为关键字。除以上规定外,变量命名时也最好有意义,这样能够让别人一下就知道这个变量是用于什么的,这也是一个好的习惯。C语言中主要的关键字就是下面代码块里所列举的32个,在 C99标准中又追加了 _Bool,_Complex等关键字,具体的在这里可以查到:https://zh.cppreference.com/w/c/keyword

3.4.全局变量与局部变量

在了解了变量怎么创建之后就要了解有哪些变量以及如何使用变量。C语言中变量可以分为两类,一类是全局变量,一类是局部变量。全局变量在整个程序的任何位置都能使用,而局部变量只有在自己的作用域里生效,从下图的比较中可以看出一二。值得注意的是,当全局变量与局部变量命名冲突时,使用该变量名会优先使用局部变量的。当一个变量成功创建好后,我们就可以在变量的作用域里随意的使用他了,包括给他重新赋值,让他参与一些运算等操作。在一开始给变量命名的同时我们往往会给变量赋上一个初值,这个操作叫变量的初始化,建议大家在使用变量前都进行初始化,避免编译器在使用变量时调用随机值,产生不必要的问题。

3.5.字符与字符串

我们一开始讲过,所有数据在计算机里是按二进制形式储存的,我们在键盘上敲的 a,b,c 等称之为字符,在C语言中字符用单引号 ' ' 引用显示,形如 'a','b' ,'c' 等。但字符的二进制储存形式必须统一,不然影响代码的跨平台运行,所以美国国家标准学会出台了一套标准的ASCII编码制度,所有的字符都遵循这一套制度。在众多的字符编码里我们只需要简单记一下 'A','a','0' 这三个字符就行,掌握了这三个的ASCII码值之后,我们可以反推出日常所用的英文字符与数字字符的ASCII码值,'A' 到 'Z' 是6到90,'a' 到 'z' 是9到122,'0' 到 '9' 是48到57,值得注意的是,在所有字符里,ASCII码值在0到31的这32个为不可打印字符,无法在屏幕上看到,更多的在这里可以查到:https://zh.cppreference.com/w/cpp/language/ascii

在知道了字符的表示形式之后,那怎么表示一长串的字符?同样的,我们只要用双引号 " " 引用这一长串字符就能表示字符串了,就如最开始打印的 "Hello World !" 一样,这表示的就是字符串 Hello World ! 。字符的打印格式是%c,字符串的打印格式是%s。值得注意的是,字符串的末尾会隐藏放入一个 \0 字符用以表示字符串的结束。那能否观察到?其实是可以的,我们按 F10 进入程序的调试模式,关掉多余窗口后,按如下步骤打开监视窗口,在监视窗口里输入字符串然后展开,就能看到隐藏起来的 \0 字符了。

3.6.转义字符

在前面的内容里我们多次见到 \n,那可能有小萌新会疑惑,这个 \n 到底有什么用?其实这里就涉及到了转义字符的表示,那关于转义字符这一块只讲一下常用的几个 ,以及字符的八进制表示形式 \ddd 或字符的十六进制表示形式 \xdd,剩余的大家可以自行了解。

首先我们已经知道了字符串的表示形式是 "xxxx",那在字符串的某个或某几个字符前加上 \ ,就可以转变字符原来的意思,使其具有其他功能,那形如 "\x" 或 "\xx" 这样的就叫转义字符。

1. \n 换行符,通过打印的结果我们可以发现编译器在完成一行打印之后并不会自动换行,下一行打印信息紧跟在上一行的尾巴后面,而使用了 \n 就可以让信息换行打印。

2.\' \" \\ 这三个,根据前面的学习我们知道 ' 引起来的内容是单个字符," 引起来的是字符串,\ 用来转义,那么当我想要打印 ' 的ASCII码值或者 " 或者 \ 时,按照常规方法就会报错,那么这时候在前面加上 \ 就能正常打印了。

3.\ddd \xdd 这两个,如下图举例的 \111 与 \x33 前者表示字符 'I',后者表示字符 '3'。这边先浅谈一下进制转换内容,更多内容会在后续博客提及。我们已经知道计算机储存数据是以二进制表示,而我们日常所见的数据大多以十进制表示。就如十进制逢十进一一样,在二进制中逢而进一,所以二进制表示的数只有0与1,如果一个十进制数是10,那么它的二进制表示数就是1010,具体原因可以看图理解。十进制里每一位数是以10为基底的幂次,那么换到其他进制里就是以进制数为基底的幂次,所以八进制下的111在十进制下是73,十六进制下的33在十进制下是51,对应前面学过的ASCII码值,'A' 是65,那么73就是 'I','0'是48,那么51就是 '3'。再结合最后的示例可以看出,我们也能通过转义ASCII值来打印字符。

4.scanf 与 printf 详解

4.1.printf 的占位符与格式控制

使用 printf 函数打印时使用的%d等称之为占位符,意思是这个位置将由其他值代替,第一个字符规定为%,第二个字符代表要带入的数据的数据类型,%d就表示带入的是一个 int 类型的十进制整数。这边就举例几个常用的打印格式,更多的还请小萌新们自行探索。除了前面讲过的,常用的还有:浮点型 float 的打印格式是%f,浮点型 double 的打印格式是%lf,整型 long long 的打印格式是%lld。

除此之外 printf 函数在打印结果时可以根据我们的需要来规范输出结果的格式。

1.限制位宽,使用形如%md的格式表示这个占位符的宽度最少是m位,如果长度不足m位则会在最前面补空格,此格式是默认右对齐,如果想要左对齐在右侧补空格,可以使用形如%-md的格式。

2.限制小数位数,使用形如%.nf的格式表示在输出小数时保留n位小数,此格式可以与位宽格式结合使用。

3.限制字符串输出,使用%s打印字符串默认全部输出,但如果使用%.ms的格式表示最多输出从头开始的m个字符。

4.输出结果带正号,使用%d打印数字时,负数带符号,正数默认不带符号,但如果使用%+d的格式就可以让正数带上正号。

4.2.printf 的返回值

值得注意的是,printf 函数实际上也是有返回值的,当我们尝试打印下图代码时,会发现除了 Hello之外还有一个 6,这是因为 printf 的返回值是自己这一层在屏幕上所打印的字符个数,\n 与空格也都算是字符,此时如果在最外面再嵌套一层,则会打印 2。

4.3.scanf 的读取特性与格式控制

与 printf 函数对应的是 scanf 函数,当我们创建好变量之后,就可以利用 sacnf 函数向变量传入我们需要的值。scanf 的用法与 printf 类似,只是需要在变量名前面加上&,有关&的知识后续博客会详细讲解,这里就不展开了。我们只讲两个 scanf 函数特有的格式:

1.使用%[ ]可以对字符串进行定向筛选,他只会匹配[ ]里所有的字符,一旦遇到没有的字符就会中断读取。这边使用到了字符数组,关于字符数组是什么以及为什么没用&,我们暂且不讨论,在后续的博客里都会慢慢讲明白的。

2. scanf 对于输入的格式有严格的要求,如果想要程序不按照格式也能正常读取数据,就要使用 scanf 的赋值忽略符 * ,将 * 加在某个占位符的%后面,那么这个占位符在读取输入后就会直接丢弃而不是存入变量。

接下来我们来看一下 scanf 函数有关输入的一些特点:

1.scanf 在解读用户输入时除了%c,都会自动过滤开头的空白字符,包括空格,换行符等,如果想要跳过%c前的空白字符,需要在%c前加上一个空格,表示跳过若干个空白字符。

2.scanf 在解读用户输入时会从上一次解读遗留开始读取,直到遇到第一个空格或者读完缓存,因此 scanf 无法一下子读取一个带若干空格的字符串,除非使用多个 scanf,不过不推荐,真想实现对带空格字符串的读取可以使用 fgets 函数,但具体用法需要小萌新自研。

3.scanf 在将字符串读入字符数组时,不会检测字符串长度是否超过了数组的最大长度,从而可能引发一些问题。

4.4.scanf 的返回值

值得注意的是,scanf 函数同样也是有返回值的,当我们尝试打印下图代码时,会发现打印结果是2,这是因为 scanf 的返回值是自己成功读取到的变量个数,当我传入的7与3.41被成功读取后,scanf 将读取到的变量个数传给 printf,由 printf 打印在屏幕上。

在知道了 scanf 的这个特性之后,我们就可以写出下图代码实现批量的加法操作。EOF的全称是end of file,是文件结束的标志,在Windows系统里通常通过Ctrl+Z+Enter的形式告诉程序已经结束数据的输入,但由于VS的特殊性需要连用三次才能结束程序。

5.结语

本篇博客到这里就结束了,希望能够帮到各位刚接触C语言的小萌新们,下篇博客将继续讲解C语言的相关知识。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询