第二章 数据类型、运算符与表达式

如何打开项目

如何打开已经存在的解决方案?

找到要打开的解决方案目录,进去之后双击后缀为.sln的文件即可打开该解决方案。

在这里插入图片描述

或者从最近打开项目中打开:

在这里插入图片描述

Online Judge使用

OJ简介

在线判题系统(Online Judge,缩写OJ)是一种在编程竞赛中用来测试参赛程序的在线系统,也可以用于平时练习。

评测状态是指代码在提交后进行评测的阶段或结果,会向用户进行反馈。

在这里插入图片描述

使用OJ的注意事项

所有的OJ都是完美匹配输入和输出的。

OJ的output会接收到所有的标准输出printf。例如下图所示例子:

在这里插入图片描述

在以后机试中或者公司的面试中使用的OJ也是同样的,要严格遵守规范。(有的甚至后面多一个空格都不让Accepted,有的好一点后面有空格会自动给你去掉)。

以下才会被OJ通过,所以在OJ上答题时不能有多余的输入和输出

在这里插入图片描述

数据类型

C语言中数据类型有:

  1. 基本类型
    • 整型int
    • 字符型char
    • 浮点型:单精度浮点型float、双精度浮点型double
  2. 构造类型
    • 数组类型[]
    • 结构类型struct
    • 联合类型union
    • 枚举类型enum
  3. 指针类型 *
  4. 空类型(无值类) void

C语言中的关键字(关键字都是小写字母)如下表。注:不能使用关键字作为变量名。

在这里插入图片描述

变量与常量

常量

int main() {
	int a = 3;//a是一个变量,3是常量,这句话计算机是将常量3 复制 给了a
    a = 5;//变量a是有自己的内存地址的,而常量则没有
}

常量没有自己的内存地址,那么常量在哪呢?

程序加载到内存里面有一个编译后的.exe,.exe就是一个代码段,程序一旦运行就会将.exe放到内存的代码段,而常量3是编到代码段里的,代码段里的内容是不可变的。 变量a是有自己的内存空间的,代码是一句一句向下执行,当执行到a=3时,会将3复制到a的地址。如下图:

在这里插入图片描述

变量

变量的命名规定如下:C语言规定标识符只能由字母、数字、和下划线三种字符组成,并且第一个字符必须为字母或下划线

如何查看变量地址

利用监视调试窗口查看变量变化。

int main() {
	int a = 3;//a是一个变量
	a = 5;
}

进入调试窗口要先打上断点,然后运行。

在这里插入图片描述

在这里插入图片描述

点下一步,int a = 3;运行结束后此时看到a内存地址里的值变成了3。

在这里插入图片描述

再点下一步,a = 5;执行完,a内存地址里的值又变成了5。

在这里插入图片描述

符号常量

用define关键字定义的就是符号常量。符号常量也是常量,不可以再被赋值。

#define PI 3  //PI就是一个符号常量。
int main() {
	printf("%d\n",PI);
}

常量不可以再被修改,这里再把PI的值赋予了10,发生了报错

在这里插入图片描述

当VS出现如上图所示的弹窗提醒发生错误时,不管什么时候都要点“否”,然后找到错误并修改。

查看错误报告:

在这里插入图片描述

表达式左边称左操作数,右边称右操作数;左值是指可以修改的值,也就是说只有变量才能叫左值。

进制变换

观察内存使用的是十六进制。

如下代码段:

int main() {
	int i = 123;
}

当int i = 123;这句代码还没有执行时,微软会给变量i一个初始值,十六进制下就是cccc cccc,对应的十进制-858993460。(int型占4B,C语言中int用补码表示)。

在这里插入图片描述

当int i = 123;这句代码执行过之后,此时i=123,变量i的内存地址里存储的便是123,对应的是十六进制7B,计算机中采用小端存储(多字节数据中,最低有效字节放在低地址,最高有效字节放在高地址,方便计算机处理数据),故内存中存储的机器数是7B 00 00 00。[补充:x86架构都是小端存储,Intel和AMD的CPU采用的都是x86架构]

在这里插入图片描述

在监视窗口下直接输入变量名i,仅显示 值 ,而不显示地址。

在这里插入图片描述

scanf函数

在同一个解决方案下新建两个项目

当在一个解决方案里面新建两个项目时,在解决方案的位置点击右键,然后按如下步骤操作:

在这里插入图片描述

在这里插入图片描述

在新建的项目里添加main.c文件。[一个项目里可以有多个代码文件,但同一个项目里所有的代码文件只能有一个入口main。]

在这里插入图片描述

设置启动项目

想让哪个项目运行,要把该项目设置为启动项目

在这里插入图片描述

启动项目对应的项目名称是粗体,以此来分辨哪个是启动项目。

在这里插入图片描述

VS是为开发大型项目来准备的,所以每次都要新建一个项目,这样如果用了多个.c文件,就会自动的编译到一起,变为一个可执行文件.exe,非常方便。

scanf函数的原理

往屏幕输出是printf;从屏幕中读取数据,称为读取标准输入,用scanf。

C语言通过scanf函数读取键盘输入,键盘输入又被称为标准输入。当scanf函数读取标准输入时,如果还没有输入任何内容,那么scanf函数会被卡住(专业用语为阻塞)。

#include <stdio.h>

int main() {
	int a;
	scanf("%d", &a);//此时一定要在变量前加入取地址符号&
	printf("a=%d\n", a);
}

当仅编入如上代码时,会发生输入报错,原因是微软认为scanf函数不安全,建议用微软自己的scanf_s函数,但**千万不能使用**scanf_s函数,首先这个scanf_s不属于C语言,其次在复试中使用scanf_s是编译不通过的,所以千万不能使用scanf_s。

在这里插入图片描述

