数据类型学习

问题的引入

直到计算机的是用来解决问题的一种工具

计算机通过把问题域的数据保存起来,然后通过某些运算得到想要的结果

程序 = 算法 + 数据结构

计算机首要解决的就是数据的保存问题,在数据保存之前。

首先要知道这个数据的大小,取值范围...

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 32bits

long ->ubuntu 14.04 32bits

long ->ubuntu 16.04 64bits

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,里面有10int型元素

结构体

联合体

枚举

3)指针类型

4void类型

voidC语言中,有三个作用

1void*

通用指针

2void当做函数形参,表示该函数不需要带参数

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

如果短的有符号的,高位全部补符号位

练习:

1char 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

=============

2unsigned 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;

c11111101

192 00000000     00000000 000000000 11000000

char + int =>int (自动升级为int)

dchar,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

19200000000 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位为 24181

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

//81,之后因为首部为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);

255int

补码 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);

255int

补码 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);

}

END

原文地址:https://www.cnblogs.com/qihuanye-229110/p/11147288.html