声明和定义区别
声明变量不需要建立存储空间,如:extern int a;
定义变量需要建立存储空间,如:int b;
#include <stdio.h>
int main()
{
//extern 关键字只做声明,不能做任何定义,后面还会学习,这里先了解
//声明一个变量a,a在这里没有建立存储空间
extern int a;
a = 10; //err, 没有空间,就不可以赋值
int b = 10; //定义一个变量b,b的类型为int,b赋值为10
return 0;
}
从广义的角度来讲声明中包含着定义,即定义是声明的一个特例,所以并非所有的声明都是定义:
int b 它既是声明,同时又是定义
对于 extern b来讲它只是声明不是定义
一般的情况下,把建立存储空间的声明称之为“定义”,而把不需要建立存储空间的声明称之为“声明”。
使用示例
#include <stdio.h>
#define MAX 10 //声明了一个常量,名字叫MAX,值是10,常量的值一旦初始化不可改
int main()
{
int a; //定义了一个变量,其类型为int,名字叫a
const int b = 10; //定义一个const常量,名为叫b,值为10
//b = 11; //err,常量的值不能改变
//MAX = 100; //err,常量的值不能改变
a = MAX;//将a的值设置为MAX的值
a = 123;
printf("%d\n", a); //打印变量a的值
return 0;
}
常量的定义:
1、const 数据类型 常量名
2、【宏定义】#deifne 常量名 值
注意:
1、通过#define 定义的常量 是根据值来匹配数据类型的
2、const 修饰的常量是不安全 可以通过指针来修改
十进制转化二进制的方法:用十进制数除以2,分别取余数和商数,商数为0的时候,将余数倒着数就是转化后的结果。
十进制的小数转换成二进制:小数部分和2相乘,取整数,不足1取0,每次相乘都是小数部分,顺序看取整后的数就是转化后的结果。
八进制,Octal,缩写OCT或O,一种以8为基数的计数法,采用0,1,2,3,4,5,6,7八个数字,逢八进1。一些编程语言中常常以数字0开始表明该数字是八进制。
八进制的数和二进制数可以按位对应(八进制一位对应二进制三位),因此常应用在计算机语言中。
十六进制(英文名称:Hexadecimal),同我们日常生活中的表示法不一样,它由0-9,A-F组成,字母不区分大小写。与10进制的对应关系是:0-9对应0-9,A-F对应10-15。
十六进制的数和二进制数可以按位对应(十六进制一位对应二进制四位),因此常应用在计算机语言中。
8421法则:
将各个位数的二进制用十进制中的【数字 】来表示多位的二进制数 通过【数字 】相加就可以得到二进制数的数据
8 1000
4 100
2 10
1 1
1000
100
10
1
————
1 1 1 1
转化任意进制
进制在程序中打印:
int a=10;//十进制中的10
int b=010;//八进制中的10 在程序中定义一个八进制数需要在数前面加上0区分
int c=0x10;//十六进制中的10在程序中定义一个十六进制数需要在数前面加上0x区分
int d=0X10;//十六进制中的10在程序中定义一个十六进制数需要在数前面加上0X区分
注意:在程序中没有办法表示一个二进制数
%d 将数据按照十进制输出
%o将数据按照八进制输出
%x将数据按照十六进制小写输出
%X将数据按照十六进制大写输出
#include <stdio.h>
int main()
{
int a = 123; //十进制方式赋值
int b = 0123; //八进制方式赋值, 以数字0开头
int c = 0xABC; //十六进制方式赋值
//如果在printf中输出一个十进制数那么用%d,八进制用%o,十六进制是%x
printf("十进制:%d\n",a );
printf("八进制:%o\n", b); //%o,为字母o,不是数字
printf("十六进制:%x\n", c);
return 0;
}
原码、反码、补码
原码
一个数的原码(原始的二进制码)有如下特点:
- 最高位做为符号位,0表示正,为1表示负
- 其它数值部分就是数值本身绝对值的二进制数
- 负数的原码是在其绝对值的基础上,最高位变为1
反码
- 对于正数,反码与原码相同
- 对于负数,符号位不变,其它部分取反(1变0,0变1)
补码
在计算机系统中,数值一律用补码来存储。
补码特点:
- 对于正数,原码、反码、补码相同
- 对于负数,其补码为它的反码加1
- 补码符号位不动,其他位求反,最后整个数加1,得到原码
在计算机系统中,数值一律用补码来存储,主要原因是:
统一了零的编码
将符号位和其它位统一处理
将减法运算转变为加法运算
两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃
一个有符号的整型数据可以分为两部分一部分是符号位、一部分是数字位
无符号数据类型只包含数字位部分
signed int a= 1986(有符号标识 signed可以不用写)
二进制:11111000010
1986原码:0000 0000 0000 0000 0000 0111 1100 0010
-1986原码:1000 0000 0000 0000 0000 0111 1100 0010
1986反码: 0000 0000 0000 0000 0000 0111 1100 0010
-1986反码:1111 1111 1111 1111 1111 1000 0011 1101
1986补码: 0000 0000 0000 0000 0000 0111 1100 0010
-1986补码:1111 1111 1111 1111 1111 1000 0011 1110
结果: 1 0000 0000 0000 0000 0000 0000 0000 0000
溢出:在数据进行操作的时候会导致超出数据类型大小,会向前位进1,多于原始数据类型大小,会被系统自动舍弃 保留从后面开始数据类型大小的位数
10+20
0000 1010
0001 0100
0001 1110
-10+-20
原码:1000 1010
反码:1111 0101
补码:1111 0110
原码:1001 0100
反码:1110 1011
补码:1110 1100
计算
1111 0110
1110 1100
补码: 1110 0010
反码: 1110 0001
原码: 1001 1110 16+8+4+2=-30
补码符号位不动,其他位求反,最后整个数加1,得到原码
补码: 1110 0010
求反: 1001 1101 符号位不动,其他位求反
原码: 1001 1110 最后整个数加1
练习:用生辰年份年去生辰日期
1992
-326
1、将10进制转化为二进制
1992 :0000 0000 0000 0000 0000 0111 1100 1000
-326 :0000 0000 0000 0000 0000 0001 0100 0110
2、加符号位将数据变为原码
1992 :0000 0000 0000 0000 0000 0111 1100 1000
-326 :1000 0000 0000 0000 0000 0001 0100 0110
3、转化为反码
1992 :0000 0000 0000 0000 0000 0111 1100 1000
-326 :1111 1111 1111 1111 1111 1110 1011 1001
4、将反码+1转化为补码
1992 :0000 0000 0000 0000 0000 0111 1100 1000
-326 :1111 1111 1111 1111 1111 1110 1011 1010
5、计算补码
1992 :0000 0000 0000 0000 0000 0111 1100 1000
-326 :1111 1111 1111 1111 1111 1110 1011 1010
结果:1 0000 0000 0000 0000 0000 0110 1000 0010
6、将数据转化为10进制
110 1000 0010
2+128+512+1024 = 1666
无符号:
unsigned int a= 1986
无符号:1111 1111 1111 1111 1111 1111 1111 1111 =
0000 0000 0000 0000 0000 0000 0000 0000 =0
无符号整型取值:0-4294967295(2^32-1)
无符号的字符型:0-255
有符号:
int a= 1986
0111 1111 1111 1111 1111 1111 1111 1111 = 2147483647
0000 0000 0000 0000 0000 0000 0000 0001
原码: 1111 1111 1111 1111 1111 1111 1111 1111 = -2147483647
反码:1000 0000 0000 0000 0000 0000 0000 0000
补码:1000 0000 0000 0000 0000 0000 0000 0001=-2147483647
-0的补码
补码:1000 0000 0000 0000 0000 0000 0000 0000=-0 = -2147483648
sizeof关键字
sizeof不是函数,所以不需要包含任何头文件,它的功能是计算一个数据类型的大小,单位为字节
sizeof的返回值为size_t
size_t类型在32位操作系统下是unsigned int,是一个无符号的整数
#include <stdio.h>
int main()
{
int a;
int b = sizeof(a);//sizeof得到指定值占用内存的大小,单位:字节
printf("b = %d\n", b);
size_t c = sizeof(a);
printf("c = %u\n", c);//用无符号数的方式输出c的值
return 0;
}
b = 4
c = 4
整型变量的定义和输出
打印格式 |
含义 |
%d |
输出一个有符号的10进制int类型 |
%o(字母o) |
输出8进制的int类型 |
%x |
输出16进制的int类型,字母以小写输出 |
%X |
输出16进制的int类型,字母以大写写输出 |
%u |
输出一个10进制的无符号数 |
#include <stdio.h>
int main()
{
int a = 123; //定义变量a,以10进制方式赋值为123
int b = 0567; //定义变量b,以8进制方式赋值为0567
int c = 0xabc; //定义变量c,以16进制方式赋值为0xabc
printf("a = %d\n", a);
printf("8进制:b = %o\n", b);
printf("10进制:b = %d\n", b);
printf("16进制:c = %x\n", c);
printf("16进制:c = %X\n", c);
printf("10进制:c = %d\n", c);
unsigned int d = 0xffffffff; //定义无符号int变量d,以16进制方式赋值
printf("有符号方式打印:d = %d\n", d);
printf("无符号方式打印:d = %u\n", d);
return 0;
}
a = 123
8进制:b = 567
10进制:b = 375
16进制:c = abc
16进制:c = ABC
10进制:c = 2748
有符号方式打印:d = -1
无符号方式打印:d = 4294967295
整型变量的输入
#include <stdio.h>
int main()
{
int a;
printf("请输入a的值:");
//不要加“\n”
scanf("%d", &a);
printf("a = %d\n", a); //打印a的值
return 0;
}
术语 |
含义 |
bit(比特) |
一个二进制代表一位,一个位只能表示0或1两种状态。数据传输是习惯以“位”(bit)为单位。 |
Byte(字节) |
一个字节为8个二进制,称为8位,计算机中存储的最小单位是字节。数据存储是习惯以“字节”(Byte)为单位。 |
WORD(双字节) |
2个字节,16位 |
DWORD |
两个WORD,4个字节,32位 |
1b |
1bit,1位 |
1B |
1Byte,1字节,8位 |
1k,1K |
1024 |
1Kb(千位) |
1024bit,1024位 |
1KB(千字节) |
1024Byte,1024字节 |
数据类型 |
占用空间 |
short(短整型) |
2字节 |
int(整型) |
4字节 |
long(长整形) |
Windows为4字节,Linux为4字节(32位),8字节(64位) |
long long(长长整形) |
8字节 |
整型常量 |
所需类型 |
10 |
代表int类型 |
10l, 10L |
代表long类型 |
10ll, 10LL |
代表long long类型 |
10u, 10U |
代表unsigned int类型 |
10ul, 10UL |
代表unsigned long类型 |
10ull, 10ULL |
代表unsigned long long类型 |
打印格式 |
含义 |
%hd |
输出short类型 |
%d |
输出int类型 |
%l |
输出long类型 |
%ll |
输出long long类型 |
%hu |
输出unsigned short类型 |
%u |
输出unsigned int类型 |
%lu |
输出unsigned long类型 |
%llu |
输出unsigned long long类型 |
#include <stdio.h>
int main()
{
short a = 10;
int b = 10;
long c = 10l; //或者10L
long long d = 10ll; //或者10LL
printf("sizeof(a) = %u\n", sizeof(a));
printf("sizeof(b) = %u\n", sizeof(b));
printf("sizeof(c) = %u\n", sizeof(c));
printf("sizeof(c) = %u\n", sizeof(d));
printf("short a = %hd\n", a);
printf("int b = %d\n", b);
printf("long c = %ld\n", c);
printf("long long d = %lld\n", d);
unsigned short a2 = 20u;
unsigned int b2 = 20u;
unsigned long c2= 20ul;
unsigned long long d2 = 20ull;
printf("unsigned short a = %hu\n", a2);
printf("unsigned int b = %u\n", b2);
printf("unsigned long c = %lu\n", c2);
printf("unsigned long long d = %llu\n", d2);
return 0;
}
sizeof(a) = 2
sizeof(b) = 4
sizeof(c) = 8
sizeof(c) = 8
short a = 10
int b = 10
long c = 10
long long d = 10
unsigned short a = 20
unsigned int b = 20
unsigned long c = 20
unsigned long long d = 20
#include <stdio.h>
int main()
{
signed int a = -1089474374; //定义有符号整型变量a
printf("%X\n", a); //结果为 BF0FF0BA
//B F 0 F F 0 B A
//1011 1111 0000 1111 1111 0000 1011 1010
return 0;
}
当我们写程序要处理一个不可能出现负值的时候,一般用无符号数,这样可以增大数的表达最大值。
有符号和无符号整型取值范围
数据类型 |
占用空间 |
取值范围 |
short |
2字节 |
-32768 到 32767 (-2^15 ~ 2^15-1) |
int |
4字节 |
-2147483648 到 2147483647 (-2^31 ~ 2^31-1) |
long |
4字节 |
-2147483648 到 2147483647 (-2^31 ~ 2^31-1) |
unsigned short |
2字节 |
0 到 65535 (0 ~ 2^16-1) |
unsigned int |
4字节 |
0 到 4294967295 (0 ~ 2^32-1) |
unsigned long |
4字节 |
0 到 4294967295 (0 ~ 2^32-1) |
一个有符号的整型数据可以分为两部分一部分是符号位、一部分是数字位
无符号数据类型只包含数字位部分
无符号:1111 1111 1111 1111 1111 1111 1111 1111 = 4294967295(2^32-1)
0000 0000 0000 0000 0000 0000 0000 0000 =0
无符号整型取值:0-4294967295(2^32-1)
有符号:0111 1111 1111 1111 1111 1111 1111 1111 = 2147483647 (2^31-1)
有符号:1111 1111 1111 1111 1111 1111 1111 1111 = -2147483647 (-2^31-1)
原码:1111 1111 1111 1111 1111 1111 1111 1111 = -2147483647
反码:1000 0000 0000 0000 0000 0000 0000 0000
补码:1000 0000 0000 0000 0000 0000 0000 0001 = -2147483647
-0的补码
补码:1000 0000 0000 0000 0000 0000 0000 0000 = -2147483648
#include <stdio.h>
int main(void)
{
int a = 2147483647;
a = a + 1;
printf("a=%d\n", a);
return 0;
}
a=-2147483648
#include <stdio.h>
int main(void)
{
int a = 2147483647;
a = a + 2;
printf("a=%d\n", a);
return 0;
}
a=-2147483647
#include <stdio.h>
int main(void)
{
unsigned int a = 0;
a = a - 1;
printf("a=%u\n", a);
return 0;
}
a=4294967295
无符号整型取值:0-4294967295(2^32-1)
无符号的字符型:0-255
字符型:char
字符变量的定义和输出
字符型变量用于存储一个单一字符,在 C 语言中用 char 表示,其中每个字符变量都会占用 1 个字节。在给字符型变量赋值时,需要用一对英文半角格式的单引号(' ')把字符括起来。
字符变量实际上并不是把该字符本身放到变量的内存单元中去,而是将该字符对应的 ASCII 编码放到变量的存储单元中。char的本质就是一个1字节大小的整型。
输出和输入:
输出字符的两种方式:
1、printf("%c",变量)
2、putchar(字符)
输入字符的两种方式:
1、scanf("%c",&b变量)
2、变量=getchar()
#include <stdio.h>
int main(void)
{
char a;
printf("请输入a的值:");
scanf("%c",&a);
printf("a=%c\n", a);
}
#include <stdio.h>
int main(void)
{
char b;
printf("请输入b的值:");
b = getchar();
putchar(b);
putchar('\n');
return 0;
}
ASCII值 |
控制字符 |
65 |
A |
90 |
Z |
97 |
a |
122 |
z |
48 |
0 |
57 |
9 |
转义字符
转义字符 |
含义 |
ASCII码值(十进制) |
\n |
换行(LF) ,将当前位置移到下一行开头 |
10 |
\t |
水平制表(HT) (跳到下一个TAB位置) |
9 |
\a |
警报 |
7 |
\b |
退格(BS) ,将当前位置移到前一列 |
8 |
\f |
换页(FF),将当前位置移到下页开头 |
12 |
\r |
回车(CR) ,将当前位置移到本行开头 |
13 |
\v |
垂直制表(VT) |
11 |
\ |
代表一个反斜线字符"" |
92 |
代表一个单引号(撇号)字符 |
39 |
|
" |
代表一个双引号字符 |
34 |
? |
代表一个问号 |
63 |
\0 |
数字0 |
0 |
\ddd |
8进制转义字符,d范围0~7 |
3位8进制 |
\xhh |
16进制转义字符,h范围0~9,a~f,A~F |
3位16进制 |
%%可输出一个%
#include <stdio.h>
int main()
{
printf("abc");
printf("\refg\n"); //\r切换到句首, \n为换行键
printf("abc");
printf("\befg\n");//\b为退格键, \n为换行键
printf("%d\n", '\123');// '\123'为8进制转义字符,0123对应10进制数为83
printf("%d\n", '\x23');// '\x23'为16进制转义字符,0x23对应10进制数为35
return 0;
}
当超过一个数据类型能够存放最大的范围时,数值会溢出。
有符号位最高位溢出的区别:符号位溢出会导致数的正负发生改变,但最高位的溢出会导致最高位丢失。
数据类型 |
占用空间 |
取值范围 |
char |
1字节 |
-128到 127(-2^7 ~ 2^7-1) |
unsigned char |
1字节 |
0 到 255(0 ~ 2^8-1) |
char 1B=8bit
0x7f是127
0x7f+2
0111 1111
0000 0010
1000 0001 相加结果
1000 0000 求反码
1111 1111 -127 ,求原码
0xff
1111 1111
0000 0001
1 0000 0000
#include <stdio.h>
int main()
{
char ch;
//符号位溢出会导致数的正负发生改变
ch = 0x7f + 2; //127+2
printf("%d\n", ch);
// 0111 1111
//+2后 1000 0001,这是负数补码,其原码为 1111 1111,结果为-127
//最高位的溢出会导致最高位丢失
unsigned char ch2;
ch2 = 0xff+1; //255+1
printf("%u\n", ch2);
// 1111 1111
//+1后 10000 0000, char只有8位最高位的溢出,结果为0000 0000,十进制为0
ch2 = 0xff + 2; //255+1
printf("%u\n", ch2);
// 1111 1111
//+1后 10000 0001, char只有8位最高位的溢出,结果为0000 0001,十进制为1
return 0;
}
实型(浮点型):float、double
实型变量也可以称为浮点型变量,浮点型变量是用来存储小数数值的。在C语言中, 浮点型变量分为两种: 单精度浮点数(float)、 双精度浮点数(double), 但是double型变量所表示的浮点数比 float 型变量更精确。
数据类型 |
占用空间 |
有效数字范围 |
float |
4字节 |
7位有效数字 |
double |
8字节 |
15~16位有效数字 |
由于浮点型变量是由有限的存储单元组成的,因此只能提供有限的有效数字。在有效位以外的数字将被舍去,这样可能会产生一些误差。
不以f结尾的常量是double类型,以f结尾的常量(如3.14f)是float类型。
#include <stdio.h>
int main()
{
//传统方式赋值
float a = 3.14f; //或3.14F
double b = 3.14;
printf("a = %f\n", a);
printf("b = %lf\n", b);
//科学法赋值
a = 3.2e3f; //3.2*1000 = 3200,e可以写E
printf("a1 = %f\n", a);
a = 100e-3f; //100*0.001 = 0.1
printf("a2 = %f\n", a);
a = 3.1415926f;
printf("a3 = %f\n", a); //结果为3.141593
return 0;
}
a = 3.140000
b = 3.140000
a1 = 3200.000000
a2 = 0.100000
a3 = 3.141593
#include <stdio.h>
int main()
{
float r = 2;
float s = 3.14*r*r;
printf("s = %.2f\n", s); //s = 12.56
return 0;
}
格式控制符m.n,m表示输出数据宽度,n表示数据精度,具体因数据类型而不同。
"%m.nf"
1 m:总宽度,包括小数点
2 n:小数部分位数
3 m>n+1, 也可以小于, 但编译结果会按实际数据输出
4 如果m过大, 会在左边补空格
#include <stdio.h>
int main()
{
float r = 2;
float s = 3.14*r*r;
printf("s = %9.2f\n", s); //s = 12.56
return 0;
}
结果:
s = 12.56
浮点型:
float 用于存储带有小数的数据
在格式化输入printf("%f",变量)通过占位符%f来接收的
double 用于存储带有小数的数据 数据长度比float更长
注意:因为将小数转化为二进制时不是一个精确的值,所以浮点型都会有数据偏差
数据类型在内存的大小
#include <stdio.h>
int main()
{
int a=10;
//sizeof()求出数据类型在内存中占字节(Byte)大小
int len1 = sizeof(a);
//单精度浮点型
float b = 3.14;
//字符型
char c = 'A';
//双精度浮点型
double d = 5.12;
//短整形
short e = 10;
//长整型
long f = 10;
//长长整形
long long g=10;
int len2 = sizeof(b);
int len3 = sizeof(c);
int len4 = sizeof(d);
int len5 = sizeof(e);
int len6 = sizeof(f);
int len7 = sizeof(g);
printf("%d\n",a);
printf("int =%d\n",len1);
printf("float =%d\n",len2);
printf("char = %d\n",len3);
printf("double = %d\n",len4);
printf("short = %d\n",len5);
printf("long = %d\n",len6);
printf("long long = %d\n",len7);
return 0;
}
格式化输入输出
#include <stdio.h>
int main(void)
{
int a;
scanf("%d",&a);
printf("%d\n",a);
return 0;
}
练习
7f为127
#include <stdio.h>
int main(void)
{
char ch;
ch=0x7f+2;
printf("%d\n",ch);
return 0;
}
08浮点型数据操作
#include <stdio.h>
int main(void)
{
/*
单精度浮点型
float r=2;
float s = r*r*3.14;
printf("%1.2f\n",s);
*/
double a=2.0;
double s = a* a* 3.14;
printf("%f\n",s);
return 0;
}
思考任务(课后练习)
八进制必须以_____开头,十六进制必须以_______开头。
标识符只能由_______、__和_______组成。在计算机中的进制表现形式有三种,分别是、 _______、 。
C 语言提供了 sizeof 运算符,该运算符主要用于。
二进制和八进制相互转换
111 010 101 011 转换为八进制后结果为?
76321 转换为二进制结果为?
二进制和十六进制相互转换
1111 1010 1101 1011 转换为十六进制后结果为?
a6b2f1 转换为二进制结果为?
请写出-8的原码、反码、补码
计算如下程序结果
short a = 0xfffe;
printf("%d\n", a); //结果为多少?
unsigned short a = 0xfffe;
printf("%u\n", a); //结果为多少?
short a = 0x7fff + 2;
printf("%d\n", a); //结果为多少?
unsigned short a = 0xffff + 5;
printf("%u\n", a); //结果为多少?