解决上述报错仅需在第一行(必须是在第一行)添加如下内容 #define _CRT_SECURE_NO_WARNINGS即可,其中_CRT_SECURE_NO_WARNINGS是上图中报错提示中出现的。[注]:该报错仅会在vs2017版本及之后才会出现,如果是更低的版本则不会出现该问题,在复试中看学校使用的是什么版本,再看用不用加;vs2012、2013、2015都不需要加。

#define _CRT_SECURE_NO_WARNINGS  //解决scanf编译报错问题
#include <stdio.h>

int main() {
	int a;
	scanf("%d", &a);//此时一定要在变量前加入取地址符号&
	printf("a=%d\n", a);
}

其中由于没有接收scanf的返回值,所以提示波浪线,定义一个返回值之后便消失了,不过这都没有影响,这里接不接返回值都可以。

在这里插入图片描述

想要项目只编译,不运行,只需点重新生成即可。

在这里插入图片描述

由于用的是 %d,所以只能输入整数。要输入两个整数就是 %d%d (中间不要有空格)。

#define _CRT_SECURE_NO_WARNINGS  //解决scanf编译报错问题
#include <stdio.h>

int main() {
	int a,b;
    //输入两个整数
	scanf("%d%d", &a,&b);//此时一定要在变量前加入取地址符号&
	printf("a=%d,b=%d\n",a,b);
}

在这里插入图片描述

输出两个值的和:

#define _CRT_SECURE_NO_WARNINGS  //解决scanf编译报错问题
#include <stdio.h>

int main() {
	int a,b;
	scanf("%d%d", &a,&b);//此时一定要在变量前加入取地址符号&
	printf("%d\n",a+b);
}

在这里插入图片描述

整型

x86表示所建的程序是32位的(32位的控制台应用程序)。项目有32位和64位之分。

在这里插入图片描述

%d的使用

%d 就是以十进制方式输出某一个整数,要输出两个整数就要%d%d ,同理每多输出一个整数都要多加一个%d (只能输出整数而不能输出浮点数)。

int main() {
	int a = 123;
	int b = 0x7b; //0x 表示十六进制
	int c = 0173;//前面有个0表示八进制,八进制用的少,了解一下即可。
	printf("%d\n%d\n%d\n", a,b,c);//%d 表示以十进制方式输出某一个整型数
	//输出结果a,b,c均为123
}

在这里插入图片描述

64位CPU既可以运行32位程序也可以运行64位程序,而32位CPU只能运行32位程序。

本程序是32位程序,存储字长=32,所以一个字占32位,按字节编址,一个字占4B。可以看到每个字的地址相差4。这里地址占32位=4B,所以寻址空间是232=4GB。

在这里插入图片描述

浮点型

浮点数的表示形式

浮点型常量的形式有两种,如下所示,其中e代表10的幂次,幂次可正可负

小数形式:0.123

指数形式:3e - 3 为 3 x 10-3 ,即0.003。

注意:字母e或E之前必须有数字,且e后面的指数必须为整数。

%f的使用

%f就是以浮点数形式输出对应的数据。

float main() {
	float f1 = 1.234;
	printf("%f\n", f1);//输出浮点数时需要用%f。即%f就是以浮点数形式输出对应数据。
	printf("%f\n", 1.234);
	printf("输出浮点数 %f\n", f1);//printf里面除了%d、%f外,写什么都是字符串
	float f2 = 3e-3;	//不推荐使用指数形式的浮点数,不要用
	printf("%f\n", f2);
	float f3 = 3e3; //e表示10的幂次
	printf("%f\n", f3);
}

在这里插入图片描述

注意在机试的时候printf里都要填英文字符串,不要用中文,防止编译错误导致乱码。甚至机试为了OJ就根本不用输入多余的字符串。

字符型数据

字符型常量

单引号括起来的一个字符是字符型常量,且只能包含一个字符。例如’a’,‘A’,‘1’是正确的字符型常量,而’abc’,‘a’,’ ’ 是错误的字符型常量。以“\”开头的特殊字符称为转义字符,转义字符用来表示回车,退格等功能键。

各种转义字符及其作用:

\n:换行

\b:退格

\:反斜杠

%c的使用

%c表示以字符形式对后面的变量进行输出。

	char c = 'a';
	printf("%c\n",c);//%c表示以字符形式对后面的变量进行输出
	printf("%c\n",97);//输出的也是a

在这里插入图片描述

在这里插入图片描述

system(“pause”);是VS2012版本让调试控制台停留显示必须要加的一句话,否则调试控制台将会一闪而过,不会停留。而高版本的VS则不用加这句话,同时OJ中也不要加这句话,否则OJ会判失败。

大小写转换实现

原理:查ASCII可知小写字母对应的值比大写字母对应的数值大32,所以通过这个来实现大小写转换

	//大小写转换
	char c = 'a';//现在是小写字母a,要变为大写字母A
	c = c - 32;//查ASCII可知小写字母对应的值比大写字母对应的数值大32,所以通过这个来实现大小写转换
	printf("%c\n", c);//以字符形式输出c

	char d = 'A';//现在是大写字母A,要变为小写字母a
	d = d + 32;//查ASCII可知小写字母对应的值比大写字母对应的数值大32,所以通过这个来实现大小写转换
	printf("%c\n", d);//以字符形式输出d

字符串型常量

字符串型常量是由一对双引号括起来的字符序列。如“How do you do.” 可以通过printf(“How do you do.”)输出一个字符串。但要注意的是,'a’是字符型常量,“a”是字符串型常量,二者是不同的。单引号的是字符型,双引号的是字符串型,二者不一样。

关于字符串变量:

C语言没有专门提供一种变量类型来存字符串的。C语言是通过字符数组来存字符串的。C语言并没有像C++、Java专门发明一个String类型的去存字符串。

