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

news2024/12/23 0:20:33

如何打开项目

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

找到要打开的解决方案目录,进去之后双击后缀为.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;
}

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

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GIN框架(GOLANG)讲解如何疯速入门

1.初始化项目&#xff1a; 1.初始化项目&#xff1a;go mod init 2.下载gin框架&#xff1a;go get -u github.com/gin-gonic/gin 3.引入&#xff1a;import "github.com/gin-gonic/gin" 注意点&#xff1a; 报错&#xff1a;$GOPATH/go.mod exists but should …

Python可视化分析项目

今天给大家分享一个基于python的django框架结合爬虫以及数据可视化和数据库的项目&#xff0c;该项目总体来说还是挺不错的&#xff0c;下面针对这个项目做具体介绍。 1&#xff1a;项目涉及技术&#xff1a; 项目后端语言&#xff1a;python 项目页面布局展现&#xff1a;前…

代码随想录算法训练营第四十二天|416. 分割等和子集

LeetCode416. 分割等和子集 背包问题&#xff0c;有N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最大。背包问题有多种背包方式&#xff0c;常见…

地理探测器的应用方法

关于地理探测器的使用&#xff0c;网络上有大量的教学视频及资料&#xff0c;既可以用Excel计算&#xff0c;也可以利用R语言计算&#xff0c;本文主要分享利用Excel计算的方法&#xff0c;借鉴了大量的学习资料&#xff0c;记录一下供自己参考&#xff0c;也希望能帮到有需要的…

CLR via C#(一)CLR的执行模型

一、什么是CLR CLR全称Common Language Runtime&#xff0c;即公共语言运行时。它可以为所有面向CLR的语言提供运行时的内存管理、程序集加载、安全性、异常处理和线程同步等功能。 事实上&#xff0c;CLR并不关心开发者使用的到底是哪种语言&#xff0c;只要这门语言的编译器…

chatgpt赋能python:Python图像处理优化技巧:提高网站SEO效果的必修课程

Python图像处理优化技巧&#xff1a;提高网站SEO效果的必修课程 介绍 在当前数字化时代&#xff0c;网站的SEO优化已经成为了网站营销的重要一环。在优化网站SEO的同时&#xff0c;提升图像处理技巧也成为了重要的一环。Python作为当前最为火热的数据科学语言之一&#xff0c…

chatgpt赋能python:Python计算圆柱体积的方法

Python计算圆柱体积的方法 Python是一种广泛使用的编程语言&#xff0c;由于其易于学习和使用的特点&#xff0c;许多人在业余时间选择了学习Python。Python可以用来解决各种计算问题&#xff0c;其中包括计算圆柱体积。在本文中&#xff0c;我们将探讨如何使用Python计算圆柱…

chatgpt赋能python:Python在一个程序里调用另一段程序

Python在一个程序里调用另一段程序 随着Python程序的复杂度越来越高&#xff0c;有时候一个程序难以处理所有的任务。这时候我们可能需要将任务拆分成多个脚本来执行。但是&#xff0c;这会导致代码的复杂性增加&#xff0c;同时也会增加可读性和维护成本。这时候&#xff0c;…

LeetCode排序数组(常用排序一一实现)

912. 排序数组 - 力扣&#xff08;LeetCode&#xff09; 这道题他会设置一个数据量特别特别大的案例&#xff0c;对于一般的算法是一定过不去的 1.冒泡排序---这种的时间复杂度是O(n*n)&#xff0c;对于这道题是不可能过得去的 /*** Note: The returned array must be malloce…

EMQX将数据发送到后端

本文主要是记录了使用免费的EMQX的数据集成功能&#xff0c;将数据流转到后端平台。 在实现过程中&#xff0c;首先是在云服务器之中下载了EMQX&#xff0c;之后通过EMQX的数据集成功能&#xff0c;创建了数据桥接以及与之对应的规则&#xff0c;可以实现将EMQX接收到的数据转发…

C# | 二分查找算法的实现

C# | 二分查找算法的实现 文章目录 C# | 二分查找算法的实现前言示例代码算法思路测试结果结束语 前言 二分查找法一种在有序数组中查找目标值的算法。划重点——“有序”&#xff0c;与需要遍历整个数组的查询算法不同&#xff0c;二分查找法通过将数组分成两部分来快速定位目…

MATLAB-二维图形的绘制

本博文主要介绍绘图函数 Plot 函数的使用,图形的网格、坐标、标题、图例备注以及线型和颜色标记等。 一、Plot 指令 将数据绘制成曲线的函数是 Plot 指令, 该命令可以带有不同数目的参数。最简单的形式就是将数据传递给 Plot , 但是线条的类型和颜色和颜色…

Vue.js 比较重要知识点总结三

概述 Vue 中 nextTick 的实现原理v-if 和 v-show 的区别Vue 中的 key 有什么作用如何理解ref toRef和toRefsComposition API如何实现代码逻辑复用&#xff1f; Vue 中 nextTick 的实现原理 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法&#xf…

chatgpt赋能python:Python在线聊天:实现即时通讯的快速解决方案

Python在线聊天&#xff1a;实现即时通讯的快速解决方案 在当今数字时代&#xff0c;在线聊天已经成为人与人之间交流的主流方式。Python在线聊天应用程序提供了一种快速且可定制的解决方案&#xff0c;使个人用户和企业可以进行互联网通信。本文将向您介绍Python在线聊天的基…

软考A计划-电子商务设计师-电子商务系统建设

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

深挖MYSQL大表加索引

深挖MYSQL大表加索引 起因是这样的&#xff0c;有一张表存在慢sql&#xff0c;查询耗时最多达到12s&#xff0c;定位问题后发现是由于全表扫描导致&#xff0c;需要对字段增加索引&#xff0c;但是表的数据量600多万有些大&#xff0c;网上很多都说对大表增加索引可能会导致锁…

垂直行业(新站)SEO流量快速起飞的核心思路

现在做站不比以前了&#xff0c;不管你是做百度也好&#xff0c;还是谷歌也罢&#xff0c;对于行业精准SEO流量来说肯定是没有以前那么容易做了。但是不容易做不代表没有机会做&#xff0c;机会一直还是有的&#xff0c;尤其是最近百度打击泛站&#xff0c;对于垂直行业来说其实…

chatgpt赋能python:Python图片尺寸大小修改指南

Python图片尺寸大小修改指南 在现代网站设计中&#xff0c;图像是非常重要的一部分。图片质量和大小是网站排名和用户体验的关键因素。一般来说&#xff0c;网站应该尽量避免使用过多的大图片&#xff0c;因为它们会使用户等待过长的时间&#xff0c;同时也会降低网站的加载速…

JAVA基础练习(6)

目录 1.冒泡排列学员成绩(降序) 2.常用Arrays类的应用 2.1.sort 2.2.equals 2.3.toString 2.4.fill 2.5.Arrays.copyOf 2.6.binarySearch 3.利用二维数组计算成绩 1.冒泡排列学员成绩(降序) package ch06;import java.util.Arrays; import java.util…

代码随想录算法训练营第四十一天|343. 整数拆分|96.不同的二叉搜索树

LeetCode343. 整数拆分 动态规划五部曲&#xff1a; 1&#xff0c;确定dp数组&#xff08;dp table&#xff09;以及下标的含义&#xff1a;dp[i]&#xff1a;分拆数字i&#xff0c;可以得到的最大乘积为dp[i]。 2&#xff0c;确定递推公式&#xff1a;可以想 dp[i]最大乘积…