一、数据类型介绍
生活中有各种数据,我们在C语言中要表示这些数据,就要用到数据类型,使用整型类型描述整数,使用字符类型描述字符,使用浮点型类型描述小数。类型其实就是说它们这些数据具有共同的特征,编译器只有知道了数据的类型才知道如何操作。
那么我们就来盘一下C语言中内置的各种数据类型。
1.1字符型
char//character
[signed]char//有符号的
[unsigned]char//无符号的
1.2整型
//短整型
short [int] //这里的int可以省略
[signed] short [int] //这里的int可以省略
unsigned short [int] //这里的int可以省略
//整型
int
[signed] int
unsigned [int] //这里的int可以省略
//长整型
long [int] //这里的int可以省略
[signed] long [int] //这里的int可以省略
unsigned long [int] //这里的int可以省略
//C99Z中引入更长的整型
long long [int] //这里的int可以省略
[signed] long long [int] //这里的int可以省略
unsigned long long [int] //这里的int可以省略
1.3浮点型
float
double
long double
1.4布尔类型
在C99标准之前是没有布尔类型的,都是使用整数0表示假,非零的整数表示真。C99后引入了布尔类型,用来专门表示真假。
#include<stdio.h>
#include<stdbool.h>
int main()
{
bool flag = true;
if (flag)
printf("hhhhhhhh");
return 0;
}
布尔类型的使用得包含头文件<stdbool.h> 布尔类型变量的取值是:true或者false。
1.5数据类型的长度
每种数据都有自己的长度,创建变量时,使用不同的数据类型,能够创建出长度不同的变量,变量长度不同,存储的数据范围就会有不同。
1.5.1sizeof操作符
这个操作符是用来专门用来计算sizeof的操作符数的类型长度的,单位是字节。
sizeof操作符中的操作数可以是类型、变量和表达式。
sizeof (类型)
sizeof 表达式 //后面为表达式时括号可以省略
要注意的是:表达式中的是不真实参与运算的,根据表达式的类型来得出大小!
int a=2;
sizeof(++a);
printf("%d",a);
上面的的这段代码输出是2还是3呢?很多小伙伴会认为输出的是3。其实不是,sizeof中的表达式是不参与计算的,它只返回类型的长度!原因是sizeof在代码进行编译的时候,就根据表达式的类型确定了,而表达式是在程序运行期间才能执行,在编译期间已经将sizeof处理了,在运行期间自然就不会执行表达式了~~~
1.5.2数据类型长度
二、signed和unsigned
signed关键字,表示一个类型带有正负号,包含负值。
signed关键字,表示一个类型不带有正负号,只表示0和正整数。
对于int类型,默认是带有正负号的,也就是说inr和signed int是一样的。所以在创建变量时,signed一般直接省略,写了也不会说你错,但是能说明你很心细hh~~
signed是可以省略的,但是unsigned就不能省略了,只表是非负整数时,就必需要使用关键字unsigned来声明变量。 unsigned的好处就是在相同的内存空间中,存储的最大整数值大了int一倍。
字符类型char也是可以设置signed和unsigned。但是要注意,C语言中规定char类型是否带有正负号,由当前系统来决定。也就是说char不等同于signed char,它有可能是signed char,也有可能是unsigned char。这一点与int不同,int等同于signed int。
三、数据类型的取值范围
数据类型有很多,每一种数据类型都有自己的取值范围,也就是存储数值的最大值和最小值的区间,这么多的的类型,我们就可以在适当的场景下选择合适的类型。如何查看当前系统不同数据类型的取值范围呢?
limits.h这个头文件中说明了整型类型的取值范围。
float.h这个头文件中说明了浮点型类型的取值范围。
四、变量
4.1变量的创建
前面讲了这么多关于数据类型的知识点,那么数据类型是用来干嘛的呢?是用来创建变量的。
什么是变量?C语言中把经常变化的值称为变量,不变的值称为常量。
创建变量的语法:data_type name;如下:
//变量的创建
int age;
char hh;
double high;
//变量在创建的时候,就给一个初始值,就叫做初始化。
int age=20;
char s='h';
double high = 180 ;
4.2变量的分类
4.2.1全局变量
在大括号外部定义的变量就叫做全局变量。全局变量的使用范围更广,整个工程中都有办法使用。
4.2.2局部变量
在大括号内部定义的变量就叫做局部变量。局部变量的使用范围比较局限,只能在自己所在的局部范围内使用。
PS:那如果全局变量和局部变量的名字相同呢?
我们可以看到在上面代码的运行结果都是10,那就说明,再同名的时候,局部变量是优先使用的!
4.2.3全局变量和局部变量的存储(大致了解)
学习C/C++语言的时候我们关注内存中的三个区域:栈区,堆区,静态区。
局部变量存储在栈区
全局变量存储在静态区
堆区是用来动态内存管理的(后期慢慢介绍)
五、算术操作符:
在我们写代码时,一定就会涉及到计算,为了方便匀运算,提供了一系列操作符,其中有一组就就叫做算术操作符。分别是+、-、*、/、%。这些都是双目操作符。
5.1 + -
+和-用来完成加法和减法。+和-都是有两个操作数的,位于操作符两端的就是它们的操作数,也就是双目操作符。
5.2 *
运算符*用来完成乘法,也是双目运算符。
5.3 /
前两个运算符都比较简单,就不做过多的描述,但是这个运算符就大有讲究了。这个运算符是用来完成除法的。
5.3.1 /运算符要注意点
1.当除号的两端都是除法时,执行的是整数除法,得到的结果也是整数。
尽管x的类型是float,但是输出结果仍是2,而不是2.5,原因就在于C语言里面的整数除法是整除,只返回整数部分,丢弃小数部分。
那我们如何得到浮点数结果呢?两个操作数至少有一个是浮点数,C语言就会执行浮点数除法。
我们来看一个典例:
//下面这串代码输出的结果是多少?
int main()
{
int x=5
x=(x/20)*100
printf("%d",x);
return 0 ;
}
你经过运算后是不是觉得输出结果是25,但实际上输出的是0,x/20是整除,得到的结果是整数0,0*100后得到的结果是0。
如果要得到你算出的结果,我们只需将20改为20.0,让其执行浮点数除法,就可以得到结果25。
5.4 %
这个运算符会进行求模(余)运算,返回两个整数相除的余数。这个运算只能用于整数,不能用于浮点数。
5.4.1负数求模规则
结果的正负号由第一个运算数的正负号决定。
六、赋值操作符
在创建变量的时候给一个值,叫做初始化,在变量创建好之后再给它一个值,叫做赋值。赋值操作符为=。
int a=100;//初始化
a=66666;//赋值
6.1连续赋值
int a=11;
int b=22;
int c=33;
c=b=a+4;//从右向左依次赋值
这样的代码不容易被理解,建议拆开来写,方便观察代码执行的细节。
6.2复合赋值符
在写代码时,我们会=可能会对一个值进行自增,自减。
C语言中的复合赋值符。可以很方便的表示。复合赋值符有:
+= -= *= /= %=
//下面的后期会讲解
>>= <<= &= |= ^=
int a=2;
a+=2;//等同于a=a+2;
a-=1;//等同于a=a-1;
七、单目运算符
前面说到的都是双目运算符,有两个操作数。C语言中还有一些操作符只需要一个操作数,被称为单目操作符。++、--、+(正)、-(负)都是单目操作符。
7.1++ --
++分为前置++和后置++,--分为前置--和后置--。(前置指的是操作符在操作数前,后置指的是操作符咋操作数后)
7.1.1前置++
口诀:先+1,后使用。
int main()
{
int a = 10;
int b = ++a;
printf("%d\n", a);
printf("%d\n", b);
return 0;
}
a原来是10,a+1后赋值给b,b就是11。此时a,b都是11。
7.1.2后置++
口诀:先使用,后+1。
int main()
{
int a = 10;
int b = a++;
printf("%d\n", a);
printf("%d\n", b);
return 0;
}
a原来是10,先赋值给b,a然后在+1变为11。此时a=11,b=10。
.1.3前置--和后置-- 前置--、后置--与前面的前置++、后置++是同理的,只是把+1换成了-1。
7.2+ -
这里的+、-表示正负号,都是单目操作符。运算符+对正负没有影响,可以省略,写了也不会出错,运算符-可以改变一个值的正负号,就要用到我们常用的口诀:正负得负,负负得正。
八、强制类型转换
操作符中有有一种特殊的操作符是强制类型转换。
int a=6.666;
a是int类型,6.66是float类型,两边的类型不一致,编译器会报错。为了消除这个错误,我们就可以用到强制类型转换。
int a=(int)6.66;
这样会将6.66强制转换为int类型,只取整数部分。强制类型转化到万不得已的时候才会使用,代码都我们手敲上去的,为什么不一步到位?给自己找麻烦呢?
九、printf scanf
9.1printf
9.1.1基本用法
它的作用是将参数文本输出到屏幕上。f代表format(格式化),表示输出文本的格式。要注意的是使用printf时要引用<stdio.h>这个头文件,l里面定义了printf。
9.1.2占位符
占位符,顾名思义,就是这个位置可以用其他值带入。
#include <stdio.h>
int main()
{
printf("我是%d个清澈愚蠢的大学生",1);
return 0;
}
在这个代码中,我是%d个清澈愚蠢的大学生 是输出文本,%d就是一个占位符,这个位置会被后面的1替换。占位符的第一个字符一律是%,第二个字符表示占位符的类型,%d表示这里必须要用一个整数来替换。最后的输出结果:我是1个清澈愚蠢的大学生。
除了%d,还有很多的占位符,%s表示带入的是字符串。
#include <stdio.h>
int main()
{
printf("%s正在学习C语言","Q.__");
return 0;
}
我们可看到前面的占位符为%s时,printf函数的第二个参数就必须是字符串。打印出来的结果就是Q.__正在学习C语言。
在一个输出文本内,我们可以有多个占位符,要注意的是:参数和占位符是一一对应的关系,第一个占位符为%d,那么printf函数的第二个参数就必须为一个整数。如果有n个占位符,那么参数就有n+1个。如果参数缺少对应的占位符,那么则会输出内存中的任意值。
9.1.3占位符举例
%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:已输出的字符串数量。该占位符本身不输出,只将值存储在指定变量之中。
%0:八进制整数。
%p:指针。
%s:字符串。
%u:符(unsigned int)。
%x:十六进制整数。
%zd: size_t类型。
%%:输出一个百分号。
9.1.4输出格式
我们在编辑文档时,都可以设置很多的格式,printf函数也可以有输出格式。
9.1.4.1规定宽度打印
打印时我们可以规定最小的宽度。
%5d表示这个占位符最小的宽度为5,不够最小宽度的时候,则会在值的前面添加空格。默认是右对齐,如果要左对齐,那么则在输出内容的后面输入空格或在占位符%后添加一个-号。
9.1.4.2显示正负号
如果想要输出的数据前显示正负号,就在占位符%后添加一个+号。
9.1.4.3规定小数位数
当一个小数我们只希望保留两位小数,该如何做呢?只需在占位符%后添加.2就可以完成这个操作。 【在%s占位符和%添加一个.X(X为一个数)则表示要输出的长度!】规定小数位数可以和前面的规定宽度一起使用。
9.2scanf
前面讲的都是关于输出的,接下来介绍一下用于输入的函数——scanf
9.2.1基本用法
这个函数用来读取我们在键盘的输入,当程序运行到这段语句的时候,就会停下来,等待你敲键盘,输入好后,按下回车,scanf函数则会将你输入的值存入一个变量中。使用它时和printf函数一样,都需要引用头文件<stdio.h>,语法和printf函数很相似。
C语言中的数据都是有类型的,所以必须要先知道输入的数据是什么类型,才能去处理数据。在这里你看到了一个前面没有讲过的运算符,就是&,在变量的前面必须要加这个运算符(指针便变量除外,如:字符串变量)原因是scanf函数传递的是地址,不是值。
像前面的printf函数一样,scanf函数一次也能输入多个变量。
scanf("%d%d%f%f",&x,&y,&z,&m);
上面这串代码中,格式字符串%d%d%f%f,表示输入的是整数整数浮点数浮点数。比如6 -66 3.1415 -4.0e3。这四个值依次放入x,y,z,m这四个变量中。
scanf函数在处理数字占位符时,会自动过滤空白字符:空格,制表符,换行符等。所以我们在输入数据时,有多少个空格都不会影响到数据的输入,将数据分成几行也不会影响数据的解读。
scanf函数处理用户输入的原理是:先将用户的输入放入缓存,等按下回车键之后,按照占位符对缓存进行解读。解读用户的输入时,会从上一次解读遗留的第一个字符开始,直到读完缓存,或者遇到第一个不符合条件的字符为止。
我们看下面这一串代码:
#include <stdio.h>
int main()
{
int x;
float y;
//输入" -66.66e66# 0 "
scanf("%d", &x);
printf("%d\n", x);
scanf("%f", &y);
printf("%d\n", y);//两行scanf函数可以一次表示为scanf("%d%f",&x,&y);
return 0;
}
scanf函数开始读取,忽略数据前面的空格,从-开始读取数据,第一次读取到-66停止,因为后面的.就不属于整型的有效字符了。第二次读取时,则会从上一次停止的地方开始读取,这一从.开始读取,由于是%f,那么便会读取到.66e66(这是用科学计数法表示的浮点数)后面的#不属于浮点数的有效字符了,便会终止读取。
9.2.2scanf函数的返回值
scanf函数其实是有返回值的,返回值为一个整数,表示成功读取的变量个数。如果没有读取到任何数据,或者匹配失败,则会返回0。如果读取任何数据之前,发生了读取错误或者是遇到了读取文件的结尾,则会返回常量EOF(-1)。
如果输入两个数,按Ctrl+z,提前结束输入,则输出:我们看到r的值为2,表示正确读取了2个数值。
一个数据都不输入,则显示r=-1,也就是EOF:
9.2.3占位符
scanf函数的占位符和printf函数的占位符差距不大,这里只讲解特殊的几个
9.2.3.1 %[]
在方括号内指定一组匹配的字符(比如%[0-9])当遇到不在集合之内字符,匹配将会停止。
9.2.3.2 %c
其他的占位符都会自动忽略一开始的的空白字符,进行读取数据,这个字符不会忽略空白字符,总是返回当前的第一个字符,不管是不是空格。如果要强制跳过前面的空格,那么在%和c之间添加一个空格,表示跳过空格。
9.2.3.3 %s
它的使用规则是:从当前第一个非空白的字符开始读取,直到遇到空白字符结束。
这个规则也就说明了,%s不能读取多个字符串,除非是多个%s一起使用。
scanf函数遇到%s占位符时,会在字符串变量的末尾放上一个空字符\0。
scanf函数将字符度读取输入到字符数组时,不会检测字符串是否超过了数组的长度。如果存储的字符串大于数组的长度,那么会造成预想不到的结果。为了避免这个情况的出现,我们将%s写成%[m]s,m指定了读取字符串的最大长度,后面的字符就会被丢弃。
9.2.4赋值忽略符
每个人在输入的时候都会有不同的输入方式,可能不会按预定的格式输入,则会导致scanf函数解析数据失败。我们看下面这一串代码:
我输入的时候并没有按照预设的格式区输入,scanf函数就出现了读取错误,为了避免这种情况,scanf函数提供了赋值忽略符,(*)只要把*放在任何占位符的%后,该占位符就不会返回值,解析后将被丢弃。
我们可以看到,%c的中间加了赋值忽略符,表示这个占位符没有对应的变量,解读后不用返回。