C语言规定,在每个字符串型常量的结尾加一个字符串结束标志,以便系统据此判断字符串是否结束。C语言规定以字符’\0’作为字符串结束标志。字符’\0’对应的ASCII码是0。

例如,字符串型常量“CHINA”在内存中的存储结果如图所示,它占用的内存单元不是5个字符,而是6个字符,即大小为6字节,最后一个字符为’\0’。然而,在输出时不输出’\0’,因为’\0’无法显示。

在这里插入图片描述

后面我们会把这个东西赋值给字符数组,如果不知道字符串常量字符串的大小,在后面使用的时候就会用错,实际用5个字节是放不下的。

混合运算

在C语言的不同类型的数据混合运算中, 要先转换成同一类型后进行运算

	float i = 5;
	float j = i / 2; 
	/*
	右边表达式中i为浮点型,2为整型,所以C语言会判断此为浮点型运算,便会将整型2进行自动类型提升转换为浮点数类型2.0。
	浮点型运算所得结果还是浮点型,然后赋值给浮点型变量j
	*/

强制类型转换

整数进行除法运算时,如果运算结果为小数,那么存储浮点数时一定要进行强制类型转换。强制类型转换运算符( (类型) )。

下面代码中的解释一定要看,这样才能知道如果不进行强制类型转换会发生什么错误。

	//混合运算
	int i = 5;
	float j = i / 2; 
	printf("%f\n", j);//输出结果为2.0
	/*
	解释:C语言在进行除法的时候,是如何知道表达式(等式右边的整体是一个表达式)的类型呢?这个
	整体表达式的类型由谁决定呢?
	表达式i / 2;其中i是整型,2也是整型,所以这是整型的除法,所以结果得到的是一个整数。再把这个
	整数结果赋值给float类型,最终显示成浮点数。
	*/

	//想要正确的显示结果,就需要掌握强制类型转换运算符。强制类型转换运算符( (类型) )
	//等式右边只有一个变量时也算是一个表达式,不管右边是什么都是表达式。
	float m = (float)i;//在右边便会将i强制类型转换为float类型
	
	float k = (float)i / 2;
	/*
	运算顺序,先将i强制转换为float类型,再除以2。此时i为浮点型,此时便是浮点型运算,
	右边得到的结果便是2.5,再将其值赋值给k
	*/

	printf("j=%f,k=%f\n", j, k);//一个%f对应后面一个变量

在这里插入图片描述

常用的数据输入/输出函数

C语言通过scanf读取的输入叫“标准输入”。408中会出现“标准输入”等说法,需要知道指的是scanf读取的输入。printf是标准输出。

scanf读取的是标准输入;printf输出到黑窗口(控制台),输出到了标准输出。

scanf

scanf的使用方法:

	//语法: 
	#include <stdio.h>
	int scanf( const char *format, ... );

format是一个字符串。… 是可变参数,参数的数目与format中的%的数目保持一致

format的格式:(重点掌握前三种即可)

  • %d 一个十进制整数
  • %f 一个浮点数
  • %c 一个单一的字符
  • %s 一个字符串

“%d%d%d”,&a,&b,&c 。%的个数与参数的个数要相等。且scanf的参数都要加取地址符号&。 如“%d%f%c”,&a,&b,&c ;%d、%f、%c这些都可以混合使用且不限制个数,但参数的类型要对应。

scanf的原理

当scanf函数读取标准输入时,如果还没有输入任何内容,那么scanf函数会被卡住(专业术语为阻塞)。

scanf读取标准输入缓冲区的原理:

每一个进程里都有一个标准输入缓冲区,当在黑窗口(控制台)输入内容时就会将其放入标准输入缓冲区中,但此时scanf还不会去匹配。因为scanf是行缓冲,当在输入中遇到换行符(回车键)时,才会执行真正的I/O操作(scanf从标准输入缓存区中读取数据)。

回车\n并不是什么都不存在的,\n也会放到标准输入缓存区中。

标准输入缓冲区规定里面的所有内容均是字符,所以里面此时有三个字符1、0、\n。scanf(“%d”, &i)当写%d时就会将1、0这两个字符转成整型数存放到变量i中;这就是scanf的原理。

当按下回车键后,scanf便开始从标准输入缓冲区中读取数据,实际scanf只会将1、0读取走,\n还会留在标准输入缓冲区中。

在这里插入图片描述

读取完后缓冲区中还有\n这个字符。实际scanf只会将1、0读取走,\n还会留在标准输入缓冲区中。

在这里插入图片描述

int main() {
	int i;
	scanf("%d", &i);
	printf("i=%d\n", i);
}

在这里插入图片描述

验证scanf读取走内容后缓冲区中还剩下\n:

刚开始输入10,按下回车键(换行符),scanf就会将字符1、0读走,在%d下转换为整型赋值给变量i;此时并没有把缓冲区中的\n读取走,\n还存在于标准输入缓冲区中,只有当标准输入缓冲区为空时scanf才会阻塞,但当执行到scanf(“%c”, &c)时缓冲区不为空,里面还有字符\n (\n在ASCII码中对应10),所以在scanf(“%c”, &c)处并不会发生阻塞,而会直接将\n再读取走转换成字符赋值给c。所以会看到c=回车。

int main() {
	int i;
	char c;
	scanf("%d", &i);
	printf("i=%d\n", i);
	scanf("%c", &c);
	printf("c=%c\n", c);
}

在这里插入图片描述

调出调试窗口看到c的值确实是10(\n)。

在这里插入图片描述

