目录:
前言:
笔者写博客的初衷是把自己的学习成果及见解分享给别人,并希望能够与各位大佬交流学习。由于笔者目前还是一个菜鸟,难以避免错误和存在观点片面的时候,希望各位读者帮忙指正。希望能在这里与大家共同进步。
一. C语言是什么?
C语言作为一门计算机语言,是人和计算机沟通的桥梁。⼈们是通过计算机语⾔写的程序,给计算机下达指令,让计算机⼯作的。
C语言是一门通用计算机编程语言,且广泛用于底层开发。
| 应用软件(QQ,网盘...) | 上层软件
底层软件 |
| 操作系统(windows,Linux,max...) | |
| 驱动 | |
| 电脑----硬件 |
二. 第一个C语言程序。
这⾥演⽰VS2022中创建项⽬和编写C代码。
#include<stdio.h>
int main()
{
printf("hello\n");
return 0;
}
————代码要怎么写呢?
1. 开发环境的选择 。
C语言源代码都是文本文件,文本文件本身无法直接运行,需要通过编译器的编译和链接器的链接,生成计算机能够读懂的二进制文件,才能够执行。
笔者第一次接触的环境是vs2022,这种⽤于提供程序开发环境的应⽤程序,⼀般包括代码编辑器、编译器 、调试器和 图形⽤⼾界⾯ 等⼯具。 集成了代码编写功能、分析功能、编译功能、调试功能等⼀体化的开发软件服务套叫做集成开发环境(IDE)。
笔者推荐初学者可以使用vs2022,它直接安装即可使⽤,基本不⽤额外配置环境,上⼿容易,对初学者比较友好。
关于vs2022的下载,网上有很多教程,笔者在这里就不过多赘述了。
2 .如何使用vs2022。
打开vs2022,点击创建新项目。

点开后我们发现,有很多种项目类型,我们只需要创建一个空项目即可。

点击下一步后,输入项目名称,选择好项目存放路径,我们的项目就创建好了。

进入项目,有的朋友会发现自己的界面上找不到这个解决方案资源管理器,只需要点击视图就能找到了。

现在,我们右键源文件 —> 添加 —> 新建项,就可以开始写代码了。
3. #include<stdio.h>。
#include<stdio.h> 是 C 语言中的预处理指令,作用是在程序编译前,将标准输入输出头文件( stdio.h )的内容包含到当前程序中。 stdio.h 是 “standard input - output header” 的缩写,其中包含了 printf() (输出)、 scanf() (输入)等输入输出函数的声明及相关宏定义。
简单来说,就是#include<>里面包含的文件里面有我们写代码要用上的东西,它能够帮助我们实现某种功能,因为这些功能需要经常使用,如果每次使用都要把头文件里的东西打出来,就会大大降低代码书写的效率,而通过包含头文件这一行代码就能够代替这些代码,十分方便。
注意:尖括号< >用于包含标准库头文件;英文双引号" "用于我们自定义的头文件!!
4. 数据类型介绍。
4.1 数据类型。
| 数据类型 | 打印方式 | |
| char | 字符型 | %c |
| short | 短整型 | %d |
| int | 整型 | %d |
| long | 长整型 | %ld |
| long long | 更长的整型 | %lld |
| float | 单精度浮点数 | %f |
| double | 双精度浮点数 | %lf |
| long double | 长双精度 | %lf |
| _Bool / bool | 布尔类型 |
注:打印八进制数(%0),打印十六进制数(%0x)。
布尔类型是C99中引入的专门用来表示真假的类型,用整数0表示假,非零值表示真,取值为true或false,使用布尔类型时需要包含头文件<stdbool.h>。
为什么会出现这么多类型呢? ——因为我们现实生活中要用到整数,小数。
那为什么整数有int 和 short 还用long、long long,小数有float、double这么多种类呢?为啥不只用一种数据类型来表示呢? ——数据类型的选择通常取决于我们需要存储的数据范围和精度。不同的数据类型在存储数据时所占用的内存大小和表示范围是不同的,因此我们需要根据实际需求选择合适的数据类型来存储数据。
4.2 各种数据类型的长度。
4.2.1 sizeof操作符。
sizeof 是一个关键字,也是一个编译时操作符,用于获取对象或数据类型的内存占用字节数。它的操作数可以是类型,也可以是变量或者是表达式。

