变量的数据类型:
无论是什么数据类型,只要存储到内存中,都会以二进制的形式存在。
但是,所有数据类型,都会确定固定内存空间,在该内存空间所占据的位数中,最高位是符号位,剩余的其他位才是用来存储具体数据的。
最高位为0,代表该数为正
最高位为1,代表该数为负
①整型:
整型分为:
普通整型 int 使用%d进行格式占位
短整型 short 使用%d进行格式占位
长整形 long 使用%ld进行格式占位
int占据4个字节大小,short占据2个字节大小,long占据8个字节大小。占据的内存空间不同->能够存放的二进制数的位数不同->能够存放的最大值和最小值是不同的
计算机为了达到所有数据的大小关系和他们的绝对值的大小关系一致,计算机引入了源码-反码-补码的概念。
源码:通过短除法将十进制数转换出来的二进制数,就是源码
反码:在源码的基础上,符号位不变,其他为取反(0变1,1变0)
补码:负数的补码就是在反码的基础上+1,正数的补码就是源码
所以,在计算机中,所有的数据都是以二进制补码的形式存在的
当求得一个数的补码之后,如果是负数,则无法直接从补码获得十进制数,只能从源码算的十进制数。只需要对补码再求一次补码,就能得到源码
②字符型:
char 内存中占据1个字节内存空间,使用%c进行格式占位。但是在printf同时可以使用%d进行格式占位
我们人为的为所有的字符编排了一个序号表,每一个字符都有独特的序号,我们把该序号称为ASCII码。所以如果在printf中使用%d来输出一个字符数据,输出的会是他的ASCII码
同理,我们可以使用ASCII码对一个字符进行赋值
关于强制类型转换:在目标数据前面加上(),里面写上目标数据类型,那么此时,该目标的数据类型就会被强制的转换成该类型
关于数字字符与数字之间的转换:
③浮点型:浮点型分为单精度浮点型和双精度浮点型
单精度浮点型:float,使用%f格式占位
最高位为符号位,2到9位为指数位,10到32为尾数位。
双精度浮点型:double,使用%lf格式占位
最高位为符号位,2到13位为指数位,14到64位为尾数位。
注意:在浮点型数据的大小比较当中,通常不使用a>b这样的比较方式,而是使用a-b>-0.0001 并且 a-b<0.0001
浮点型数据不涉及位运算:什么是位运算,将数据转换二进制数,然后针对每一位0/1进行运算
浮点型数据在printf中有更多的格式占位方式:
使用%.nlf可以设定输出小数点后n位,不做设定的时候,系统默认输出小数点后6位。
使用%.nlf输出的时候,系统会对输出内容做五舍六入的操作,但是数据本身没有改变
使用%g输出小数点后有效位
④空类型:void :无法用来声明变量,但是可以用来声明函数没有返回值
⑤自定义数据类型(复合型数据类型):可以将若干个数据类型及数据含义复合后形成一个定义数据类型。该数据类型专门用来形容特定的数据变量
⑥地址数据类型:使用地址数据类型声明的变量可以用来保存一个内存地址(十六进制数),我们将这样的一个变量称为指针变量,简称指针
指针的基础:
我们可以使用一个变量去保存一个十六进制的数,该变量就是一个指针变量,也就是指针。
既然使用到了指针变量(以下简称指针),就需要声明该指针
指针类型的确定:确定所保存的地址 上面储存的数据的数据类型,然后将该数据类型作为基础数据类型,在基础数据类型后面加上*,最终形成了指针类型
我们将一个指针保存一个地址的行为称为:该指针指向了该地址
举例:int a = 0;
int* pa = &a;
pa保存了变量a的地址,我们称为pa指向了a的地址
在确定拥有一个内存地址的时候,我们就可以访问到地址上的值。
如何通过一个确定的内存地址来访问内存地址上的值:使用运算符:运算符又叫取值运算符,他只能对一个地址数据进行运算,当他对一个地址数据运算时,整个运算就成为了一个数学表达式。该数学表达式对应的值就是该内存地址上的
举例:int a = 5;
&a 就是a的地址
&a 此时可以视作整个表达式,表达式的值就是a的值,也就是5
int pa = &a;
所以pa本质就是对pa所保存的地址做取值操作,pa保存的地址就是a的地址,所以pa就能获得a的值
我们可以这么理解:对一个数据取值()运算之后,该数据的数据类型就会减少一个号
一个指针无论指向多大数据的内存地址,他永远只能指向该整段内存地址的首地址,那么在取值的时候,系统会根据该指针的基础数据类型,来判断需要针对多少个字节的内存地址进行取值。
运算符基础:
①算数运算符:
+,-,*,/,%
5/2 = 2
5%2 = 1
除法和取余运算中:除数不能为0。
取余运算中,参与运算的两个数据必须都为整型数。有些时候,不得不对两个浮点型数据进行取余运算,那就必须对参与运算的两个浮点型数据进行强制数据类型装换
强制类型转换:无论数据如何,高精度的向低精度转换时,只能是精度丢失。低精度向高精度转换,精度不变
强制类型转换是属于暂时性的类型转换,并且数据本身没有改变
在算数运算符中,需要了解到两个概念:
1. 绝大多数通过运算符构成的运算都能形成一个数学表达式,一个数学表达式就对应一个值,例如 2+3就是一个数学表达式,他的值就是5
2. 参与算数运算符的数据,数据类型如果不一致,遵循最高精度的数据类型进行计算
②赋值运算符:
=,+=,-=,*=,/=,%=以及各种其他等于
=:先读取等号右侧的数据,读取完成后,写入等号左侧。所以等号左侧必须是变量
-=:例如:a-=1 -> a=a-1,先计算等号左侧运算右侧的值,然后将运算结果重新写入到左侧,所以左侧依旧必须是一个变量
注意:赋值运算符,都必须先读取右侧的值,所以,无论何种情况下,赋值运算符的优先级肯定是最低的,看到赋值运算符,总是先计算赋值运算符右侧的值
③比较运算符:
<,>,<=,>=,==,!=
比较运算符同样的能够构成一个数学表达式,表达式的结果只有2种可能,要么为0,要么为1。如果表达式成立,则表达式的值为1,不成立则为0
④自增/自减运算符(属于单目运算符)
int a = 0;
int b = 0;
a++ -> a+=1 -> a=a+1;后加加:先赋值,后运算
++b -> b+=1 -> b=b+1;前加加:先运算,后赋值
这里无论是前加加还是后加加,赋值的对象指的是++表达式本身
a++:先将a的值,赋值给a++表达式,然后a再做自增运算
++a:a先做自增运算,然后再将新的值赋值给++a表达式
⑤逻辑运算符:
逻辑与 &&:参与逻辑与的两个数据/表达式,都为真,则整个逻辑与表达式为真,其他情况下,逻辑与表达式为假
计算机会用0表达为假,用1表达为真
计算机判断0为假,判断非0为真
逻辑或 ||:参与逻辑或的两个数据/表达式,只要有一个为真,则整个逻辑或表达式为真,全都为假的情况下,整个逻辑或表达式才为假
逻辑非 !:非(动词,逻辑非)真为假,非假为真
其中,逻辑与和逻辑或属于双目运算符,逻辑非属于单目运算符
⑥三目运算符:(表达式0)?表达式1:表达式2
判断“表达式0”的真或假,如果为真,则整个三目运算符表达式的结果为“表达式1”,反之则为“表达式2”
⑦位运算符:位运算符都是针对二进制数上的每一位的0或者1进行运算操作
按位与 &,参与运算的两个数,每一位上,都为1,则1,其他情况为0
按位或 |,参与运算的两个数,每一位上,有1则为1,全0则为0
按位取反 ~,针对参与运算的数据的每一位,都取反。
按位取反可以简单的理解成对参与运算的数据,先加1,再求相反数
按位异或 ^:针对参与运算的两个数据的每一位,相同则为0,不同则为1
左移和右移 << ,>> 1左移两位 1<<2
0000 0001->0000 0100
其中,除了按位取反为单目运算符,其他的位运算符都是双目运算符
int a = 10
a &= ~(1<<n),关闭从右往左数,第n+1栈灯
a |= (1<<n),打开从右往左数,第n+1栈灯
类型强制转换
#include<stdio.h>
int main(){
/*char ch = 'a';
printf("%d\n",ch);
printf("%c\n",ch);*/
char a = 0;
char b = a+1;
while((char)a<(char)(a+1)){
a++;
//b++;
}
printf("%d\n",a);
return 0;
}
输出ASII码
#include<stdio.h>
int main(){
char num = 0;
scanf("%c",&num);
while(getchar()!='\n');
printf("%d\n",num);
printf("%d\n",num-'0');
return 0;
}
当输入123时,因为num为char类型的,只读取一个字符1,因为格式占位符%d,所以num输出的不是字符1而是1的ASII码。
#include<stdio.h>
int main(){
double a = 3.126000000000000123;
double b = 0.123456789;
/* a == b;
a - b >-0.0000001 并且 a - b < 0.0000001;*/
printf("%.2lf\n",a);
printf("%.3lf\n",a);
printf("%g\n",b);
return 0;
}
#include<stdio.h>
int main(){
int a = 5;
int* pa = &a;
printf("%lu\n",sizeof(pa));
//sizeof可以测量一个变量或者一个数据类型在内存空间中占据的内存大小
char b = 0;
char* pb = &b;
int** ppa = &pa;
int*** pppa = &ppa;
printf("%p\n",pa);
printf("%d\n",***pppa);
return 0;
}
#include<stdio.h>
int main(){
double a = 3.6, b = 2.1;
/*int res = (int)a%(int)b;
printf("%lf\n",(double)(int)a);
printf("%d\n",res);*/
/*printf("%d\n",(int)a);
printf("%lf\n",a);*/
printf("%lf\n",3/2.0);
return 0;
}
/*
假设,程序中有一个固定的整型数据int a = 12345
现在要求对他做处理后变成54321,并写入另外一个变量b中,并输出
*/
#include<stdio.h>
int main(){
int num = 12345;
int n5 = num%10 * 10000;
int n4 = num/10%10 * 1000;
int n3 = num/100%10 * 100;
int n2 = num/1000%10 * 10;
int n1 = num/10000;
int res = n1+n2+n3+n4+n5;
printf("%d\n",res);
return 0;
}
#include<stdio.h>
int main(){
int a = 3,b = 4,c = 5,d = 6,e = 7;
printf("%d\n",a+=b+=b*=c/=d%=e-3);
return 0;
}
#include<stdio.h>
int main(){
/*int a = 4,b = 3,c = 2;
printf("%d\n",a>b>c);*/
int a = 1;
int b = 1;
printf("%d\n",a++);
printf("%d\n",++b);
return 0;
}
#include<stdio.h>
int main(){
int a = 2, b = 3;
a*=a++ + b++ + a++;
b+=a++ + b + b++;
printf("a = %d\n",a);
printf("b = %d\n",b);
return 0;
}
#include<stdio.h>
int main(){
int a = 4, b = 3 , c = 2;
printf("%d\n",!a);//a>b>c
return 0;
}
#include<stdio.h>
#define FUN(x,y) ((x)>(y))?(x):(y)
/*
第一题:从键盘输入3个数,使用三目运算符比大小,输出最大的数
第二题:将三目运算符,封装成带参宏,并使用该带参宏,实现上述案例
*/
int main(){
/*int a = 4, b = 3 , c = 2;
int res = (0)?a:b;
printf("%d\n",res);*/
int a = 0 ,b = 0 ,c = 0;
scanf("%d %d %d",&a,&b,&c);
while(getchar()!='\n');
int bigger = FUN(a,b);
int max = FUN(bigger,c);
printf("%d\n",max);
return 0;
}
/*
从键盘输入2个非0整型数字,以这两个数作为一个点的x坐标和y坐标
不使用任何判断语句,计算出该点在第几象限
*/
#include<stdio.h>
int main(){
int x = 0, y = 0;
scanf("%d %d",&x,&y);
while(getchar()!='\n');
int res = (x<0) + (y<0) + 1 + ((x>0)&&(y<0))*2;
return 0;
}
#include<stdio.h>
int main(){
int a = 10, b = 8;
printf("%d\n",a^b);
/*
0000 1010
0000 1000
0000 0010
*/
/*
0000 1000
1111 0111
1000 1000
1000 1001
*/
/*
0000 1010
0000 1000
0000 1010
*/
/*
一个文件分为3组人的3中权限,分别是用户,同组人,其他的可读,可写,可执行权限
可读权限:4
可写权限:2
可执行权限:1
3组人满权限,就是0777
*/
/*
0|4 从没有权限->拥有可读权限
0000 0000
0000 0100
0000 0100 -> 4
4|2 拥有可读权限->追加可写权限
0000 0100
0000 0010
0000 0110 -> 6
6|1 拥有读写权限->追加可执行权限
0000 0110
0000 0001
0000 0111 -> 7
7|4 拥有满权限,当再次追加可读权限,权限值依旧是7
0000 0111
0000 0100
0000 0111 -> 7
*/
return 0;
}
#include<stdio.h>
/*
使用3种方式,交换两个变量的值
也就是说初始值 int a = 5, b = 10;
交换完成后 a = 10 , b = 5
①使用中间变量交换两个变量的值
②使用算数运算符交换两个变量的值
③使用按位异或交换两个变量的值
*/
int main(){
int a = 10, b = 10;
/*int temp = 0;
temp = a;
a = b ;
b = temp;*/
/*a = a+b; //a==15
b = a-b; //b==10
a = a-b; //a==5*/
a = a^b;
b = a^b;
a = a^b;
/*
0000 1010
0000 0101
0000 1111 -> 15
0000 0101
0000 1010 -> 10
0000 1111
0000 0101 -> 5
*/
printf("a = %d, b = %d\n",a,b);
/*
在使用算数运算符以及按位运算符交换两个变量的值的时候,一定注意,这两个变量值可以一样,但是这两个变量不允许是同一片内存空间
*/
return 0;
}
#include<stdio.h>
int main(){
int a = 10, b = 10;
printf("%d\n",a|=(1<<2));
/*
0000 1010
*/
return 0;
}