在上述例子中,我们向标准输入缓冲区中放入的字符为’10\n’,输入’\n’(回车)后,scanf函数才开始匹配,scanf函数中的%d匹配整型数10,然后放入变量i中,接着进行打印输入,这是’\n’仍然在标准输入缓冲区中,如果第二个scanf函数为scanf(“%d”,&i),那么依然会发生阻塞,因为scanf函数在读取整型数、浮点数、字符串时,会忽略’\n’(回车符)、空格符等字符,(忽略是指scanf函数执行时会首先删除这些字符,然后再阻塞。【因为只有当标准输入缓冲区为空时scanf才会阻塞,把这些字符删除掉,缓冲区就为空了,就会阻塞】)。scanf函数匹配一个字符时,会在缓冲区删除对应的字符。因为在执行scanf(“%c”,&c)语句时,不会忽略任何字符,所以scanf(“%c”,&c)读取了还在缓冲区中残留的’\n’。

根据上述原理,在执行下述代码时,printf(“f=%f\n”, f)会输出scanf读取的浮点数,而非’\n’(回车符)。根据<scanf函数在读取整型数、浮点数、字符串时,会忽略’\n’(回车符)、空格符等字符>,在执行到scanf(“%f”, &f)时会将标准输入缓存区中剩下的’\n’删除掉,然后再阻塞,等待输入。【标准输入缓冲区规定里面的所有内容均为字符,是scanf将字符读取走根据%d,%f,%c等类型转换成对应的类型】

int main() {
	int i;
	//char c;
	float f;
	scanf("%d", &i);
	printf("i=%d\n", i);
	//scanf("%c", &c);
	//printf("c=%c\n", c);
	scanf("%f", &f);
	printf("f=%f\n", f);
}

第一次输入10,第二次输入98.5,得到如下结果:

在这里插入图片描述

根据该原理,求输入两个数的和,输入两个数时要以空格键或回车键隔开,用以区分输入了两个数。当用空格隔开时,已知scanf函数在读取整型数、浮点数、字符串时,会忽略’\n’(回车符)、空格符等字符(忽略是指scanf函数执行时会首先删除这些字符,然后再阻塞),所以并不会将空格读取到;回车键同理也不会读取到。

在这里插入图片描述

根据上述原理,当使用%c时则不会忽略’\n’(回车符)、空格符等字符。所以会出现如下情况:当以回车隔开时,缓冲区中是a\n,还未等输入下一个字符scanf便会开始匹配,因为%c时并不会忽略’\n’(回车符)、空格符等字符,将字符a读走作为第一个字符后,此时本来应该阻塞等待,而在%c的情况下并不会忽略’\n’(回车符)、空格符等字符(即并不会删除这些字符,也就是缓冲区不为空,所以不会阻塞),所以会将缓冲区中留下的\n读取走作为第二个字符。以空格隔开时同理。

scanf函数在读取整型数、浮点数、字符串时,会忽略’\n’(回车符)、空格符等字符,(忽略是指scanf函数执行时会首先删除这些字符,然后再阻塞。【因为只有当标准输入缓冲区为空时scanf才会阻塞,把这些字符删除掉,缓冲区就为空了,就会阻塞】)

在这里插入图片描述

练习判断闰年

练习题目:判断某个年份是不是闰年,如果是闰年,请输出“yes”,否则请输出“no”。

判断一个年份是否是闰年的方法:能被400整除,或者能被4整除但不能被100整除的都是闰年,其余的年份均为平年。

int main() {
	int year;
	scanf("%d", &year);//scanf要加取地址符&,这点不要忘了
	if (year%400==0 || (year%4==0 && year%100!=0))//这里的&&可以不加小括号,因为“&”的运算优先级高于“|”
	{
		printf("yes\n");
	}
	else
	{
		printf("no\n");
	}
}

scanf循环读取

什么是EOF

scanf()的返回值是成功赋值的变量数量, 发生错误时返回EOF。

直接在代码里输入EOF,按着CTRL键,然后鼠标左键点击,可以在<stdio.h>中看到EOF等于常量-1。

#define EOF    (-1)

说明定义了EOF是常量-1。(为什么加小括号:为了防止和其他的发生结合。高级阶段会讲什么是”结合“。)

什么情况下scanf会出错(即返回值=EOF)?

行首连着输入ctrl z回车 三次。(必须在行首连着输入三次ctrl z 回车三次才可以)

在这里插入图片描述

如果没有在行首输入ctrl z 而是在字符后面输入ctrl z 回车,则便会疯狂打印不会停止。

在这里插入图片描述

另一种出现疯狂打印的情况:

当scanf(“%d”,&i)时,但是在调试控制台输入了一个字符,按下回车键便开始疯狂打印。

在这里插入图片描述

原因解释:

当输入10后按下回车键(换行符\n),scanf(“%d”,&i)只能读取标准输入缓冲区中的0-9的字符,可以将字符1、0读走并转换为整型赋值给变量i。

{因为scanf函数在读取整型数、浮点数、字符串时,会忽略’\n’(回车符)、空格符等字符,(忽略是指scanf函数执行时会首先删除这些字符,然后再阻塞。【因为只有当标准输入缓冲区为空时scanf才会阻塞,把这些字符删除掉,缓冲区就为空了,就会阻塞】)}

在这里插入图片描述

在scanf(“%d”,&i)下,将1、0读取走之后会将\n删除掉,此时缓冲区为空,scanf阻塞。当此时输入字符时,如a,按下回车键,由于scanf(“%d”,&i)只能读取标准输入缓冲区中的0-9的字符,所以scanf无法读取缓冲区中的a。

scanf()的返回值是成功赋值的变量数量.

由于无法读取缓冲区中的a,故赋值失败,返回值为0。scanf(“%d”,&i)!=EOF为true,进入循环,由于缓冲区不为空,所以scanf便不会阻塞,将陷入死循环。无法读取缓冲区中的a,给变量i赋值失败,所以此时i的值还是上次赋的值,故i=10,所以便会出现疯狂打印i=10。