sizeof的计算结果是size_t类型的。在vs2022中使用%d打印sizeof的返回值时,编译器报了警告,它说参数1也就是sizeof(a)拥有的类型size_t。所以我们打印sizeof的返回值是一般使用%zd。

sizeof中表达式不计算:sizeof 在代码进⾏编译的时候,就根据表达式的类型确定了,类型的常⽤,⽽表达式的执⾏却要在程序运⾏期间才能执⾏,在编译期间已经将sizeof处理掉了,所以在运⾏期间就不会执⾏表达式了。

4.2.2 数据类型长度。

返回值的单位是字节(Byte),这里我们来了解下计算机内存单位。
8 bit = 1 Byte,1024 Byte = 1 KB, 1024 KB = 1 MB, 1024 MB = 1 TB, 1024 TB = 1 PB。
比特(bit)是最小的计算机内存单位。
4.3 signed 和 unsigned。
C语言使用signed和unsigned关键字修饰字符型和整型类型。signed表示该类型带正负号,包含负值;unsigned表示一个类型不带正负号,只能表示零和整数。
对于整型:以int举例,int默认是带有正负号的,也就是int等同于signed int。
1 signed int a;
int类型也可以不带正负号,表示非负整数。这是就必须使用unsigned声明变量。
1 unsigned int a;
这里的int同样可以省略。
整型变量声明为unsigned的好处是,相同长度的内存可以表示的最大整数值,增大了一倍,比 如 signed int 的取值范围-2,147,483,648 - 2,147,483,647;而unsigned int 的取值范围是0 - 4,294,967,295。
对于字符型:需要注意的是,字符型与整型不同,C语言规定char类型默认是否带有正负号,由当前系统决定。也就是说,char可能是signed char 也可能是 unsigned char 。
4.4 数据类型的取值范围。
每⼀种数据类型有⾃⼰的取值范围,也就是存储的数值的最⼤值和最⼩值的区间,如果要查看当前系统上不同数据类型的极限值:limits.h ⽂件中说明了整型类型的取值范围。float.h 这个头⽂件中说明浮点型类型的取值范围。
为了代码的可移植性,需要知道某种整数类型的极限值时,应该尽量使⽤这些常量。
• SCHAR_MIN , SCHAR_MAX :signed char 的最⼩值和最⼤值。
• SHRT_MIN , SHRT_MAX :short 的最⼩值和最⼤值。
• INT_MIN , INT_MAX :int 的最⼩值和最⼤值。
• LONG_MIN , LONG_MAX :long 的最⼩值和最⼤值。
• LLONG_MIN , LLONG_MAX :long long 的最⼩值和最⼤值。
• UCHAR_MAX :unsigned char 的最⼤值。
• USHRT_MAX :unsigned short 的最⼤值。
• UINT_MAX :unsigned int 的最⼤值。
• ULONG_MAX : unsigned long 的最⼤值。
• ULLONG_MAX :unsigned long long 的最⼤值。
4.5 强制类型转换。
在操作符中还有⼀种特殊的操作符是强制类型转换,语法形式很简单,形式为: (类型)。
1 int a = 3.14
当我们把double类型的3.14赋给整型变量a时,因为两边类型不一样 ,编译器会报警告。为了 消除这个警告,我们可以使用强制类型转换:

