C语言:基础知识

简介: C语言:基础知识

创作不易,友友们给个三连吧

一、C语⾔的基本概念与发展历史

1.1 人和计算机进行交流的语言

       通常,我们使用英语、中文等语言来进行两个人之间的交流。这意味着当我们想要和他人进行交流时,我们需要一种语言来表达自己的感受。同样的,当我们想要和计算机进行交流时,我们也需要一种语言,可以通过该语言向计算机提供信息,传达指令,我们称该语言为计算机语言。

      然而C语言只不过是众多语言中的一种,像C++/Java/Go/Python都是计算机语⾔。

1.2 C语言的辉煌和历史

C 语⾔最初是作为 Unix 系统的开发⼯具⽽发明的。

类似的操作系统还有:windows、linux、macos(苹果)……

1.3“C生万物,编程之本”

C语言的四大领域:

游戏:目前很多游戏客户端都是基于C++开发的,除了一些网页游戏可能不是,所以如果想从事游戏开发行业学好C++是没错的。

服务器端开发:很多互联网公司的后台服务器程序都是基于C++开发的,而且大部分是linux,unix等类似操作系统。如果你想从事这样的工作,需要熟悉linux操作系统及其在上面的开发,熟悉数据库开发,精通网络编程。

数字图像处理:现在市面上有很多VC++图像处理的书籍,可见在这个领域的应用软件开发也是占了很大比重,需要深入学习数字图像处理和模式识别等课程。

虚拟现实仿真:这个也是发展很快的计算机领域,目前各种数字地球,数字城市,虚拟地理环境什么的,出现了这方面的大量应用

       C语言出现时间较早,其他语言基本都是在C语言之后出现,或者在C语言的基础上进行创造,比如Java,C++是两门很有代表性的语言。

       并且 学习了之后,语言的通用性还是存在的,所以在学习其他的语言的时候,学习起来就相对会简单一点。

       TIOBE网站上可以查到每年编程语言的使用排名,其中c语言常见保持前3,

网址:https://www.tiobe.com/tiobe-index/

二、编译器的选择和使用方法

2.1 编译和链接

       C语⾔是⼀⻔编译型计算机语⾔C语言源代码都是文本文件,文本文件本身无法执行,必须通过编译器翻译和链接器的链接,生成二进制的可执行文件,可执行文件才能执行。(计算机识别的是二进制指令) C语⾔代码是放在 .c 为后缀的⽂件中的,要得到最终运⾏的可执⾏程序,中间要经过编译和链接2个过程。

      ⼀个工程⼀般都会有多个源文件组成,如下图所示,演示了源程序经过编译器和链接器处理的过程。

.c→.obj→.exe

⼀个工程⼀般都会有多个源文件组成,如下图所示,演示了源程序经过编译器和链接器处理的过程。

1. 每个源文件(.c)单独经过编译器处理⽣成对应的目标⽂件(.obj为后缀的⽂件)

2. 多个⽬标⽂件和库文件经过链接器处理⽣成对应的可执行程序(.exe⽂件)

2.2 编译器对比和选择

        C语⾔是⼀⻔编译型的计算机语⾔,需要依赖编译器将计算机语⾔转换成机器能够执⾏的机器指令。

        那我们常⻅的C语⾔编译器都有哪些呢? ⽐如:msvc、clang、gcc 就是⼀些常⻅的编译器,当然也有⼀些集成开发环境如:VS2022、 XCode、CodeBlocks、DevC++、Clion等。

集成开发环境(IDE):⽤于提供程序开发环境的应⽤程序,⼀般包括代码编辑器、 编译器 、 调试器 和 图形⽤⼾界⾯ 等⼯具。 集成了代码编写功能、分析功能、编译功能、调试功能等⼀体化的开发软件服务套。

VS2022 集成了MSVC(安装报包较⼤⼀些,安装简单,⽆需多余配置,使⽤起来⾮常⽅便)

XCode 集成了clang(苹果电脑上的开发⼯具)