可以通过监视窗口看到,当输入字符时,scanf的返回值是0,即成功赋值的变量个数为0.

在这里插入图片描述

解决办法:在每一次scanf读取缓冲区之前将缓冲区的内容给清除掉,清除掉之后缓冲区为空,等待下一次输入。

清空缓冲区使用rewind(stdin);stdin是标准输入。

[注] rewind(stdin)仅用于Windows操作系统,Mac操作系统不能用。 且这里清空缓冲区使用rewind(stdin)只是在练习时使用,防止在练习时误输入导致死循环打印,在初始和复试中都不用写的,包括OJ也不用写,因为OJ后端检测的输入肯定是正确的输入,不会有非法输入。

//清空缓冲区,VS2012使用 fflush(stdin);新版本VS2013-VS2019使用rewind(stdin)。
// [注]fflush(stdin)在新版本中无效
//stdin是标准输入
int main() {
	int i;
	/*
	scanf()的返回值是成功赋值的变量数量, 发生错误时返回EOF.(可查看EOF是常量-1)
	所以可以通过返回值来判断是否要跳出循环。
	【EOF这个宏已经在<stdio.h>中定义出来了】
	*/
	while (rewind(stdin),scanf("%d",&i)!=EOF)//while是实现循环,后面要有一个小括号。当为true时进入循环。
	{
		printf("i=%d\n", i);
	}
	return 0;
}

在这里插入图片描述

循环读取字符

//循环读取字符,将小写字母转换成大写字母
int main() {
	char c;
	while (scanf("%c",&c)!=EOF)//循环读取字符时不用清空缓冲区rewind(stdin),只有在读取整型数和浮点数时才使用
	{
		//字符用单引号''  ;   字符串用双引号""
		if (c != '\n')//判断,后面有一个小括号,小括号里面是一个表达式
		{
			printf("%c", c-32);
		}
		else//else就是否则
		{
			printf("\n");
		}
	}
}

在这里插入图片描述

scanf的混合输入

scanf同时读取多种类型的数据,混合输入时每次在%c之前需要加入一个空格。只有混合输入里有%c时需要该操作,当混合输入里没有%c或者不是混合输入均不需要该操作。

//一个scanf读取多种类型的数据
int main() {
	int i;
	char c;
	float f;
	//混合输入时每次在%c之前需要加入一个空格。只有混合输入时需要该操作
	scanf("%d %c%f", &i, &c, &f);
	printf("i=%d,c=%c,f=%f\n", i, c, f);
	return 0;
}

在这里插入图片描述

printf

printf的使用方法

printf的语法:

	//printf使用方法
	#include <stdio.h>
	int printf( const char *format, ... );

这里format的格式同scanf中的格式一样:(重点掌握前三种即可)

  • %d 一个十进制整数
  • %f 一个浮点数
  • %c 一个单一的字符
  • %s 一个字符串

控制输出格式

printf标准输出缓冲区中都是字符串(显示在黑窗口调试控制台上的其实都是字符串),OJ时是通过判断你输出的字符串是否和后台文件中的字符串一致,差一点都无法AC。必须一模一样才能AC,所以务必掌握输出格式(机试很重要)。

如果没有控制输出格式,则浮点数98.5会输出98.500000,OJ想要AC必须和要求输出的格式一模一样,即输入98.5,输出也必须是98.5才行。

在这里插入图片描述

控制输出格式后:

//printf控制输出格式
int main() {
	//将score=%f修改为score=%4.1f,4表示浮点数输出占4个位置(包括小数点),1表示小数点后有1位
	printf("name=%s,age=%d,sex=%c,score=%4.1f\n", "LXL", 22, 'm', 98.5);
}

在这里插入图片描述

	//将score=%f修改为score=%0.5f,5表示小数点后有5位
	printf("name=%s,age=%d,sex=%c,score=%0.5f\n", "LXL", 22, 'm', 98.5000);

在这里插入图片描述

以下是整型数和字符串控制输出格式,没有那么重要。

//printf控制输出格式
int main() {
	//将score=%f修改为score=%4.1f,4表示浮点数输出占4个位置(包括小数点),1表示小数点后有1位
	printf("name=%4s,age=%-3d,sex=%c,score=%4.1f\n", "LXL", 22, 'm', 98.5);
}

在这里插入图片描述

解答疑问

内存地址解析

VS中内存调试窗口显示四个字节还是显示是几个字节,是拖动的效果。

这里32位程序,所以是32位地址总线和32位数据总线,所以让内存取4B。(事实上我们的计算机现在都是64位的机器,但考试只考32位的机器,二者原理是一样的)。

在这里插入图片描述

32位机器

在这里插入图片描述

运算符

运算符类型