这里的意思是将3.14强制类型转换为int类型,这种强制类型转换只取整数部分。但俗话说:强扭 的瓜不甜,只有万不得已的时候我们才去使用强制类型转换。
5. 关键字介绍。
C语⾔中有⼀批保留名字的符号,⽐如: int 、 if 、 return ,这些符号被称为保留字或者关键
字。
• 关键字有特殊的意义,是保留给C语⾔使⽤的。
• 我们在创建标识符的时候不能和关键字重复。
• 关键字不能⾃⼰创建。
C语⾔的32个常用关键字如下:
auto breakcase char constcontinue default dodouble else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while
注:https://zh.cppreference.comc/keyword(C语⾔关键字的全部介绍)
6. main函数。
C 语⾔程序不管有多少⾏代码,多少个函数,它都是从 main 函数开始执⾏的,main函数是程序的⼊⼝。 main 前⾯的 int 表⽰ main 函数执⾏结束的时候返回⼀个整型类型的值。所以在 main函数的最后写 return 0,表示返回一个数字0。
• main函数是程序的⼊⼝。
• main函数有且仅有⼀个。
• 在⼀个项⽬中有多个.c⽂件时,也只能有⼀个main函数。
一个C语言的标准如下,所以main函数也叫做主函数。
#include<stdio.h>
int main()
{
return 0;
}
写代码时需要注意:
• main函数的名字不能改变。
• 一条语句结束后,要有分号做结尾。
• 所有符号都要使用英文形式。
7. 库函数。
为了不再重复实现常⻅的代码,让程序员提升开发效率,C语⾔标准规定了⼀组函数,这些函数再由不同的编译器⼚商根据标准进⾏实现,提供给程序员使⽤。这些函数组成了⼀个函数库,被称为标准库,这些函数也被称为库函数。在这个基础上⼀些编译器⼚商可能会额外扩展提供部分函数(这些函数其他编译器不⼀定⽀持)。
⼀个系列的库函数⼀般会声明在同⼀个头⽂件中,所以库函数的使⽤,要包含对应的头⽂件。
#include<头文件>
库函数⽐较多,感兴趣的可以去c++官网了解一下:https://cplusplus.com/reference/clibrary/
8. 字符与ASCII编码。
我们在键盘上可以敲出各种符号,这些符号都被称为字符,C语⾔中字符是⽤单引号括起来的,如:'a','b','@'。
在计算机中,所有的数据都以二进制的形式存储,为了方便大家互相通信,美国国家标准学会(ANSI)出台了一个标准ASCII编码,C语言中的子符就遵循了ASCII编码的方式。
表格可以保存下来,需要时随时查看,不过还是建议记住几组比较重要的数据:
• 字符A~Z的ASCII码值是65~90。
• 字符a~z的ASCII码值是97~122。
• 字符a和A的ASCII码值的差值是32。
• 数字字符0~9的ASCII码值是48~57。
• ASCII码值0~31,这32个字符是不可打印字符。
9. 字符串。
在C语言中,使用双引号括起来的一段字符就被称为字符串,例如:"abc"就是一个字符串。字符串的打印格式有两种,可以用%s来指定,也可以直接打印。
#include<stdio.h>
int main()
{
printf("%s\n","abc");
printf("abc");
return 0;
}
在代码中,我们可以看到字符串中有三个字符,可实际上,它真的只有三个字符吗?

代码调试起来后,我们发现存放字符串"abc"的数组arr1中多出一个字符 \0 。这个 \0 是什么呢?我们再来看一段代码。

当我们将字符串中的三个字符分开存放时,调试窗口中显示数组arr2中只有三个字符,打印两个数组时,arr2会有一段意义不明的代码。

