问题的引入
直到计算机的是用来解决问题的一种工具
计算机通过把问题域的数据保存起来,然后通过某些运算得到想要的结果
程序 = 算法 + 数据结构
计算机首要解决的就是数据的保存问题,在数据保存之前。
首先要知道这个数据的大小,取值范围...
1。数据类型
在C语言中,有如下类数据型
(1)基本类型 ,C语言已经定义好的类型
主要是用来存储 数(整数,小数)
整数:
(signed)char/unsigned char 占8bits
(signed)short/unsigned short 占16bits
(signed)int/unsigned int
(signed)long/unsigned long
上面的这些基本类型有什么区别?
a :
signed/unsigned
有符号 :符号位(最高位)+数值位
无符号:数值位
b:
所占内存空间不一样 =》取值范围不一样
在不同的编译器下,同一类型所占的空间大小不一样
int =>C51 占16bits
int ->ubuntu 14.04 占32个bits
long ->ubuntu 14.04 占32个bits
long ->ubuntu 16.04 占64个bits
sizeof(1)
在C语言中整数默认的类型int
typeof(2) =>int
int a;
typeof(a) =>int
typeof(3+2) =>int
typeof 某某的类型
typeof(a) b;
浮点数:
float :单精度浮点数
double:双精度浮点数
long double:长双精度浮点数
区别:
所占空间大小不一样,保存的精度不一样
sizeof(double) =>8
sizeof(float) =>4
C语言中小数的默认类型是double
typeof(2.0) =>double
typeof(2.0f) =>float
typeof(2.0+3) =>double
C语言中自动向高精度转(向存储空间大的转)
(2)构造类型:C语言中允许程序员自定义的类型
数组:一组相同元素的数据集合
int a[10];//定义了一个数组,数组名为a,里面有10个int型元素
结构体
联合体
枚举
(3)指针类型
(4)void类型
void在C语言中,有三个作用
(1)void*
通用指针
(2)void当做函数形参,表示该函数不需要带参数
eg:
int func(void)
{
}
(3)void当做函数的返回值类型,表示该函数无返回值
eg:
void func()
{
return ;
}
===
void func()
{
}
C语言中的数据,从(可写的)属性上分
变量:可以改变的数据对象
常量:不可以改变的数据对象
2.变量
变量是指在程序运行期间,其值是可以改变的数据对象。
存储变量的时候聚会开辟一个存储单元
变量在使用前,必须先定义
2.1 变量的定义
语法:
变量的类型 变量名 {=变量的初始值};
{} 可选·
变量的类型:指定数据对象的类型,所有C语言合法的数据类型都可以
变量名:一个对象的名字,标识符
C语言规定:标识符是一串字符,由字母,下划线,数字三类组成,并且第一个字符必须是字母或下划线
“见其名知其意”
int sum;
eg:
int a = 5;//定义并初始化
2.2变量的属性
变量的类型
变量名
变量的值
变量的存储单元中的内容(值)
每一个变量都有一个值,无论是否赋值
变量的存储单元
在程序运行时,系统会为每一个变量分配一个空间用来保存变量的值。
并且这个空间有一个唯一的地址,这个地址就是变量的地址
eg:
int a;
printf("gfuri%d ",a);
//没有任何语法错误
2.3变量的访问
读/写
读:从变量的存储单元中读取它的内容
读变量的值
写:把一个数值写到变量所对应的存储单元中
“赋值”
eg:
int a = 5;
a = 1024;//写操作 把1024这个值写到a所对应的地址中
b = a*4;//读操作 把a的值乘以4赋值给b
=>任意一个变量,有且仅有两层含义
(1)代表变量的地址
lvalue 左值 可写的地址
(2)代表变量的值
rvalue 右值 可读的值
3.常量
常量是指在程序运行期间,其值是不能改变的数据对象
常量有多种情况:
(1)整型常量:在代码文本中,代表整数的常量值
八进制整型常量
0[0-7]*
以字符0开头后面接0个或多个0~7的字符
eg:
0123
0777
088 //error
int a = 0123;
printf("%d ",a);
八进制与二进制对应的关系
一个八进制对应三个二进制
八进制 二进制
0 000
1 001
..
7 111
十六进制
0[xX][0-9a-fA-F]+
eg:
int a = 0xf3;
十六进制与二进制对应的关系
一个十六进制对应四个二进制
十六进制 二进制
0 0000
1 0001
..
f 1111
十进制
[0-9]+
(2)字符常量
字符常量使用单引号引起来的一个或多个字符的序列
eg:
普通字符:有形状可以打印
'a'
转义字符:没有形状可以打印
' ' =>换行符
' ' =>tab键
' ' =>回车符
'v' =>垂直制表
'' =>退格
' ' =>空字符
'ddd' 任意字符 三位八进制
'xhh' 任意字符 二位十六进制
在计算机中,保存一个字符,保存的是字符的ASCII码,而不是他的形状
美国吧每一个字符给一个唯一的整数来标识。美国使用字符是不超过256个字符,
整数值只需要8bits保存
char ,unsigned char
man ascii
'0' ~'9' 48 ~57
'a'~'z' 97 ~122
'A'~'Z' 65 ~ 90
================================
Oct Dec Hex Char Oct Dec Hex Char
────────────────────────────────────────────────────────────────────────
000 0 00 NUL ' ' 100 64 40 @
001 1 01 SOH (start of heading) 101 65 41 A
002 2 02 STX (start of text) 102 66 42 B
003 3 03 ETX (end of text) 103 67 43 C
004 4 04 EOT (end of transmission) 104 68 44 D
005 5 05 ENQ (enquiry) 105 69 45 E
006 6 06 ACK (acknowledge) 106 70 46 F
007 7 07 BEL 'a' (bell) 107 71 47 G
010 8 08 BS '' (backspace) 110 72 48 H
011 9 09 HT ' ' (horizontal tab) 111 73 49 I
012 10 0A LF ' ' (new line) 112 74 4A J
013 11 0B VT 'v' (vertical tab) 113 75 4B K
014 12 0C FF 'f' (form feed) 114 76 4C L
015 13 0D CR ' ' (carriage ret) 115 77 4D M
016 14 0E SO (shift out) 116 78 4E N
017 15 0F SI (shift in) 117 79 4F O
020 16 10 DLE (data link escape) 120 80 50 P
021 17 11 DC1 (device control 1) 121 81 51 Q
022 18 12 DC2 (device control 2) 122 82 52 R
023 19 13 DC3 (device control 3) 123 83 53 S
......
eg:
printf("%c ",65);//A
printf("%c ",0101);//A 1+64*1=65
printf("%c ",0x41);//A 4*16+1=64+1=65
printf("%c ",'a');//a
printf("%c ",'103');//C
printf("%c ",'x46');//F
(3)浮点型常量
由整数部分,小数点,小数部分,一个e/E,一个可选的带符号的整数指数和一个
可选的表示类型的后缀(f/F/l/L)
f/F =>float
l/L =>long double
没有后缀 double
整数部分 :可以省略
小数部分 :也可以省略
但是不可以同时省略
eg:
float f = 2.3E3;//正确
float f = .3E3 ;//正确
float f = 5E4;//正确
float f = 2.3E-3;//正确
float f = E5;//不正确
(4)void常量
4.整数的存储问题
整数在计算机中是如何存放?
整数是以二进制的补码形式存放
为什么要以补码?
正数
正数的补码就是其原码本身
“原码”:把相应的数值转换为二进制
13 :8bits
00001101
9 :bits
00001001
负数
负数的补码是 其绝对值的原码 取反 +1
-13 8bits
|-13| = 13 原码
00001101
11110010
11110011 =》-13在计算机中的存储形式
用8bits来存一个整数
-2的存放形式
11111110
254的存放形式
11111110
结论:一个负整数会和一个比较大的正整数的补码形式(在计算机中的存放形式)一样的
-x 和 (2^n-x) 一样
n表示存放的bit位数
11111101
既可以是-3又可以是253
unsigned =>253
signed =>-3
符号位+数值位
符号位 :
1 =》负数
0 =》正数
结论:CPU内部是没有正负之分,对于CPU来说,所有的bit位都是数值位
都参与运算。至于是有符号位还是无符号位,就看编译器的词义
练习:
分析如下程序的输出结果
(1)
int a = -3;
//程序运行时,会a分配32bits的存储单元
并且把数值-3 按照补码存放到a的存储单元中
|-3| 原码
00000000 00000000 00000000 00000011 3
11111111 11111111 11111111 11111100 取反
11111111 11111111 11111111 11111101 +1
=》-3的存放形式
%d
11111111 11111111 11111111 11111101 (x)
最高位是符号位,并且是1,负数
那么负多少?
求这个数的绝对值原码
数的绝对值原码
-1 =》取反
11111111 11111111 11111111 11111101 (x)
11111111 11111111 11111111 11111100 -1
00000000 00000000 00000000 00000011 取反
|x| = 3
%u
11111111 11111111 11111111 11111101
无符号数,全部都是数值位
printf("a = %d ",a);//-3
printf("a = %u ",a);//2^32-3
(2)
int a = -56;
printf("a = %d ",a);//-56
printf("a = %u ",a);//2^32-56
(3)
int a = 2048;
printf("a = %d ",a);//2048
printf("a = %u ",a);//2048
(4)
unsigned int a = -1u;
-1 和-1u的区别?
typeof(-1) =>int
typeof(-1u) =>unsigned int
printf("a = %d ",a);//-1
printf("a = %u ",a);//2^32-1
char : -128~127
unsigned char : 0~255
正数
0 1111111 =>127
1 0000000
1 1111111
1 0000000 =》128 x= -128
无符号:0
11111111 255
GNU有一个标准的头文件 stdint.h
int8_t //有符号8bits整数类型
uint8_t //无符号8bits整数类型
...
有符号8bits整数的最小值和最大值
INT8_MIN
INT8_MAX
INT16_MIN
INT16_MAX
INT32_MIN
INT32_MAX
...
===============
char c = 250;
char d;
d = c+8;
c:
11111010
00001000
d: 00000010
printf("d = %d ",d);//2
printf("d = %u ",d);//2
5.整型变量的赋值问题
在C语言中,允许不同类型的整数之间相互赋值
char =>int
long =>short
c标准:
(1)长-》短
长的赋值给短的,低字节直接拷贝
高字节全部丢弃
(2)短-》长
短的赋值给长的,低字节直接拷贝
高字节补?
如果短的无符号的,高位全部补0
如果短的有符号的,高位全部补符号位
练习:
(1)char c = -3;
printf("c = %d ",c);//-3
printf("c = %u ",c);//2^32-3
c:
1111 1101
%d :int
短=》长
有符号数
11111111 11111111 11111111 11111101
-1 11111111 11111111 11111111 11111100
取反 00000000 00000000 000000000 00000011
%u
11111111 11111111 11111111 11111101
=============
(2)unsigned char c = -3;
printf("c = %d ",c);//253
printf("c = %u ",c);//253
c:
1111 1101
%d :int
短=》长 短的无符号的,高位直接补0,低字节直接拷贝
00000000 00000000 00000000 11111101
%u:int
短=》长 短的无符号的,高位直接补0,低字节直接拷贝
00000000 00000000 00000000 11111101
6."溢出问题"
char c = 253;
char d;
d = c+192;
c:11111101
192 : 00000000 00000000 000000000 11000000
char + int =>int (自动升级为int)
d为char,8bits,在计算时,192只取低8bits
11111101
11000000
110111101
11111111 11111111 11111111 10111101
printf("d = %d ",d);//-67
printf("d = %u ",d);//2^32-67
======
char c = 253;
unsigned char d;
d = c+192;
c :
11111101
192:11000000
d : 10111101
char =>int
00000000 00000000 00000000 10111101
printf("d = %d ",d);//255-2-64 = 189
printf("d = %u ",d);//189
======
char c = 253;
int d;
d = c+192;
c :11111101
192:00000000 00000000 00000000 11000000
c+192:
c =>int
11111111 11111111 11111111 11111101
00000000 00000000 00000000 11000000
100000000 00000000 00000000 10111101
printf("d = %d ",d);//189
printf("d = %u ",d);//189
=====
char c = 253;
char c1 = 192;
int d;
d = c+c1;
printf("d = %d ",d);//-67
printf("d = %u ",d);//2^32-67
c :
c1:
c+c1:
c->int
c1->int
7.总结
数据类型
基本类型
构造类型
指针类型
void
变量的属性:
变量的类型
变量名
变量的值
变量的存储单元
变量的访问:
读/写
lvalue
rvalue
常量
整数在计算机中的存放形式
补码
-x 与 2^n-x补码形式一样
整数之间的赋值问题
长 =》短
短 =》长
作业:
分析如下程序的输出结果
printf("%d ",-1);
printf("%u ",-1);
printf("%d ",(char)-1);
printf("%u ",(char)-1);
printf("%d ",(unsigned char)-1);
printf("%u ",(unsigned char)-1);
printf("%d ",-1u);
printf("%u ",-1u);
printf("%d ",255);
printf("%u ",255);
printf("%d ",(char)255);
printf("%u ",(char)255);
printf("%d ",(unsigned char)255);
printf("%u ",(unsigned char)255);
#include<stdio.h>
//share文件夹,测试程序
int main()
{
printf("j1=%d ", -1);
printf("j1=%u ", -1);
// -1 2^32-1
//就1的绝对值的原码为0000 0001 补码为1111 1111 扩展为36位为 24个1加8个1
printf("j1=%d ", (char)-1);
printf("j1=%u ", (char)-1);
//感觉与上题目一致,测试的确一致
printf("j1=%d ", (unsigned char)-1);
printf("j1=%u ", (unsigned char)-1);
//255 255
//只要将1111 1111全部扩展到32位,跟着前面的符号位进行变化,因为是无符号,所以前面全部加0,所以理解
printf("j1=%d ", -1u);
printf("j1=%u ", -1u);
//-1 2^32-1
//因为开始加u就是无符号的所以,全部已经进行了扩展
printf("j1=%d ", 255);
printf("j1=%u ", 255);
//255 255
//直接是整型的,所以不需要怎么样的
printf("j1=%d ", (char)255);
printf("j1=%u ", (char)255);
//-1 2^32-1
//8个1,之后因为首部为1,判定为负数,扩展之后是全1,所以判定为负数,最后减数1,取反
printf("j1=%d ", (unsigned char)(255));
printf("j1=%u ", (unsigned char)(255));
//255 255
//全为1,然后因为无符号,所以全部补上0,符号位判定为0,直接计算
}
作业答案:
printf("%d ",-1);
printf("%u ",-1);
-1 :int
-1的补码:11111111 11111111 11111111 11111111
%d: (第一个1当做符号位)
减1 :11111111 11111111 11111111 11111110
取反:00000000 00000000 00000000 00000001
其值为-1
%u:(没有符号位)
11111111 11111111 11111111 11111111
其值为2^32-1
printf("%d ",(char)-1);
printf("%u ",(char)-1);
-1 :int
-1的补码:11111111 11111111 11111111 11111111
转换成char
11111111
再转换成int:
11111111 11111111 11111111 11111111
%d: (第一个1当做符号位)
减1 :11111111 11111111 11111111 11111110
取反:00000000 00000000 00000000 00000001
其值为-1
%u:(没有符号位)
11111111 11111111 11111111 11111111
其值为2^32-1
printf("%d ",(unsigned char)-1);
printf("%u ",(unsigned char)-1);
-1 :int
-1的补码:11111111 11111111 11111111 11111111
转换成unsigned char
11111111
再转换成int:
00000000 00000000 00000000 11111111
%d: (第一个1当做符号位)
00000000 00000000 00000000 11111111
其值为255
%u:(没有符号位)
00000000 00000000 00000000 11111111
其值为255
printf("%d ",-1u);
printf("%u ",-1u);
-1u :unsigned int
-1的补码:
11111111 11111111 11111111 11111111
%d:(第一个1当做符号位)
减1 :11111111 11111111 11111111 11111110
取反:00000000 00000000 00000000 00000001
其值为-1
%u:(没有符号位)
11111111 11111111 11111111 11111111
其值为2^32-1
printf("%d ",255);
printf("%u ",255);
255 :int
补码 :00000000 00000000 00000000 11111111
%d: (第一个0当做符号位)
00000000 00000000 00000000 11111111
其值为255
%u:(没有符号位)
00000000 00000000 00000000 11111111
其值为255
printf("%d ",(char)255);
printf("%u ",(char)255);
255:int
补码 :00000000 00000000 00000000 11111111
转化成char
11111111
再转换成int
11111111 11111111 11111111 11111111
%d:(第一个1当做符号位)
减1 :11111111 11111111 11111111 11111110
取反:00000000 00000000 00000000 00000001
其值为-1
%u:(没有符号位)
11111111 11111111 11111111 11111111
其值为2^32-1
printf("%d ",(unsigned char)255);
printf("%u ",(unsigned char)255);
255:int
补码 :00000000 00000000 00000000 11111111
转化成char
11111111
再转换成int
00000000 00000000 00000000 11111111
%d:(第一个0当做符号位)
00000000 00000000 00000000 11111111
其值255
%u:(没有符号位)
00000000 00000000 00000000 11111111
其值255
算生日代码
#include <stdio.h>
int main()
{
int n,sum = 16;
int year,month,day;
//输入出生年月日
scanf("%d%d%d",&year,&month,&day);
//去掉尾年,把整年总天数算出来
for(n = year;n<=2018;n++)
{
if((n%4 == 0 && n%100 != 0) || (n%400 == 0))//判断是否为闰年
{
sum += 366;//年数加366
}
else
{
sum += 365;
}
}
//去掉出生那日之间的天数
int monthday[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
for(n = 1; n < month;n++)
{
sum -= monthday[n];
}
sum -= day;
if(((year%4 == 0 && year%100 != 0) || (year%400 == 0))&& (month > 2))//判断是否为闰年
{
sum -= 1;//年数加366
}
printf("sum = %d ",sum);
}