C语言提供了13种类型的运算符:

  1. 算术运算符(+ - * / %)【掌握】
  2. 关系运算符(> < == >= <= !=)【掌握】
  3. 逻辑运算符(! && ||)【掌握】
  4. 位运算符(<< >> ~ | ^ &)【了解,在高级阶段会学】
  5. 赋值运算符(=及其扩展赋值运算符)【掌握】
  6. 条件运算符(? 😃【了解】
  7. 逗号运算符(,)【了解】
  8. 指针运算符(*和&)【在指针部分学习】
  9. 求字节数运算符(sizeof)【掌握】
  10. 强制类型转换运算符((类型))【掌握】
  11. 分量运算符(. ->)【在结构体部分学习】
  12. 下标运算符([ ])【在数组部分学习】
  13. 其他(如函数调用运算符( ))

从这里可以知道sizeof其实是运算符,而不是函数。

双目运算符:需要有两个操作数。

算术运算符包含+、-、*、/和%,当一个表达式中同时出现这5种运算符时,先进行乘(*)、除(/)、取余(%),取余也称取模,后进行加(+)、减(-),也就是乘、除、取余运算符的优先级高于加、减运算符。

算术运算符的优先级见下图。C语言所有的运算符的优先级见附件[C语言优先级完整版]。

在这里插入图片描述

处于同一级别的优先级一样,若同时出现则运算先后次序是从左到右;1比2的优先级高,先计算1后计算2。

**常用的运算优先级:逻辑非 ! > 算术运算符 > 关系运算符 > 逻辑运算符 > 赋值运算符 = **.

算术运算符练习

int main() {
	scanf("%d", &a);
	printf("a=%d\n", a);

	/*
	如果输入的是1234,那么现在将让输出4321,该如何操作?
	思路如下:1234%10=4,余数是4,商是123;得到的商再重复%4,余数得到3,商是12,重复上述步骤;
	当商为0时,跳出循环.(最后是1%10,余数是1,商是0,此时可以结束循环了)。
	*/

	//对于循环结束条件不知道如何写,可以先写循环体,等循环体写好了,循环结束条件也就大概知道了
	while (a!=0) //当a不等于0时就可以进入循环
	{
		printf("%d", a % 10);
		a = a / 10;
	}
}

在这里插入图片描述

拓展:上述结果如何以字符形式输出4321?

只需将循环体改成如下内容即可,因为查ASCII码表可知,字符0-9对应十进制48-57。所以整型数+48再以字符形式输出即可。

	while (a!=0)
	{
		//以字符形式输出结果4321
		printf("%c", a % 10 + 48);
		a = a / 10;
	}

关系运算符

关系运算符> < == >= <= != 。由关系运算符组成得表达式称为关系表达式,关系表达式只有真和假,对应得值为1和0。由于C语言中没有布尔(bool)类型,所以在C语言中0值代表假,非0值代表真

【注】C语言认为一切非零值都是真

	if (5)
	{
		printf("true");
	}
	//C语言认为一切非零值都是真。所以会输出ture

	//C语言中没有布尔(bool)类型,所以以下结果并不会输出true 或 false,而是输出1 或 0
	printf("%d\n",5 < 3);//结果为假,输出0
	printf("%d\n", 5 > 3);//结果为真,输出1

逻辑运算符

概述

! 逻辑非 :如果原来是真,取非就是假;如果是假,取非就是真。

&& 逻辑与 :a&&b,a和b任何一个为假,就是假;如果均为真,整体为真。

|| 逻辑或 :a||b,a和b任何一个为真,则结果为真;如果两个都为假,则结果为假。

逻辑运算符组成的式子叫逻辑表达式,逻辑表达式只有真和假,对应的值就是1和0。

//关系运算符和逻辑运算符
int main(){
	int a = 8;
	//常用的运算优先级:算术运算符>关系运算符>逻辑运算符。所以 if的判断条件不用加括号
	if (a > 3 && a < 10)//如果要判断3<a 同时 a<10 ,要用逻辑运算符
	{
		printf("a is right");
	}
	else {
		printf("a is wrong");
	}
}

练习:判断浮点数是否等于某个值(判断两个浮点数是否相等)。不太重要,初试没有考过浮点数,复试也不太可能考这个点,因为这是个细节点,除非复试特别难,才会这样考。

【注】当一个浮点数以IEEE754标准存储到计算机中时,其实是“近似的”。浮点数在计算机中的存储是近似存储,可以这样理解,是用两个数相乘去逼近这个浮点数的。

通过监视调试窗口可以看到f1赋值234.56,但在计算机中存储的确是234.559998,所以当用f1 == 234.56 时返回值是0,说明为假。(其实计算机是拿234.559998 与 234.560000去比较,结果当然为假)

在这里插入图片描述

//判断浮点数是否等于某个值(判断两个浮点数是否相等)
int main(){
	/*
	浮点数在计算机中的存储是近似存储,可以这样理解,是用两个数相乘去逼近这个浮点数的。
	*/
	float f1 = 234.56;
	if (f1 == 234.56) //判断结果返回是0,说明为假
	{
		printf("f1 is equal to 234.56\n");
	}
	else {
		printf("f1 is not equal to 234.56\n");
	}

	//判断浮点数是否等于某个值(判断两个浮点数是否相等),必须用以下方法
	float f2 = 234.56;
	if (f2 - 234.56 > -0.0001 && f2 - 234.56 < 0.0001)//判断结果返回是1,说明为真
	{
		printf("f2 is equal to 234.56\n");
	}
	else {
		printf("f2 is not equal to 234.56\n");
	}
}

以上代码的输出结果如下图:

在这里插入图片描述

从以上代码中可知,判断浮点数是否等于某个值(判断两个浮点数是否相等),必须用以下方法:

if (f2 - 234.56 > -0.0001 && f2 - 234.56 < 0.0001)

原理是判断是否是一个“近似值”即可,取0.0001是因为浮点数显示的有效位数一般为7位(这里好像又与IEEE754描述的有效位数不太一样,这里记住怎么用就行,不太重要)。原理就是判断两个浮点数在数轴上的距离是否小于0.0001。

在这里插入图片描述

数据结构中的大题大概率会用到算术运算符,关系运算符,逻辑运算符;如写排序时就会用到这三种运算符。

一般OJ题目中限制输入范围是为了降低难度,并不是要求代码中实现只能输入该范围的数,除非题目说明当输入的值不在该范围时输出字符串“wrong”或“error”。

在这里插入图片描述

逻辑非

首先说明一点,逻辑非用到的地方不多。

针对代码中的逻辑非,首先给变量j赋值5,因为j的值非0,所以!j的值为0;然后由于逻辑非是单目运算符,结合顺序是从右至左,得到!!j的值为1。也就是对0取非,得到的值为1;对非0值取非,得到的值为0。【逻辑表达式只有真和假,对应值是1和0,在C语言中非0值都为真】

//逻辑非
int main(){
	int i, j, k;
	j = 5;
	i = !j;
	printf("i=%d\n",i);
	k = !!j;
	printf("k=%d\n", k);
}

在这里插入图片描述

赋值运算符

**常用的运算优先级:逻辑非 ! > 算术运算符 > 关系运算符 > 逻辑运算符 > 赋值运算符 = **.

	while (rewind(stdin),(ret=scanf("%d",&i))!=EOF)//while是实现循环,后面要有一个小括号。当为true时进入循环。
	{
		printf("i=%d\n", i);
	}

(ret=scanf(“%d”,&i))!=EOF 这里赋值运算符的优先级低于关系运算符,所以要想让赋值运算符先运算,需要加小括号()。[我们这里希望scanf的返回值先赋给ret,然后再用ret与EOF进行判断]

赋值运算符的左边只能是变量,以下代码会报”左操作数必须为左值“的错误。

//赋值运算符的左边只能是变量
int main(){
	int a = 5;
	//a + 3 = 10;
    //如果报出左操作数必须为左值,这是说明等号左边必须是变量。
	//左值:可以修改的值,也就是说只有变量才能叫左值
}

逗号运算符

逗号运算符的优先级最低。逗号表达式的整体值是最后一个表达式的值。

	while (rewind(stdin),(ret=scanf("%d",&i))!=EOF)//while是实现循环,后面要有一个小括号。当为true时进入循环。
	{
		printf("i=%d\n", i);
	}

while中rewind(stdin),(ret=scanf(“%d”,&i))!=EOF的”逗号,“就是逗号运算符。逗号前后各一个表达式,整体构成一个逗号表达式,逗号表达式的运算顺序是从左至右,逗号表达式的整体值是最后一个表达式的值,最后一个表达式为真,则整体为真,最后一个表达式为假,则整体为假。一般用逗号表达式往往都是在while循环里面或for循环里面,其他场景不用。

自增、自减运算符

任何时候,遇见i++;i–等都拆成两步。如j = i++ > -1;拆成两步,j=i>-1;i++。再如j = i++;拆成两步,j = i ; i++。

++i ; --i 按优先级进行正常运算即可。如 j = ++i ; 相当于 j = i +1。

自增自减运算符的结合顺序是从右到左,解释一下:逻辑非的结合顺序也是从右到左,从右到左就是拿操作数与运算符操作,如 !!j 结合顺序是从右到左,顺序是 !(!j) , 也就是从右边开始依次结合。而算术运算符都是从左到右,如 i + j + k,结合顺序是从左到右,顺序是(i + j) + k ,也就是从左边开始依次结合。

//i++代表的是i=i+1;比较难理解的是后加加和后减减
int main(){
	int i = -1;
	int j;
	j = i++ > -1;//拆成两步,j=i>-1;i++
	printf("i=%d,j=%d\n", i, j);
}

求字节运算符

sizeof不是函数,是C的关键字,是一个运算符。求字节运算符sizeof( )中只能放变量,不能放表达式。

int main(){
	int i = -1;
	//求字节运算符sizeof( )中只能放变量,不能放表达式
	printf("i的字节数=%d\n", sizeof(i));
	//控制台输出 i的字节数=4
}

作业练习

Description:读取一个65到122之间的整型数,然后以字符形式输出它,比如读取了97,输出字符a。Input:读取一个整型数,整型数 大于等于65,小于等于122;Output:输出整型数在ASCII表中对应的字符。

int main(){
	int i;
	scanf("%d", &i);
	printf("%c\n", i);//整型数在0-128之间可以用%c输出。实际上就是ASCII码表
	return 0;
}

下面来演示一下一个经典的错误。当实际操作的空间超出了变量本身占用的空间大小时,就会报这种错误。这个错误是很经典的,后面学数组时依然有可能会犯这个错误。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/25759.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

WebService接口测试

WebService的理解 WebService就是Web服务的意思&#xff0c;对应的应用层协议为SOAP&#xff08;相当于HTTP协议&#xff09;&#xff0c;可理解为远程调用技术。 特点&#xff1a; 客户端发送的请求主体内容&#xff08;请求报文&#xff09;的格式为XML格式 接口返回的响…

【P36】JMeter 交替控制器(Interleave Controller)

文章目录 一、交替控制器&#xff08;Interleave Controller&#xff09;参数说明二、测试计划设计 一、交替控制器&#xff08;Interleave Controller&#xff09;参数说明 可以将内部的组件在线程迭代时交替执行&#xff1b;交替控制器内部一般会有多个取样器 选择线程组右…

黑马Redis视频教程高级篇(一:分布式缓存)

目录 分布式缓存 一、Redis持久化 1.1、RDB持久化 1.1.1、执行时机 1.1.2、RDB原理 1.1.3、小结 1.2、OF持久化 1.2.1、AOF原理 1.2.2、OF配置 1.2.3、AOF文件重写 1.3、RDB与AOF对比 二、Redis主从 2.1、搭建主从架构 2.1.1、集群结构 2.1.2、准备实例和配置 …

多层级table联动

elementui 多层级table联动&#xff1a; 引用&#xff1a; https://blog.csdn.net/weixin_44780971/article/details/130054925 https://blog.csdn.net/qq_42581563/article/details/114325920 需要了解的属性&#xff1a; select-all 全选的时候执行select &#xff1a; 选择…

linux高级---k8s中的五种控制器

文章目录 一、k8s的控制器类型二、pod与控制器之间的关系三、状态与无状态化对特点四、Deployment1、Deployment的资源清单文件2、在配置清单中调用deployment控制器3、镜像更新4、金丝雀发布5、删除Deployment 五、Statefulset六、DaemonSet1、daemonset的资源清单文件2、在配…

点到直线距离

点到直线距离最小二乘解释 推倒部分 形象描述是C到AB距离最短&#xff0c;也就是CD最短用数学语言描述是 m i n ∣ ∣ ( B − A ) λ A − C ∣ ∣ min||(B-A) \lambda A - C || min∣∣(B−A)λA−C∣∣ 其中 D ( B − A ) λ A D (B-A) \lambda A D(B−A)λA,其实本质…

使用Windbg动态调试目标进程的一般步骤及相关要点详解

目录 1、概述 2、将Windbg附加到已经启动起来的目标进程上&#xff0c;或者用Windbg启动目标程序 2.1、将Windbg附加到已经启动起来的目标进程上 2.2、用Windbg启动目标程序 2.3、Windbg关联到目标进程上会中断下来&#xff0c;输入g命令将该中断跳过去 3、分析实例说明 …

macOS Ventura 13.5beta2 (22G5038d)发布

系统介绍 黑果魏叔 6 月 1 日消息&#xff0c;苹果今日向 Mac 电脑用户推送了 macOS 13.5 开发者预览版 Beta 2 更新&#xff08;内部版本号&#xff1a;22G5038d&#xff09;&#xff0c;本次更新距离上次发布隔了 12 天。 macOS Ventura 带来了台前调度、连续互通相机、Fac…

FPGA基于AXI 1G/2.5G Ethernet Subsystem实现千兆UDP通信 提供工程源码和技术支持

目录 1、前言2、我这里已有的UDP方案3、详细设计方案传统UDP网络通信方案本方案详细设计说明UDP层设计AXIS-FIFOAXI 1G/2.5G Ethernet Subsystem&#xff1a;输出 4、vivado工程详解5、上板调试验证并演示系统配置UDP数据回环测试注意事项 6、福利&#xff1a;工程代码的获取 1…

RK3588平台开发系列讲解(项目篇)RKNN-Toolkit2 的使用

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、RKNN-Toolkit2安装二、模型转换和模型推理三、性能和内存评估沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 NPU 是专门用于神经网络的处理单元。它旨在加速人工智能领域的神经网络算法,如机器视觉和自…

如何在 Linux 中进行网络地址转换 (NAT)?

网络地址转换&#xff08;Network Address Translation&#xff0c;简称NAT&#xff09;是一种在网络中使用的技术&#xff0c;它允许将私有网络中的IP地址映射到公共网络上&#xff0c;从而实现多个设备共享单个公共IP地址。在Linux系统中&#xff0c;我们可以使用一些工具和配…

《Web安全基础》01. 基础知识

基础 1&#xff1a;概念名词1.1&#xff1a;域名1.2&#xff1a;DNS1.3&#xff1a;网站开发语言1.4&#xff1a;后门1.5&#xff1a;Web1.6&#xff1a;Web 相关安全漏洞 2&#xff1a;数据包2.1&#xff1a;HTTP2.2&#xff1a;HTTPS2.3&#xff1a;请求数据包2.3.1&#xff…

MySQL 数据操纵语言 DML

文章目录 数据操纵语言 DMLINSERT 语句UPDATE 语句DELETE 语句 数据操纵语言 DML 数据操纵语言&#xff08;Data Manipulation Language&#xff0c;DML&#xff09;是 SQL 语言的核心部分之一。在添加、更新或者删除表中的数据时&#xff0c;需要执行 DML 语句。很多时候我们提…

03 【数据代理 事件处理】

03 【数据代理 事件处理】 1.数据代理 了解数据代理需要js的一些知识&#xff1a;Object.defineProperty()&#xff0c;属性标志&#xff0c;属性描述符&#xff0c;getter&#xff0c;setter。。。 1.1数据代理 建议学习文章地址&#xff1a; https://zh.javascript.info/p…

软考A计划-试题模拟含答案解析-卷十三

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

docker可视化管理工具portainer忘记密码重置教程

目录 前言&#xff1a; 1 停止portainer容器 2 借助仓库 portainer/helper-reset-password 重置密码 3 重新启动portainer容器 4 验证是否修改成功 5 修改登录密码 前言&#xff1a; 由于学习的深入&#xff0c;各种账号密码实在是太多了&#xff0c;建议各位配置账号密…

【JavaSE】Java基础语法(三十五):多线程实战

文章目录 1. 多线程入门1.1 多线程相关概念1.2 什么是多线程1.3 多线程的创建方式1.3.1 继承 Thread 的方式1.3.2 实现 Runnable 接口的方式1.3.3 实现 Callable 接口的方式1.3.4 Thread 类中常用方法1.3.5 sleep() 方法 和 wait() 方法区别&#xff1a; 2. 线程安全2.1 线程安…

机器学习算法

机器学习擅长的任务: ● 回归&#xff08;regression&#xff09; ● 分类&#xff08;classification&#xff09; ● 聚类&#xff08;clustering&#xff09; 1.回归&#xff08;regression&#xff09; 回归是处理连续数据时使用的方法&#xff0c;如时间序列数据。 …

java 利用poi根据excel模板导出数据(一)

前言 作为B端开发&#xff0c;导出数据是不可以避免的&#xff0c;但是有时候需求很变态&#xff0c;表头复杂的一笔&#xff0c;各种合并单元格&#xff0c;如下图&#xff1a; 这些虽说用代码可以实现&#xff0c;但是很繁琐&#xff0c;而且代码并不能通用&#xff0c;遇到…

Python编程面试题及答案(20例)

以下是一些常见的Python编程面试题以及它们的答案&#xff1a; 1.解释Python中的 GIL&#xff08;全局解释器锁&#xff09;是什么&#xff0c;它对多线程编程有什么影响&#xff1f; 答案&#xff1a;GIL是Python解释器中的一个机制&#xff0c;它确保在任何给定时间只有一个…