这是为什么呢?————对于字符串"abc",我们表面上看到有三个字符,实际上在它的末尾还隐藏着一个 \0 的转义字符,\0 是字符串的结束标志,当我们在打印字符串长度或者计算字符串长度时,遇到 \0 的时候就自动停止了。 如果字符数组在打印时没有遇到 \0 ,打印就不会停止,所以arr2在打印了a,b,c之后还打印了一些随机值,直到它在内存中遇到另外的 \0 时才停止打印。接下来我们来验证一下 \0 的作用:我们在arr2数组中单独放入一个 \0 ;在打印的字符串中间放上一个 \0 。
看到三次结果是一样的,都是打印到 \0 的时候就停止了。从上述的例子中我们可以直观的观察到 \0 的作用和重要性。
在这里引入一个库函数 strlen,使用时需要包含头文件 #include<string.h> 。strlen 是运行时函数,用于计算字符串长度(" \0 "前的字符数),只能针对字符串或者字符数组。

10. 语句与语句分类。
10.1 空语句。
空语句是最简单的,一个分号就代表一条语句,即空语句。
#include<stdio.h>
int main()
{
;//空语句 。
return 0;
}
空语句一般用在某个地方需要一条语句,但是这个语句不需要做任何事,就可以写一条空语句。
10.2 表达式语句。
表达式语句就是在表达式的后面加上分号。
#include<stdio.h>
int main()
{
int a = 0;
int b = 0;
b = a + 1;//表达式语句。
return 0;
}
10.3 函数调用语句。
函数调用的时候需要加上分号,即函数调用语句。
#include<stdio.h>
int add(int x,int y)
{
return x + y;
}
int main()
{
add(2,3);//函数调用语句。
int ret = add(2,3);
printf("%d\n",ret);//函数调用语句。
return 0;
}
10.4 复合语句。
复合语句就是函数块,成对括号中的代码构成一个函数块,也就是复合语句。
#include<stdio.h>
int add(int x.int y)//函数大括号中的代码构成复合语句。
{
return x + y;
}
int main()
{
int i = 0;
for(i = 0; i <= 10 ; i++)//for循环的循环体的大括号中的构成复合语句。
{
printf("haha\n");
}
int ret = add(2,3);
return 0;
}
10.5 控制语句。
控制语句⽤于控制程序的执⾏流程,以实现程序的各种结构⽅式(C语⾔⽀持三种结构:顺序结构、选择结构、循环结构),它们由特定的语句定义符组成,C语⾔有九种控制语句。
可分成以下三类:
1. 条件判断语句也叫分⽀语句:if语句、switch语句;
2. 循环执⾏语句:do while语句、while语句、for语句;
3. 转向语句:break语句、goto语句、continue语句、return语句。
11. 转义字符。
在前面我们介绍了 \0 ,在字符中像这样的一组特殊的字符是转义字符,顾名思义,就是转变原来的意思的字符。
C语⾔中像这样的转义字符还有⼀些,具体如下:
• \? :在书写连续多个问号时使⽤,防⽌他们被解析成三字⺟词,在新的编译器上没法验证了。
• \' :⽤于表⽰字符常量 ' 。
• \" :⽤于表⽰⼀个字符串内部的双引号。
• \\ :⽤于表⽰⼀个反斜杠,防⽌它被解释为⼀个转义序列符。
• \a :警报,这会使得终端发出警报声或出现闪烁,或者两者同时发⽣。
• \b :退格键,光标回退⼀个字符,但不删除字符。
• \f :换⻚符,光标移到下⼀⻚。在现代系统上,这已经反映不出来了,⾏为改成类似于\v 。• \n :换⾏符,光标移到下一行。
• \r :回⻋符,光标移到同⼀⾏的开头。
• \t :制表符,光标移到下⼀个⽔平制表位,通常是下⼀个4/8的倍数。
• \v :垂直分隔符,光标移到下⼀个垂直制表位,通常是下⼀⾏的同⼀列。
下⾯2种转义字符可以理解为:字符的8进制或者16进制表⽰形式。
• \ddd :d d d表⽰1~3个⼋进制的数字。 如: \130 表⽰字符X。
• \xdd :d d表⽰2个⼗六进制数字。如: \x30 表⽰字符0。
• \0 :null 字符,代表没有内容, \0 就是 \ddd 这类转义字符的⼀种,⽤于字符串的结束标志。
转义字符参考:https://zh.cppreference.com/w/c/language/escape
12. 什么是注释。
注释是对代码的说明,编译器会忽略注释,也就是说,注释对实际代码没有影响。注释是给程序员⾃⼰,或者其他程序员看的, 好的注释可以帮我们更好的理解代码,但是也不要过度注释,不要写没必要的注释。 我们常用的注释写法是将注释放在双斜杠 // 后面,从双斜杠到行尾都属于注释,但这种注释只能是单行,可以放在行首,也可以放在一行语句的结尾。这是C99标准新增的语法。
//注释。
int a = 0;//注释。
另外一种注释是将注释放在 /* */ 之间,内部可以分行,可以插进行内。
/* 注释一 */
/*
注释二
*/
int fopen(char* s/* file name */,int mode);
int a = 0; /* 注释三
int b = 0; /* 注释四 */
/*
int c = 0;
int d = 0; /* 注释五 */
int e = 0;
*/
上面示例中可以看出,/* */ 这种注释方式在结束时一定要记得写结束符号 */ ,否则很容易将需要的代码注释掉,而且这种注释方式不支持嵌套注释。
需要注意的是:不管哪一种注释方式,都不能放进双引号里面,双引号里面的注释符号会被视为普通字符,没有注释作用。
三. 常量与变量。
1. 变量。
1.1 变量的创建。
在前面我们介绍了数据类型,类型有什么用呢?类型是用来创建变量的。 什么是变量呢?在C语言中,经常变化的值称为变量,不变的值称为常量。
变量创建的语法形式是这样的:
1 data_type name;
2 | |
3 | |
4 数据类型 变量名
1 char ch = 'a';//字符变量
2 int age = 18;//整型变量
3 float temp = 25.2;//单精度浮点型变量
在变量创建时,我们一般赋给它一个初始值,叫做初始化,如果创建变量时不对其进行初始化,变量里的值就会是一个随机值。
1.2 变量的分类。
变量分为全局变量和局部变量。
#include<stdio.h>
int b = 100;//全局变量
int main()
{
int a = 10;//局部变量
return 0;
}
• 全局变量:在⼤括号外部定义的变量就是全局变量,全局变量的使⽤范围更⼴,整个⼯程中想使⽤,都是有办法使⽤的。
• 局部变量:在⼤括号内部定义的变量就是局部变量,局部变量的使⽤范围⽐较局限,只能在⾃⼰所在的局部范围内使⽤的。
当全局变量和局部变量名字相同时,优先使用局部变量。

