好的,在愉快的第一节复习之后,我们马不停蹄的来到第二节复习,下面进入我们的正式内容。
上一节我们听到了整型,字符串,字符,你可能还见过浮点型,那么问题就来了:这是个煞(啥)?那还有%c、%d、%s、%f.....这是嘛玩意,别急,这一讲我们慢慢道来。
(不好意思,因为还没有去学博客编辑的格式,所以我不会加目录,各位看的时候请不要厌烦)
——---数据类型
- 我们说,用编程语言向计算机下达指令,从而解决我们的问题。要解决问题,从小学数学的应用题我们就知道,肯定先要读题,但计算机又读不懂文本咋办?那就需要用编程语言先将问题描述出来,怎么描述问题呢?对于问题中不同的信息,我们就给它们分类让计算机识别。欸,我们的数据类型就这么出来了。
在此处呢,我们先讲内置类型,自定义类型之后再说(因为我还没学)。
1.整型:先理解为整数的类型;
2.字符型:就是敲一下键盘,它所对应的符号;
3.浮点型:小数(小数点是可以左右浮动的,所以叫浮点型);
4.布尔型:判断真假,使用时要包含头文件 <stdbool.h> 布尔类型的值只有 true 和 false
(C语言中,也可以用 0 表示假,非0表示真)
————signed 和 unsigned
顾名思义,signed 表示有符号的(正数默认不会打正号),unsigned表示无符号的,这俩兄弟是用来修饰 整型和字符类型的。我们前面已经说过,字符在数据储存中是用二进制数字表示的,字符本质上也是数字,所以也可以用这俩表示。至于浮点型,你直接打出来就可以了,不需要这俩玩意。
那么,既然都有signed了,为什么还需要一个unsigned呢,有符号就可以表示所有的数了啊?
这是因为,signed unsigned 储存数据的大小有限且相同,如果你只需要打非负整数的内容(如身高,体重)unsigned就可以显示多一倍的数据,因此才会特意分出来。
————数据类型的长度
既然提到了储存数据的大小,我们就顺便说一嘴数据类型的长度。
每一种数据类型都有自己的长度,长度的不同,储存数据的范围就不同。
为了更直观的看数据类型的长度,在这里我们介绍 sizeof 这个操作符,当然,它也是一种关键字sizeof 是专门用来计算数据类型的长度的,长度单位是字节。(在这里请注意,最小长度单位是bit比特,1字节 = 8 比特)
#include <stdio.h>
int main()
{
printf("%zd\n" , sizeof (数据类型) );
printf("%zd\n" , sizeof 表达式 );
int i = 5;
printf("%zd\n", sizeof i );
printf("%zd\n", sizeof 5 );
return 0;
}
如图,我想说明的是:sizeof 的格式
数据类型必须带小括号;
表达式,创建的变量(就是int 后面跟着的 a ),具体字符(数字,字母..)是可以不用带上小括号的(打不打都行);
但是!!
#include <stdio.h>
int main()
{
int a = 0;
printf("%zd\n", sizeof (a + 5));
printf("%zd\n", sizeof a + 5);
return 0;
}
所示的两个 sizeof 中:
第一个计算的是 a+5 ;
第二个计算的是 a ;算完a后得到的值,再加上5!!!
所以,为了避免这些杂七杂八的问题,我建议不管打什么都带一个小括号,反正打出来你看得也舒服,也能避免意想不到的错误。
注:sizeof 中表达式不计算
#include <stdio.h>
int main()
{
printf("%zd\n", sizeof( 5 = 4 + 6 ));
printf("%zd\n", sizeof ( 5.0 = 4 + 2 ));
return 0;
}
在图中显示的这个表达式中,sizeof 只判断左边的那个数据是什么类型,然后打出它的类型。其余的计算式 如 (4 + 6)(4 + 2)是不会管的。
我在这里不采用鹏哥说的截断的说法,因为我个人认为这样理解有点麻烦(也可能是我学得太浅,还不明白它其他的用法),我的理解是:
————sizeof 只看你等号左边是什么类型,输出对应类型的长度,完事。
————不同的数据类型
在每一个数据类型之中,其实还有更精细的划分。
比如说: int short int(缩写为short) long int(缩写为long) long long int (缩写为long long) 这些都属于整型类型
float double long double 都属于浮点类型
(每一项中还可以加上signed unsigned,具体的这些我们不纠缠,要用的时候我们再展开讲,先清楚这些东西大概是用来做什么的,之后随着学习的深入,我们再去探究。)
那在同一个类型中,用什么来区分呢?————数据类型的长度
#include <stdio.h>
int main()
{
printf("%zd\n", sizeof (short) );
printf("%zd\n", sizeof (int) );
printf("%zd\n", sizeof (long) );
printf("%zd\n", sizeof (long long) );
printf("%zd\n", sizeof (float) );
printf("%zd\n", sizeof (double) );
printf("%zd\n", sizeof (long double) );
return 0;
}
在输入图中代码之后,我们运行程序就可以得到结果了。
这里要注意的是,有时会出现两个相同数据类型的长度相等的情况
比如: int 和 long 两个输出的结果都为 4(或者其他两个同类型的数据长度相同),这难道就是说long 和 int 长度一样,没有区别吗?
不是这样的。 long 的结果与它的前一位 int 相同,表示的是 long >= Int 的关系,long实际上不止4位。
————数据类型的范围
既然我们都知道了数据类型的长度,那么必然要提到它们的范围。通过查阅它们的取值范围,我们才可以知道在什么场景下更适合使用哪一种数据类型。
limits.h ⽂件中说明了整型类型的取值范围。
float.h 这个头⽂件中说明浮点型类型的取值范围。
————二.变量
——1.变量的概念
在小学应用题中,我们读了题就直接能做了吗?还不够。我们需要找到未知数和已知条件的等量关系,用x,y,z这样的变量表示未知数,从而写出方程,计算结果。
计算机也一样,我们给它确定了数据类型,但具体要表示一个未知量,就要创建一个变量去表示它。
类型就是所创建变量的种类
int x = 0;
在这一行中,我创建了 x 这个变量,那 x 能表示什么类型的数据呢? 前面的 int 就是 x 表示的数据种类,它表明 x 是一个整型类型的变量。
有变量,相应的就有常量,常量与我们熟知的一致,就是 100 ,20 这些数。
——2.变量的分类
全局变量:在大括号外定义的变量,可以在整个项目中使用(不同文件中需要用一定方法使用)
局部变量:在大括号内定义的变量,只能在同一个大括号内使用
如图,现在我们在大括号外和大括号内同时创建了变量 x(可以重名,只要你分得清)
在大括号内的printf 函数会打谁呢?
#include <stdio.h>
int x = 1;
int main()
{
int x = 2;
printf("%c\n", x );
return 0;
}
当然是自己人 x = 2,即局部优先。
(这些语言最早是美国人玩得最6,那么命名习惯是根据他们熟知的东西,局部优先就像美国这个国家一样,州内的事情,联邦敢过多干涉吗?管不了一点。)
——算术操作符
涉及运算,就离不开我们的数学符号了。加减乘除加上取余,但是这些熟知的符号,我们可以发现比如➗就没有出现在我们的键盘上,×(乘号)也没有,取余运算我们也没有天天在后面加个(mod),为什么呢?——因为效率太低了,➗其他地方能用吗?✖ 容易和 字母 x 弄混,mod就更是了,能直接用符号表示何必写那么多呢?
所以,编程中,+ - 保持不变,至于 ✖,我们用 *(星号)代替,➗ 用 / 代替 ,mod 用 % 代替,这样不仅效率提升了,这几个符号也都能用在其他的地方,就不需要增加符号在键盘上了。
+,-,*,/ ,% 这些两边都需要运算数的符号我们统称为双目操作符。
既然有了双目操作符,那有没有单目操作符呢? ——有的,+(正号)-(负号)++就是。
正负号好理解,那++又是什么呢?别急小老板,听我娓娓道来。
#include <stdio.h>
int main()
{
a = a + 1;
a += 1;
a++;
++a;
return 0;
}
你知道 +1 的四种写法是什么吗?请看图中,就是这四种。
为什么要这么衍生呢?——最初,你是一个什么都不懂的小白,勤勤恳恳地打着第一种;当你打多了之后,“哎呀,怎么这么麻烦,缩一缩啦。” 于是,第二种就出现了;但是呢,既然都已经缩成这样了,那能不能再缩一点呢?最终,第三种和第四种就出现了。
其中,我们着重介绍后两种:前置++ 和 后置++。
这两种++的本质都是在表达 a+1 ,但是其中别有洞天。
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
printf("%d\n", b = a++);
a = 0; // 再让 a 的值为0
b = 0; // 再让 b 的值为0
printf("%d\n", b = ++a);
return 0;
}
最后我们得到,第一次 b = 0 ; 第二次 b = 1; 而两次 a 的最终结果都是1。
原因就在于:前置++(++在前面) 是“先++,后使用” 后置++(++在后面)是“先使用,后++”
我们要打印 b 的值,第一次是 b = a++ (后置++),a 的值先赋给 b 后,a 自己再++;
第二次是 b = ++a (前置++), a 的值先 +1 ,再赋给 b 。
那么在讨论完前置后置之后,刚刚我们又看到了赋值,接下来,我们就来探讨赋值的概念。
#include <stdio.h>
int main()
{
int a = 0;
a = 1;
return 0;
}
在刚开始创建变量时,我们会顺便给这个变量一个值,这个过程就叫初始化;
我们再次用 a = 的形式让 a 的值变为你想要的值(比如 a = 2 ; a = 5 .....),再次给 a 一个值的过程就是赋值。
请注意:尽管直接写 int a ; 也可以,但是初始化是一种规范,如果不初始化,这个变量的值则是 任意值,并且在有的编译器上会报错,所以,养成好的书写习惯。
a = c = b + 2;
{
b + 2 = c;
c = a;
}
我们当然可以像连续运算一样,进行连续赋值,赋值是从右往左的顺序。
图中大括号外和大括号内的含义是一模一样的,但是:从形式上来说,分开来打不仅更美观,而且也能节省你的脑力,所以推荐分开赋值。
++,+= 也是一种赋值操作符。
——强制类型转换
顾名思义,这个操作就是强行把一个类型的数据转变为另一种类型。
int b = (int)3.14 ;
这条语句的意思是:创建整型变量 b 等于 3.14 的整型形式,也就是让 b = 3。
强制类型转换固然可以使用,但是谁在可以敲个 b = 3 的情况下 , 非得给你来个强制类型转换,那真是抽象。
所以啊,我们都是在一些特殊的地方使用它,一般不用。
————printf函数
1.内涵
打印文本到屏幕上,以<stdio.h>为头文件
2.占位符(重点概念)
占位符,通俗来讲,就是你在初高中看语文书的时候,遇到一个不懂的词义或者典故,书上给你标出来的序号:
只不过,在C语言中,我们以 % 开头作为占位符的格式,以下是不同类型的占位符:
%d : 整型占位符 %c:字符型占位符
%s : 格式串 %f :浮点型占位符
占位符格式:
printf("There are %d apples",3);
%d 代表这里要用一个整型数值代替,在逗号后面写上参数3,这句话打印出来就是“那里有3个苹果”
printf("%c", );
一般情况下,占位符会忽略空格,但是%c不会,因为空格本身也是一个字符
可以打出多个占位符,但是后面的数值必须按照顺序写,以 " , " 分隔
——3.限定宽度
在 % 的后面加上数字,就表示输出最小的宽度,默认右对齐
printf("%5d",123);
在此处,我们写了 %5d ,就代表输出的“123”要占5位,但是不够怎么办?就用右对齐的方式,将剩下的2个空位以空格替代。
如果想要跳过空格:
printf(" %c", assa);
在%c 的前面加上空格,就可以输出后面的内容了
如果想要左对齐,就输入%-5d,负号表示改变,也就是将右对齐变为左对齐
printf("%-5d",123);
——4.显示正负号
一般地,我们输入" +5 "的时候都会默认成"5",怎么样才能输出" +5 "呢?
printf("%+5d",123);
只需要添加 " + "即可。(负号是一定会显示的,所以不提及)
——5.限定小数位数
我们知道,小数默认会打印小数点后6位,但如果想要将 " 1.2 "不打成"1.200000",那该怎么办呢?
printf("%.2f",1.2);
在 % 的后面加上小数点,敲上你想要的位数即可。
当然,这几项是可以在一起用的
printf("%+5.2f",1.2);
打出来的结果就是 " +1.2"
同时,我们也可以使用 * 来传参
printf("%*.*f",3,2, 4.65);
先把参数写好,再写想要打印的数字即可。
这里,相同的格式对于字符串来说,就是限制打出字符串的个数
printf("%.5s","hello world");
我们只能看到 "hello"的结果,因为.5 已经将我们打出的个数限制在5个
有了输出,那我们可不可以输入呢?当然可以!scanf函数就是专门解决这个问题的
————scanf函数
——作用:读取用户的键盘输入
程序运行时,scanf会根据占位符类型来读取你的输入,将其存入到内存空间之中
头文件也是<stdio.h>
scanf("%d%d%f%f", &i, &j, &x, &y);
在这里,scanf会按照 整型、整型、浮点型、浮点型的顺序读取 i、j、x、y 四个数据,scanf在读取时,会自动过滤空白字符(换行符、空格)
但是,占位符的格式一定要和数据的格式保持一致!!!!
scanf("%d,%d,%d",&i &j &k);
这个例子中,双引号里占位符是以逗号隔开,但是数据之间是以空格隔开,这样造成的结果就是只能读出第一个数据,因为scanf 是根据占位符的格式一点一点读取你的数据。
scanf("%s %c %s %d",&a &b &c &d);
如果你在 c处填了整型,而c处需要的是一个字符串的时候,scanf 就会结束读取
——scanf 的返回值
在使用scanf 函数的时候,我们常常看到下面报错:"scanf 忽略返回值",虽然不理它,我们直接运行代码也能行。但这玩意究竟是个 "煞",在这里我们细细探究。
1.概念
scanf 的返回值,指的是它读取了几个数据,如:读取了1个数据,就返回1;读取了2个,就返回2
如果没有读取任何数或者匹配失败,则会报 0
如果在读取任何数据之前就发生错误,或者直接读取到文件结尾,则返回EOF(-1) EOF----- End Of File
我们可以按 ctrl + z 来得到 EOF 这个结果
2.作用
我们使用scanf 的返回值来检验是否读取成功
3.%s 的细微区别
%s 在scanf 中,不能简单的等同于字符串。
它的规则是:从第一个非空字符开始读起,直到遇到第一个空白字符结束
这也就是说,我们不能使用它来打印单词、歌曲名、书名;另外,scanf 遇到%s 时,还会在末尾存储一个\0
4.scanf 风险
实际上,scanf 最大的危险是它不会在意能装下多少,你输入多少,它就给你强行放多少。尤其是在数组中,这样的特点会导致我们的程序出错,所以我们必须要限制它:
#include <stdio.h>
int main()
{
char name[11];
scanf("%10s", name);
return 0;
}
使用%10s 表示我们只输入10个数据(因为scanf自动在末尾添加了 \0),这样就不会导致输入过多而崩溃。
5.赋值忽略符
有时,由于疏忽,我们会忽略输入的一些小问题:
#include <stdio.h>
int main()
{
int year = 0;
int month = 0;
int day = 0;
scanf("%d-%d-%d", &year, &month, &day);
printf("%d %d %d\n", year, month, day);
return 0;
}
在这里,我们的数据和占位符格式就不一致,我们该怎样避免错误呢?
#include <stdio.h>
int main()
{
int year = 0;
int month = 0;
int day = 0;
scanf("%d%*c%d%*c%d", &year, &month, &day);
return 0;
}
只需要在 % 的后面加上 *,就代表这个字符解读后可以忽略,我们就不需要在意这样的小细节了。
总结一下,在这节课中我们学习到了
1.数据类型
2.变量与操作符
3.printf 函数相关内容
4.scanf 函数相关内容
四个大内容,以及在这之下衍生的细节内容。这一节的内容才算是C语言的真正起步,虽然冗杂、繁多,但是只要你明白你是根据这四个大内容而学习具体知识,心里就不会乱。
虽然这些内容对于初学者来说很多,关系很乱记不住。但是逻辑和内核相当的简单,需要多敲多练,在不断练习代码之中掌握知识,不需要死记硬背,能用就行。