CodeBlocks 集成了gcc(这个⼯具⽐较⼩众,需要配置环境,不太推荐)

DevC++ 集成了gcc(⼩巧,但是⼯具过于简单,对于代码⻛格的养成不好,⼀些竞赛使⽤)

Clion 是默认使⽤CMake,编译器是可以配置的(⼯具是收费,所以暂时推荐⼤家使⽤)

VSCode 具有强大的插件系统,可安装各种插件,来搭建c/c++的开发环境(不推荐新手使用)

新手推荐使用VS2022社区版本,免费并且使用方便。

2.3 VS的优缺点和下载方法

优点:

• VS2022 是⼀个主流的集成开发环境,企业中使⽤较为普遍

• VS2022 包含了:编辑器+编译器+调试器,功能强⼤

• 直接安装即可使⽤,基本不⽤额外配置环境,上⼿容易

• 默认界⾯是中⽂的,初学者友好

缺点:

• 功能丰富,安装包⼤,占⽤空间多。

下载方法https://visualstudio.microsoft.com/zh-hans/downloads/

安装教程https://www.bilibili.com/video/BV11R4y1s7jz/

2.4 VS项目和源文件、头文件介绍

在项⽬中就可以添加源⽂件和头⽂件。

C语⾔把 .c 为后缀的⽂件称为源⽂件,把 .h 为后缀的⽂件称为头⽂件。

2.5 在VS上创建新项目

2.5.1 写代码的前的步骤

1、创建项目(代码是在项目中管理的)

2、创建.c文件

3、写C语言代码,邀严格按照C语言的语法来写!!

2.5.2 项目名称

1、项目名称最好有自己的实际意义

2、项目名称最好不要使用后中文

3、不要使用特殊字符

2.5.3 项目存储路径

1、代码的位置邀自己找一个熟悉的路径维护起来

2、这个代码的路径不要包括空格、特殊字符、中文字符

三、main函数

每个 C 语⾔程序不管有多少⾏代码,都是从 main 函数开始执⾏的, main 函数是程序的⼊⼝, main 函数也被叫做:主函数。 main 前⾯的 int 表⽰ main 函数执⾏结束的时候返回⼀个整型类 型的值。所以在 main 函数的最后写 return 0; 正好前后呼应。

• main函数是程序的入口

• main函数有且仅有⼀个

• 即使⼀个项⽬中有多个.c⽂件,但是只能有⼀个main函数(因为程序的入口只能有⼀个)

• main函数可以出现在任意位置,若在主函数中调用的哪些函数,则必须在main函数之前对所调用的函数进行声明,或者包含其被调用函数的头文件

• 一般约定返回0,在c语言中正常在返回0,异常会返回非0

int main()
{
printf("hello C\n");
return 0;
}

在VS2022上运⾏代码的快捷键: Ctrl+f5

四、关键字介绍

     C语⾔中有⼀批保留的名字的符号,⽐如: int 、 if 、 return ,这些符号被称为保留字或者关键 字。

     • 关键字都有特殊的意义,是保留给C语言使用的

     • 程序员自己在创建标识符的时候是不能和关键字重复的

     • 关键字也是不能自己创建的。 C语言的32个关键字如下:

注:在C99标准中加⼊了 inline 、 restrict 、 _Bool 、 _Comploex 、 _Imaginary 等关键字。 ⼀些关键字⼤家可以去了解⼀下,不过使⽤最多的还是上⾯的32个关键字。

注:https://zh.cppreference.com/w/c/keyword(C语⾔关键字的全部介绍)

注: difine不是关键字,他是编译器实现的用来定义宏的预处理指令,不是c语言中的内容。

五、字符和ASCII编码

        在键盘上可以敲出各种字符,如:a,q,@,#等,这些符号都被称为字符,C语⾔中字符是⽤单引号 括起来的,如:'a','b','@'。单个字符的打印可以使用%c来指定格式。

       我们知道在计算机中所有的数据都是以二进制的形式存储的,那这些字符在内存中分别以什么样的⼆进制存储的呢?如果我们每个⼈⾃⼰给这些字符中的每个字符编⼀个⼆进制序列,这就叫做编码,为了⽅便⼤家相互通信,不造成混乱,后来美国国家标准学会(ANSI)出台了⼀个标准 ASCII 编码,C语言中的字符就遵循了ASCII 编码的⽅式。