1.3 变量的作用域和生命周期。
作用域: 作用域是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效的,而限定这个名字的可用性的代码范围就是这个名字的作用域。 • 局部变量的作用域是变量所在的局部范围。
• 全局变量的作用域是整个工程。
生命周期: 变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段。
• 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。
• 全局变量的生命周期是:整个程序的生命周期。
简单来说作用域就是变量在哪能用,生命周期就是变量什么时候产生,什么时候消失。
2. 常量。
2.1 字面常量。
直接以数值、字符或字符串形式写在代码中的常量。没有标识符名称,直接通过值表示,类型由值自动推导。
100; // 整数字面常量
3.14; // 浮点字面常量
'A'; // 字符字面常量
"Hello"; // 字符串字面常量
2.2 const修饰的常变量。
未被修饰的变量的值是可以被改变的,但是用const修饰后,变脸不再能被修改,有了常量属性。

上面示例中,a被称为常变量。原因是:用const修饰的变量只是在语法上将它作为常量,但它的本质是变量。
2.3 #define定义的标识符常量。
格式:#define 常量名 值 。

2.4 枚举常量。
假设我们要用到星期一到星期五7个变量,如果用#define的方法定义变量,我们需要用7行代码,而使用enum(枚举)常量能用更少的代码表示相同的意思。
1 enum DAY
2 {
3 MON, TUE, WED, THU, FRI, SAT, SUN
4 };
首个枚举常量默认值为0,后续依次+1,也可手动指定常量的值,未赋值的常量继承前一项的值+1。