参考:https://zh.cppreference.com/w/cpp/language/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个字符是不可打印字符,无法打印在屏幕上观察

• 字符其实也属于整型家族

比如:可打印字符展示(32-127)

#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 1 2 3 4 5 6 7 8 9 : ; < = > ?

@ A B C D E F G H I J K L M N O

P Q R S T U V W X Y Z [ \ ] ^ _

` a b c d e f g h i j k l m n o

p q r s t u v w x y z { | } ~

六、字符串和\0

使用双引号括起来的一串字符就被称为字符串,如:“abcdef”,就是一个字符串。

字符串的打印格式可以使用 %s 来指定,也可以直接打印如下:

#include <stdio.h>
int main()
{
 printf("%s\n", "hello C");
 printf("hello c");
 return 0;
}

       C语⾔字符串中⼀个特殊的知识,就是在字符串的末尾隐藏放着⼀个 \0 字符,这个 \0 字符是字符串 的结束标志。

     为了观察这一现象,我们要在调试中找到监视功能,它在VS2022里面的路径是:【调试】->【窗口】->【监视】,但当我们打开此路径,我们并没有找到监视的功能。

原因是:监视必须是代码在调试的条件下进行,所以按下ctrl+F10,开始调试程序,此时再来到刚才的路径,就能找到监视的窗口了。

左边出现箭头即为进入调试阶段

     在进入调试状态后,比如想要监视某一个变量,添加本代码变量于监视窗口中添加完待监视项后,按f10 代码会一步一步运行,待监视项便也随着代码运行进行改变。

      我们可以发现对于字符串"abcdef",我们实际上看到了6个字符:a,b,c,d,e,f,但是实际上在末尾还隐藏⼀个 \0 的 转义字符, \0 是字符串的结束标志。所以我们在使⽤库函数 printf() 打印字符串或者 strlen() 计算字符串⻓度的时候,遇到 \0 的时候就⾃动停⽌了。

监视窗口的优点:

1.便于理解代码,对代码工作原理运行顺序的理解都很有帮助

2.可以方便地在大型工作表中检查、审核或确认公式计算及其结果。. 使用“监视窗口”,无需反复滚动或定位到工作表的不同部分。

注:C语⾔中也可以把⼀个字符串放在⼀个字符数组中,我们在这里利用下⾯的代码验证⼀下 \0 的功能。

#include<stdio.h>
int main()
{
  char arr1[] = { 'a', 'b', 'c' };//arr1数组中存放3个字符
  char arr2[] = "abc"; //arr2数组中存放字符串
  printf("%s\n", arr1);//不含有/0,所以没有停止的标志,会一直输出下去,会出现一些随机值
  printf("%s\n", arr2);//含有/0,所以会输出到停止
  return 0;
}

abc烫烫烫烫烫烫烫烫烫烫烫烫烫烫蘟bc
abc

      我们可以看到, arr1 字符数组在打印的时候,打印了 a 、 b 、 c 后还打印了⼀些随机值,这就是 因为 arr1 在末尾的地⽅没有 \0 字符作为结束标志,在打印的时候没有停⽌。

      但是 arr2 的打印就是完全正常的,就是因为 arr2 数组是使⽤字符串常量初始化的,数组中有 \0 作为技术标志,打印可以正常停⽌。

如果我们在arr1数组中单独放⼀个 '\0' 字符呢?

#include<stdio.h>
int main()
{
  char arr1[] = { 'a', 'b', 'c' ,'\0'};//arr1数组中存放3个字符
  char arr2[] = "abc"; //arr2数组中存放字符串
  printf("%s\n", arr1);
  printf("%s\n", arr2);
  return 0;
}

abc

abc

     则我们可以发现打印的结果是⼀样的了,都是打印到 \0 的时候就停⽌了,由此可以说明\0的作用以及重要性。

七、转义字符

也许在前⾯的代码中你看到 \n , \0 很纳闷时啥。其实在字符中有⼀组特殊的字符是转义字符,转义 字符顾名思义:转变原来的意思的字符。

C语⾔中像这样的转义字符,具体如下:

• \? :在书写连续多个问号时使⽤,防⽌他们被解析成三字⺟词,在新的编译器上没法验证了。

• \' :⽤于表⽰字符常量'(想打印单引号时用\将'转换成字符)

• \" :⽤于表⽰⼀个字符串内部的双引号(想打印双引号时用\将'转换成字符)

• \\ :⽤于表⽰⼀个反斜杠,防⽌它被解释为⼀个转义序列符。(相当于\\=1个\)

• \a :警报,这会使得终端发出警报声或出现闪烁,或者两者同时发⽣。

• \b :退格键,光标回退⼀个字符,但不删除字符。(覆盖前面那个字符)

• \f :换⻚符,光标移到下⼀⻚。在现代系统上,这已经反映不出来了,⾏为改成类似于 \v 。

• \n :换⾏符。

• \r :回⻋符,光标移到同⼀⾏的开头。

• \t :制表符,光标移到下⼀个⽔平制表位,通常是下⼀个8的倍数。(让输出的内容更美观和可读)

• \v :垂直分隔符,光标移到下⼀个垂直制表位,通常是下⼀⾏的同⼀列。

下⾯2种转义字符可以理解为:字符的8进制或者16进制表⽰形式

• \ddd :d d d表⽰1~3个⼋进制的数字。 如: \130 表示字符X(字符八进制的表示形式)

• \xdd :d d表⽰2个⼗六进制数字。 如: \x30 表示字符0(字符十六进制的表示形式)

• \0 :null 字符,代表没有内容, \0 就是 \ddd 这类转义字符的⼀种,⽤于字符串的结束标志,其 ASCII码值是0.

注: 关于转义字符我们首先要了解,然后要能在字符串中识别出来。(求字符串长度时,转义字符只占一个字节)

题型:求复杂字符串的长度

int main()
{
  printf("%zd\n", strlen("c:\test\130\test.c"));
}

13       因为\t和\130都只算1个字符

转义字符参考https://zh.cppreference.com/w/c/language/escape

八、语句和语句分类

8.1空语句

  空语句是最简单的,⼀个分号就是⼀条语句,是空语句。

#include <stdio.h>
int main()
{
 ;//空语句
 return 0;
}

       空语句⼀般出现的地⽅是:这⾥需要⼀条语句,但是这个语句不需要做任何事,就可以写⼀个空语句。

8.2表达式语句

      表达式语句就是在表达式的后边加上分号。如下所⽰:

#include <stdio.h>
int main()
{
 int a = 20;
 int b = 0;
 b = a + 5; //表达式语句
 return 0;
}

8.3函数调用语句

函数调⽤的时候,也会加上分号,就是函数调⽤语句。

#include <stdio.h>
int Add(int x, int y)
{
 return x+y;
}
int main()
{
 printf("hehe\n");//函数调⽤语句
 int ret = Add(2, 3);//函数调⽤语句 
 return 0;
}

8.4复合语句

复合语句其实就是前⾯讲过的代码块,成对括号中的代码就构成⼀个代码块,也被称为复合语句

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

8.5控制语句

       控制语句⽤于控制程序的执⾏流程,以实现程序的各种结构⽅式(C语⾔⽀持三种结构:顺序结构、选择结构、循环结构),它们由特定的语句定义符组成,C语⾔有九种控制语句。

可分成以下三类:

1. 条件判断语句也叫分⽀语句:if语句、switch语句

2. 循环执⾏语句:do while语句、while语句、for语句

3. 转向语句:break语句、goto语句、continue语句、return语句。

九、注释

注释是对代码的说明,编译器会忽略注释,也就是说,注释对实际代码没有影响。

注释是给程序员⾃⼰,或者其他程序员看的。

好的注释可以帮我们更好的理解代码,但是也不要过度注释,不要写没必要的注释。

当然不写注释可能会让后期阅读代码的⼈抓狂。 写注释⼀定程度上反应了程序作者的素质,建议⼤家写必要的注释,在未来找⼯作的时候,写代码时 留下必要的注释也会给⾯试官留下更好的印象。

第⼀种⽅法是将注释放在 /*...*/ 之间,内部可以分⾏。

注:这种注释⼀定不能忘记写结束符号 */ ,否则很容易导致错误。

注:/* */ 的这个注释不⽀持嵌套注释, /* 开始注释后,遇到第⼀个 */ 就认为注释结束了。

第⼆种方法是将注释放在双斜杠 // 后⾯,从双斜杠到⾏尾都属于注释。这种注释只能是单⾏,可以 放在⾏⾸,也可以放在⼀⾏语句的结尾。这是 C99 标准新增的语法。

注:不管是哪⼀种注释,都不能放在双引号⾥⾯。 双引号⾥⾯的注释符号,会成为字符串的⼀部分,解释为普通符号,失去注释作⽤。

注:编译时,注释会被替换成⼀个空格,所以(min/*    这⾥是注释   */Value) 会变成 min Value ,而不是 minValue 。

十、数据类型

C语⾔提供了丰富的数据类型来描述⽣活中的各种数据。

使⽤整型类型来描述整数,使⽤字符类型来描述字符,使⽤浮点型类型来描述⼩数。

       所谓“类型”,就是相似的数据所拥有的共同特征,编译器只有知道了数据的类型,才知道怎么操作 数据。

10.1 字符型

char
[signed] char
unsigned char

10.2 整型

//短整型
short [int]
[signed] short [int]
unsigned short [int]
//整型
int
[signed] int
unsigned int
//⻓整型
long [int]
[signed] long [int]
unsigned long [int]
//更⻓的整型
//C99中引⼊
long long [int]
[signed] long long [int]
unsigned long long [int]

10.3 浮点型

float
double
long double

10.4 布尔类型

C 语⾔原来并没有为布尔值单独设置⼀个类型,⽽是使⽤整数 0 表⽰假,⾮零值表⽰真。

在 C99 中也引⼊了 布尔类型 ,是专门表示真假的。

_Bool

布尔类型的使⽤需要包含头⽂件<stdbool.h>

布尔类型变量的取值是:true或者false

10.5 自定义类型

C语言:自定义类型——结构体-CSDN博客

C语言:自定义类型——联合和枚举-CSDN博客

10.6 数据类型的长度

10.7 signed 和 unsigned

C 语⾔使⽤ signed 和 unsigned 关键字修饰字符型和整型类型的。

signed 关键字,表⽰⼀个类型带有正负号,包含负值;

unsigned 关键字,表⽰该类型不带有正负号,只能表⽰零和正整数。

整数变量声明为 unsigned 的好处是,同样⻓度的内存能够表⽰的最⼤整数值,增⼤了⼀倍。

C 语言规定 char 类型默认是否带有正负号,由当前系统决定。

所以 char 不等同于 signed char ,它有可能是 signed char ,也有可能是 unsigned char

这⼀点与 int 不同, int 就是等同于 signed int 。

十一、变量

类型是⽤来创建变量的。C语⾔中把经常变化的值称为变量,不变的值称为常量。

data_type name;
 | |
 | |
数据类型 变量名

11.1 变量初始化

变量在创建的时候就给⼀个初始值,就叫初始化。

int age = 18;
char ch = 'w';
double weight = 48.0;
unsigned int height = 100;

11.2 变量的分类

• 全局变量:在⼤括号外部定义的变量就是全局变量

全局变量的使⽤范围更⼴,整个⼯程中想使⽤,都是有办法使⽤的。

• 局部变量:在⼤括号内部定义的变量就是局部变量

局部变量的使⽤范围是⽐较局限,只能在⾃⼰所在的局部范围内使⽤的。

int global = 2023;//全局变量
int main()
{
 int local = 2018;//局部变量
 printf("%d\n", local);
 printf("%d\n", global);
 return 0;
}

注意:局部变量和全局变量同名的时候,局部变量优先使⽤。

11.3 变量的命名规则和规范

1.一个变量名称可以由数字、字母、下划线、美元符号($) 组成

2.严格区分大小写

3.不能由数字开头,不要使用中文汉字命名

4.不能是保留字或者关键字

5.不要出现空格

十二、printf详细介绍

12.1 基本用法

printf() 的作⽤是将参数⽂本输出到屏幕。它名字⾥⾯的 f 代表 format (格式化),表⽰可以 定制输出⽂本的格式。头文件<stdio.h>

int main(void) 
{
 printf("Hello World");
 return 0;
}

Hello World

    printf() 不会在自动在行尾添加换行符,运⾏结束后,光标就停留在输出结束的地⽅,不会⾃动换行。 为了让光标移到下⼀行的开头,可以在输出文本的结尾,添加⼀个换行符 \n 。

12.2 占位符列举

• %a :⼗六进制浮点数,字⺟输出为⼩写。

• %A :⼗六进制浮点数,字⺟输出为⼤写。

• %c :字符。 • %d :⼗进制整数。

• %e :使⽤科学计数法的浮点数,指数部分的 e 为⼩写。

• %E :使⽤科学计数法的浮点数,指数部分的 E 为⼤写。

• %i :整数,基本等同于 %d 。

• %f :⼩数(包含 float 类型和 double 类型)。

• %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 类型。

• %% :输出⼀个百分号。

12.3 占位符的使用

printf() 可以在输出⽂本中指定占位符。 所谓 “占位符”,就是这个位置可以⽤其他值代⼊。

常⽤的占位符除了 %d ,还有 %s 表⽰代⼊的是字符串。

输出文本里面可以使用多个占位符!!!

int main()
{
 printf("%s says it is %d o'clock\n", "lisi", 21);
 return 0;
}

lisi says it is 21 o'clock 。

     printf() 参数与占位符是⼀⼀对应关系,如果有 n 个占位符, printf() 的参数就应该有 n + 1 个。如果参数个数少于对应的占位符, printf() 可能会输出内存中的任意值。

12.4 输出格式

printf() 允许限定占位符的最⼩宽度。

12.4.1 限定宽度

int main()
{
 printf("%5d\n", 123); // 输出为 " 123"
 return 0;
}

输出结果:“  123”

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

int main()
{
 printf("%-5d\n", 123); // 输出为 "123 "
 return 0;
}

输出结果:“123  ”

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

int main()
{
 printf("%12f\n", 123.45);
 return 0;
}

"  123.450000"

上⾯⽰例中, %12f 表⽰输出的浮点数最少要占据12位。由于小数的默认显示精度是⼩数点后6位, 所以 123.45 输出结果的头部会添加2个空格。

12.4.2 总是显示正负号

默认情况下, printf() 不对正数显⽰ + 号,只对负数显⽰ - 号。如果想让正数也输出 + 号,可 以在占位符的 % 后⾯加⼀个 + 。

int main()
{
 printf("%+d\n", 12); // 输出 +12
 printf("%+d\n", -12); // 输出 -12
 return 0;
}

+12

-12

上⾯⽰例中, %+d 可以确保输出的数值,总是带有正负号。

12.4.3 限定小数位数

输出小数时,有时希望限定⼩数的位数。举例来说,希望⼩数点后⾯只保留两位,占位符可以写 成 %.2f 。

int main()
{
 printf("Number is %.2f\n", 0.5);
 return 0;
}

Number is  0.50

这种写法可以与限定宽度占位符,结合使⽤。

int main()
{
 printf("%6.2f\n", 0.5);
 return 0;
}

"   0.50"

最⼩宽度和⼩数位数这两个限定值,都可以⽤ * 代替,通过 printf() 的参数传⼊。

int main()
{
 printf("%*.*f\n", 6, 2, 0.5);
 return 0;
}
// 等同于printf("%6.2f\n", 0.5);

"   0.50"                          上述代码等同于printf("%6.2f\n", 0.5);

12.4.4 输出部分字符串

%s 占位符⽤来输出字符串,默认是全部输出。如果只想输出开头的部分,可以⽤ %.[m]s 指定输出 的⻓度,其中 [m] 代表⼀个数字,表⽰所要输出的⻓度。

int main()
{
 printf("%.5s\n", "hello world");
 return 0;
}

hello                  占位符 %.5s 表⽰只输出字符串“hello world”的前5个字符,即“hello”。

12.5 printf的返回值

printf的返回值返回的是字符串中字符的数量(和strlen的返回值差不多,但是strlen的返回值是size_t,而printf的返回值是int)

int main()
{
  int a=printf("hello world\n");
  printf("%d\n", a);
  return 0;
}

hello world

12

十三、scanf详细介绍

13.1 基本用法

scanf() 函数⽤于读取用户的键盘输⼊。

程序运⾏到这个语句时,会停下来,等待⽤⼾从键盘输⼊。

⽤⼾输⼊数据、按下回⻋键后, scanf() 就会处理⽤⼾的输⼊,将其存⼊变量。

它的原型定义也在头⽂件 stdio.h , scanf() 的语法跟 printf() 类似。

scanf("%d", &i);

       它的其余参数就是存放⽤⼾输⼊的变量,格式字符串⾥⾯有多少个占位符,就有多少个变量。 上⾯⽰例中, scanf() 的第⼀个参数 %d ,表⽰⽤⼾输⼊的应该是⼀个整数。 %d 就是⼀个占位 符, % 是占位符的标志, d 表⽰整数。第⼆个参数 &i 表⽰,将⽤⼾从键盘输⼊的整数存⼊变量 i 。

      变量前⾯必须加上 & 运算符(指针变量除外),因为 scanf() 传递的不是值,⽽是地址, 即将变量 i 的地址指向⽤⼾输⼊的值。 如果这⾥的变量是指针变量(⽐如字符串变量),那就不⽤加 & 运算符。

    scanf() 处理数值占位符时,会⾃动过滤空⽩字符,包括空格、制表符、换⾏符等。

    所以,⽤⼾输⼊的数据之间,有⼀个或多个空格不影响 scanf() 解读数据。另外,⽤⼾使⽤回⻋ 键,将输⼊分成⼏⾏,也不影响解读。

scanf() 处理⽤⼾输⼊的原理是,⽤⼾的输⼊先放⼊缓存,等到按下回⻋键后,按照占位符对缓存 进⾏解读。 解读用户输⼊时,会从上⼀次解读遗留的第⼀个字符开始,直到读完缓存,或者遇到第⼀个不符合条件的字符为⽌。

int main()
{
 int x;
 float y;
 
 // ⽤⼾输⼊ " -13.45e12# 0"
 scanf("%d", &x);
 printf("%d\n", x);
 scanf("%f", &y);
 printf("%f\n", y);
 return 0;
}

输入: -13.45e12# 0

输出:-13

         449999994880.000000

       在上⾯⽰例中, scanf() 读取⽤⼾输⼊时, %d 占位符会忽略起⾸的空格,从 - 处开始获取数据,读 取到 -13 停下来,因为后⾯的 . 不属于整数的有效字符。这就是说,占位符 %d 会读到 -13 。 第⼆次调⽤ scanf() 时,就会从上⼀次停⽌解读的地⽅,继续往下读取。这⼀次读取的⾸字符 是 . ,由于对应的占位符是 %f ,会读取到 .45e12 (表示0.45*10^12),这是采⽤科学计数法的浮点数格式。后⾯的 # 不属于浮点数的有效字符,所以会停在这⾥。

13.2 scanf的返回值

scanf() 的返回值是⼀个整数,表⽰成功读取的变量个数。 如果没有读取任何项,或者匹配失败,则返回 0 。如果在成功读取任何数据之前,发⽣了读取错误或 者遇到读取到⽂件结尾,则返回常量 EOF。

13.3 占位符的使用

scanf() 常⽤的占位符如下,与 printf() 的占位符基本⼀致。

• %c :字符。

• %d :整数。

• %f : float 类型浮点数。

• %lf : double 类型浮点数。

• %Lf : long double 类型浮点数。 • %s :字符串。

• %[] :在⽅括号中指定⼀组匹配的字符(⽐如 %[0-9] ),遇到不在集合之中的字符,匹配将会停⽌。

13.3.1 %c

1、上⾯所有占位符之中,除了 %c 以外,都会⾃动忽略起首的空白字符。 %c 不忽略空⽩字符,总是返回当前第⼀个字符,无论该字符是否为空格。

2、如果要强制跳过字符前的空⽩字符,可以写成 scanf(" %c", &ch) ,即 %c 前加上⼀个空格,表⽰跳过零个或多个空⽩字符。

13.3.2 %s

1、占位符 %s ,它其实不能简单地等同于字符串。它的规则是,从当前第⼀个⾮空⽩ 字符开始读起,直到遇到空⽩字符(即空格、换⾏符、制表符等)为⽌。

2、 因为 %s 不会包含空⽩字符,所以⽆法⽤来读取多个单词,除⾮多个 %s ⼀起使⽤。这也意味着, scanf( ) 不适合读取可能包含空格的字符串,⽐如书名或歌曲名。另外, scanf( ) 遇到 %s 占位符,会在字符串变量末尾存储⼀个空字符 \0 。

3、 scanf() 将字符串读⼊字符数组时,不会检测字符串是否超过了数组⻓度。所以,储存字符串时, 很可能会超过数组的边界,导致预想不到的结果。为了防⽌这种情况,使⽤ %s 占位符时,应该指定读⼊字符串的最⻓⻓度,即写成 %[m]s ,其中的 [m] 是⼀个整数,表⽰读取字符串的最大场度,后⾯的字符将被丢弃。

int main()
{
 char name[11];
 scanf("%10s", name);
 
 return 0;
}

上面实例中, name 是⼀个⻓度为11的字符数组, scanf() 的占位符 %10s 表⽰最多读取⽤⼾输⼊ 的10个字符,后⾯的字符将被丢弃,这样就不会有数组溢出的⻛险了。

相关文章
|
4月前
|
存储 机器学习/深度学习 算法
c语言基础知识帮助理解(函数递归详解)
c语言基础知识帮助理解(函数递归详解)
36 0
|
4月前
|
C语言
c语言基础知识整理与帮助理解——二.数据的输出与输入
c语言基础知识整理与帮助理解——二.数据的输出与输入
59 0
|
4月前
|
Java C语言
c语言基础知识整理与帮助理解(第一篇)
c语言基础知识整理与帮助理解(第一篇)
61 0
|
4月前
|
C语言
C语言中指针的基础知识
C语言中指针的基础知识
37 0
|
4月前
|
人工智能 算法 编译器
C语言初阶测评题:测试你的基础知识和编程技能!!
C语言初阶测评题:测试你的基础知识和编程技能!!
51 1
|
6月前
|
存储 C语言 索引
初识C语言——C语言基础知识(三)(数组和操作符)
初识C语言——C语言基础知识(三)(数组和操作符)
57 0
|
6月前
|
程序员 编译器 C语言
初识C语言——C语言基础知识(一)
初识C语言——C语言基础知识(一)
44 0
初识C语言——C语言基础知识(一)
|
5月前
|
C语言
C语言结构体基础知识
C语言结构体基础知识
41 0
|
4月前
|
存储 编译器 C语言
c语言基础知识帮助理解(详解数组)
c语言基础知识帮助理解(详解数组)
48 0
|
4月前
|
程序员 编译器 C语言
c语言基础知识帮助理解(详解函数)
c语言基础知识帮助理解(详解函数)
44 0