四. 操作符。
1. 算术操作符。
1.1 + 和 - 。
运算符 + 和 - 用来完成加法和减法,都有两个操作数,这种操作符也叫做双目操作符。

1.2 * 和 / 。
运算符 * 和 / 用来完成乘法和除法。

需要注意的是,使用运算符 / 完成除法时,除号的两端如果是整数,执⾏的是整数除法,得到的结果也是整数。
![]()
上面示例中,尽管变量 x 的类型是浮点数 float ,但是 6 / 4 得到的结果不是 1.5 ,而是 1.0 ,这是为什么呢? 因为在C语言中的整数除法都是整除,只会返回整数部分,丢弃小数部分。如果想要得到浮点数结果,那两个操作数必须至少有一个浮点数,这时候才会进行浮点数除法,结果才会返回小数部分。

1.3 %
运算符 % 用来求两个操作数相除的余数,这个运算符只能用于整数。

由示例可以知道,结果的正负号只由第一个操作数的正负号决定。
2. 赋值操作符。
赋值操作符 = 是一个可以随时给变量赋值的操作符。变量创建时给一个值叫做初始化;变量创建好之后再给一个值,这叫做赋值。
1 int a = 0;//变量的初始化。
2 int b = 0;
3 int c = 0;
4
5 a = 5;//赋值
6 b = 3;
7 c = 3;
8 c = b = a+3;//连续赋值,从右向左依次赋值的。
虽然C语言支持这种连续赋值,但是写出来的代码不容易理解,为了方便观察代码的执行细节,还是更建议拆开来写。
C语言提供了一种方便的写法,当我们对一个数进行自增自减等操作,我们可以使用复合赋值符。
1 a += 3; //a = a + 3;
2 a -= 2; //a = a - 2;
3 a *= 4;//a = a * 4;
4 a /= 5; //a = a / 5;
5 a %= 6; //a = a % 6;
这里就只介绍这几种复合赋值符,还有更多在后面关于操作符的博客中再讲解。
3. 单目操作符。
前⾯介绍的操作符都是双⽬操作符,有2个操作数的。C语⾔中还有⼀些操作符只有⼀个操作数,被称为单⽬操作符。
++ 和 -- 是一种自增/自减的操作符,分为前置和后置。 • 前置:

计算口诀:先 +1 / -1,后使用。
• 后置:

计算口诀:先使用,后 +1 / -1 。
3.2 + 和 - 。
这⾥的 + 是正号, - 是负号,都是单⽬操作符。
运算符 + 对正负值没有影响,是⼀个完全可以省略的运算符,但是写了也不会报错。
运算符 - ⽤来改变⼀个值的正负号,负数的前⾯加上 - 就会得到正数,正数的前⾯加上 - 会得到负
数。
五. scanf和printf介绍。
1. printf。
1.1 基本用法。
printf( ) 的作⽤是将参数⽂本输出到屏幕。它名字⾥⾯的 f 代表 format (格式化),表⽰可以
定制输出⽂本的格式。
1.2 占位符。
printf( ) 可以在输出文本中指定占位符,简单来说,占位符就是帮助其他值占位置,在打印时,我们看到的就不是占位符了。

上⾯⽰例中,This is %s \n 是输出⽂本,⾥⾯的 %s 就是占位符,表⽰这个位置要⽤其他值来替换。占位符的第⼀个字符⼀律为百分号 % ,第⼆个字符表⽰占位符的类型,%s 表⽰代⼊的是⼀个字符串。
输出文本里面可以使用多个占位符。

printf() 参数与占位符是⼀⼀对应关系,如果有 n 个占位符, printf() 的参数就应该有 n +1 个。如果参数个数少于对应的占位符, printf() 可能会输出内存中的任意值。
占位符列举
• %a :⼗六进制浮点数,字⺟输出为⼩写。
• %A :⼗六进制浮点数,字⺟输出为⼤写。
• %c :字符。
• %d :⼗进制整数。// int
• %e :使⽤科学计数法的浮点数,指数部分的 e 为⼩写。
• %E :使⽤科学计数法的浮点数,指数部分的 E 为⼤写。
• %i :整数,基本等同于 %d 。
• %f :⼩数(包含 float 类型和 double 类型)。//float %f double - %lf
• %g :6个有效数字的浮点数。整数部分⼀旦超过6位,就会⾃动转为科学计数法,指数部分的 e
为⼩写。
• %G :等同于 %g ,唯⼀的区别是指数部分的 E 为⼤写。
• %hd :⼗进制 short int 类型。
• %ho :⼋进制 short int 类型。
• %hx :⼗六进制 short int 类型。
• %hu :unsigned short int 类型。
• %ld :⼗进制 long int 类型。
• %lo :⼋进制 long int 类型。
• %lx :⼗六进制 long int 类型。
• %lu :unsigned long int 类型。
• %lld :⼗进制 long long int 类型。
• %llo :⼋进制 long long int 类型。
• %llx :⼗六进制 long long int 类型。
• %llu :unsigned long long int 类型。
• %Le :科学计数法表⽰的 long double 类型浮点数。
• %Lf :long double 类型浮点数。
• %n :已输出的字符串数量。该占位符本⾝不输出,只将值存储在指定变量之中。
• %o :⼋进制整数。
• %p :指针(⽤来打印地址)。
• %s :字符串。
• %u :⽆符号整数(unsigned int)。
• %x :⼗六进制整数。
• %zd : size_t 类型。
• %% :输出⼀个百分号。
1.3 输出格式。
1.3.1 限定占位符最小宽度。
printf() 允许限定占位符的最⼩宽度。

上⾯⽰例中, %5d 表⽰这个占位符的宽度⾄少为5位。如果不满5位,对应的值的前⾯会添加空格。输出的值默认是右对⻬,即输出内容前⾯会有空格;如果希望改成左对⻬,在输出内容后⾯添加空格,可以在占位符的 % 的后⾯插⼊⼀个 - 号。

对于⼩数,这个限定符会限制所有数字的最⼩显⽰宽度。

上⾯⽰例中, %12f 表⽰输出的浮点数最少要占据12位。由于⼩数的默认显⽰精度是⼩数点后6位,所以 123.45 输出结果的头部会添加2个空格。
1.3.2 显示正负号。
默认情况下, printf() 不对正数显⽰ + 号,只对负数显⽰ - 号。如果想让正数也输出 + 号,可
以在占位符的 % 后⾯加⼀个 + 。

1.3.3 限定小数位数。
printf() 可以限定小数位数。

上面示例中,%.2f 表示保留两位小数,如果希望输出三位小数,就得写成 %.3f 。
这种写法可以和限定宽度占位符结合使用。

上⾯⽰例中, %6.2f 表⽰输出字符串最⼩宽度为6,⼩数位数为2。输出字符串的头部有两个空格。最小宽度和小数位数这两个限定值,都可以用 * 代替,通过 printf() 的参数传入。

1.4.4 限定字符串输出长度。
%s 占位符⽤来输出字符串,默认是全部输出。我们可以⽤ %.[m]s 指定输出的⻓度,其中 [m] 代表⼀个数字,表⽰所要输出的⻓度。

上面示例中,占位符%5s表示只输出前五个字符。
2. scanf。
2.1 基本用法。
创建变量后,当我们需要给变量输⼊值就可以使⽤ scanf 函数。scanf() 函数用于读取用户键盘输入,程序运⾏到这个语句时,会停下来,等待⽤⼾从键盘输⼊,⽤⼾输⼊数据、按下回⻋键后, scanf() 就会处理⽤⼾的输⼊,将其存⼊变量。
1 scanf("%d%d%f%f", &i, &j, &x, &y);
注意:变量前⾯必须加上 & 运算符,因为 scanf() 传递的不是值,⽽是地址,即将变量的地址指向⽤⼾输⼊的值。如果这⾥的变量是指针变量,那就不⽤加 & 运算符。
scanf() 函数可以一次将键盘输入读入多个变量。
1 scanf("%d",&n);
scanf() 函数处理数值占位符时,会自动过滤空白字符,包括空格、换行符等。所以,,输入数据时,有空格不会影响 scanf() 解读数据,另外,使用回车将输入分成几行也是可以的。
scanf() 处理输入时,会从上一次解读后的第一个字符开始,直至读完缓存,或者遇到不符合条件的字符为止。

上面示例中,第一次调用scanf() 时,会忽略起⾸的空格,读取到 -13 停下来,因为后⾯的 . 不属于整数的有效字符。这就是说,占位符 %d 会读到 -13 。第⼆次调⽤ scanf() 时,就会从上⼀次停⽌解读的地⽅,继续往下读取。这⼀次读取的⾸字符是 . ,由于对应的占位符是 %f ,会读取到 .45e12 ,这是采⽤科学计数法的浮点数格式。后⾯的# 不属于浮点数的有效字符,所以会停在这⾥。
2.2 scanf的返回值。
scanf() 的返回值是⼀个整数,表⽰成功读取的变量个数。如果没有读取任何项,或者匹配失败,则返回 0 。如果在成功读取任何数据之前,发⽣了读取错误或者遇到读取到⽂件结尾,则返回常量 EOF (-1)。EOF 意为 end of file ,⽂件结束标志。

上面示例为正常读取结果,如果在输入两个数后,按 ctrl + z ,将会提前结束输入。

上面示例中,我们发现在vs2022中按三次 ctrl + z 才会停止输入。如果我们一个数字都不输入,直接按三次 ctrl + z ,输出的 c 是-1,也就是EOF。

2.3 占位符。
scanf() 常⽤的占位符与 printf()基本⼀致。
要注意的是: 占位符 %c 不忽略空⽩字符,总是返回当前第⼀个字符,⽆论该字符是否为空格。如果要强制跳过字符前的空⽩字符,可以写成 scanf(" %c", &ch) ,即 %c 前加上⼀个空格,表⽰跳过零个或多个空⽩字符。
占位符 %s 的规则是,从当前第⼀个⾮空⽩字符开始读起,直到遇到空⽩字符为⽌。因为 %s 不会包含空⽩字符,所以⽆法⽤来读取多个单词,除⾮多个 %s ⼀起使⽤。另外, scanf() 遇到 %s 占位符,会在字符串变量末尾存储⼀个空字符 \0 。
scanf() 将字符串读⼊字符数组时,不会检测字符串是否超过了数组⻓度。所以,使⽤ %s 占位符时,应该指定读⼊字符串的最⻓⻓度,即写成 %[m]s ,其中的 [m] 是⼀个整数,表⽰读取字符串的最⼤⻓度,后⾯的字符将被丢弃。

在上面示例中,我们创建的name数组长度为11,是因为避免字符串末尾的 \0 超过数组长度。
2.4 赋值忽略符。
有时,⽤⼾的输⼊可能不符合预定的格式,这种情况下, scanf() 解析数据就会失败。
为了避免这种情况, scanf() 提供了⼀个赋值忽略符。只要把 * 加在任何占位符的百分号后⾯,该占位符就不会返回值,解析后将被丢弃。

上面示例中,%*c 表示这个占位符没有对应的变量,解读后不必返回。
完
448

被折叠的 条评论
为什么被折叠?



