您的位置:首页 > 编程语言 > C语言/C++

C语言基本教程 第4课:数据类型

2016-08-16 17:02 781 查看
现在有一排水桶,一共有0xFFFFFFFF 个,编号为0--0xFFFFFFFF,每个水桶的容量是8升,

 

 现在如果  想一次取水 3升, 那么随便选择一个水桶(比如是第32号水桶),注入水.

 因为所有的水桶看起来都一样,我们不太容易知道是哪个编号的位置里装水了,

 为了跟没有装水的水桶区别开来,我们在这个第32号装了水的水桶上贴个标签叫 "xiaoming".

 

那么这个时候从一排水桶里边找我们的第32号水桶就方便多了.

有时候我们需要一次性装入32升水,那简单, 直接找4个水桶啊. 然后在这4个水桶上 用胶带粘起来整体作为一个基本单位,贴个标签,叫做 "xiaoliang".

在这里,这一排水桶就是内存,, 一个水桶就是 基本数据类型种的 char,  4个水桶作为一个整体就是int, 

这个"xiaoming" ,  "xiaoliang" 就是变量的名字.

 



C 语言数据类型 包含 基本数据类型和构造类型,指针类型和空类型.

如下:



看了上边,会不会觉得很复杂 ?

其实常用的也就只有 char ,int , float, double, 以及以上几种的组合构造类型而已.

一般而言, 长整形至少 和整形一样长,整形至少和短整形一样长.

long >= int >= short

char 为一个字节(8位), int 一般和cpu 的机器字长, 通常由编译器决定.

通常用 sizeof 操作符来确定 具体字节.

以下代码可用于 确定 具体字节:

#include<stdio.h>

int main(int argc ,char * argv[])
{
printf("char   : %d 个字节,%d 位 \n",sizeof(char),8*sizeof(char));
printf("short  : %d 个字节 %d 位 \n",sizeof(short),8*sizeof(short));
printf("int    : %d 个字节,%d 位 \n",sizeof(int),8*sizeof(int));
printf("long   : %d 个字节,%d 位 \n",sizeof(long),8*sizeof(long));

printf("float  : %d 个字节,%d 位 \n",sizeof(float),8*sizeof(float));
printf("double : %d 个字节,%d 位 \n",sizeof(double),8*sizeof(double));

return 0;
}

以上 提到了变量的概念, 变量就是我们在初中学到的代数里边的概念, 就是 用一个字母来代替数字.

在C 语言里边, 变量就是这个作用, 

char      型变量 就是来代表一个 字母,

int         型变量 就是来代表一个 整数,  ( short,long  也是来代表一个 整数的, 只是表示范围不同).

float      型变量 就是来代表一个小数,

double 型变量 也是来代表一个小数,只不过它比 float 能表示的范围更大.

这里的表示范围跟什么有关系呢 ? 就是前边的具体字节.

我们平时使用的数字都是由 0~9 共十个数字组成的,例如 1、9、10、297、952 等,一个数字最多能表示九,如果要表示十、十一、二十九、一百等,就需要多个数字组合起来。

例如表示 5+8 的结果,一个数字不够,只能”进位“,用 13 来表示;这时”进一位“相当于十,”进两位“相当于二十。

因为逢十进一,也因为只有 0~9 共十个数字,所以叫做十进制(Decimalism)。

进制也就是进位制。在进行加法(减法)运算时,逢X进(借)一就是X进制,这种进制也就包含X个数字,基数为X。十进制有0~9共10个数字,基数为10,在加减法运算中,逢十进一,借一当十。

我们不妨将思维拓展一下,既然可以用 0~9 共十个数字来表示数值,那么也可以用0、1两个数字来表示数值,这就是二进制(Binary)。


二进制思想

二进制只有0和1两个数字,基数为2,在加减法运算中,逢二进一,借一当二。
表示数值:0、1、10、111、100、1000001
加法:1+0=1、1+1=10、10+110=1000、111+111=1110、
减法:1-0=1、10-1=1、100-11=1、1010-101=101

要想学习编程,就必须了解二进制,它是计算机处理数据的基础。

内存条是一个非常精密的部件,包含了上亿个电子元器件,它们很小,达到了纳米级别。这些元器件,实际上就是电路;电路的电压会变化,要么是 0V,要么是 5V,只有这两种电压。5V
是通电,用1来表示,0V 是断电,用0来表示。所以,一个元器件有2种状态,0 或者 1。

我们通过电路来控制这些元器件的通断电,会得到很多0、1的组合。例如,8个元器件有 28=256
种不同的组合,16个元器件有 216=65536
种不同的组合。虽然一个元器件只能表示2个数值,但是多个结合起来就可以表示很多数值了。

我们可以给每一种组合赋予特定的含义,例如,可以分别用 1101000、00011100、11111111、00000000、01010101、10101010
来表示 C、语、言、中、文、网 这几个字,那么结合起来 1101000 00011100 11111111 00000000 01010101 10101010 就表示”C语言中文网“。

一般情况下我们不一个一个的使用元器件,而是将8个元器件看做一个单位,即使表示很小的数,例如 1,也需要8个,也就是 00000001。

1个元器件称为1比特(Bit)或1位,8个元器件称为1字节(Byte),那么16个元器件就是2Byte,32个就是4Byte,以此类推:

8×1024个元器件就是1024Byte,简写为1KB;
8×1024×1024个元器件就是1024KB,简写为1MB;
8×1024×1024×1024个元器件就是1024MB,简写为1GB。

现在,你知道1GB的内存有多少个元器件了吧。我们通常所说的文件大小是多少KB、多少MB,就是这个意思。

单位换算:
8 Bit = 1Byte
1024Byte = 1KB
1024KB = 1MB
1024MB = 1GB
1024GB = 1TB

一个字节有8位,每一位 有两种情况,要么为0,要么为1, 总的可能就是 2的8次方,就是 256, 表示范围就是 0~255.

那么我们知道 char型 一共可以表示的字符 个数是 255个,这就是表示范围.

而int 是4个字节(具体编译器可能不同),那就是2的32次方,表示范围就是0~4 294 967 296.

这里有人可能会疑惑了: 无论整数还是小数,都是无穷的,怎么办? 这话很有道理,不过数字是无穷的,我们用的时候根本用不到那么大的数字,

int 型就有42亿的表示范围了, 基本上够我们用了, 如果是科学计算确实需要那么大数字, 会有特定算法进行大数据处理的,不用担心了.

而小数,通常我们也只是要求一个精确度, 小数点后保留几位小数 就是解决这个问题的.

有的人可能又要疑惑了: 说了这么多,也没见 负数怎么表示呢? 负数怎么办?

我们已经知道计算机中,所有数据最终都是使用二进制数表达。
比如,假设有一int类型的数,值为5,那么,我们知道它在32位计算机中表示为:
00000000 00000000 00000000 00000101
在计算机中,负数以其正值的补码形式表达。
原码:一个整数,按照绝对值大小转换成的二进制数,称为原码。

反码:将二进制数按位取反,所得新二进制数称为原二进制数的反码。所以11111111
11111111 11111111 11111010是5的反码。
补码:反码加1称为补码。所以,-5
在计算机中表达为:11111111 11111111 11111111 11111011。转换为十六进制:0xFFFFFFFB。

如果是带符号型,则最高位是符号位,0表正数1表负数。 比如:unsigned
char范围是0000 0000 到1111 1111,范围是0-255;

而如果是signed char型,则范围是1000
0000到0111 1111,结果是-128-127。

unsigned 未指定符号位,只能表示正数

signed  指定了符号位,能表示正数和负数.

signed 类型因为最高位符号位用作标记位,所以能表示的正数范围是unsigned 类型的一半.

如果不指名unsigned, 默认为 signed,signed可以省略.

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

char 型表面上表示的是字符型 数据, 其实存储的时候 也是按照整数存储的,

参见如下 ascii码表:





可以用 printf 的 %c 和 %d 验证.

计算机是以二进制的形式来存储数据的,它只认识0和1两个数字,我们在屏幕上看到的文字,在存储到内存之前也都被转换成了二进制(0和1序列)。

可想而知,特定的文字必然对应着固定的二进制,否则将无法转换。那么,怎样将文字与二进制对应呢?这就需要有一套规范,计算机公司和软件开发者都必须遵守。


ASCII码

我们知道,一个二进制位(Bit)有0、1两种状态,一个字节(Byte)有8个二进制位,有256种状态,每种状态对应一个符号,就是256个符号,从00000000到11111111。

计算机诞生于美国,早期的计算机使用者大多使用英文,上世纪60年代,美国制定了一套英文字符与二进制位的对应关系,称为ASCII码,沿用至今。

ASCII码规定了128个英文字符与二进制的对应关系,占用一个字节(实际上只占用了一个字节的后面7位,最前面1位统一规定为0)。例如,字母 a 的的ASCII码为
01100001,那么你暂时可以理解为字母 a 存储到内存之前会被转换为 01100001,读取时遇到 01100001 也会转换为 a。


Unicode编码

随着计算机的流行,使用计算机的人越来越多,不仅限于美国,整个世界都在使用,这个时候ASCII编码的问题就凸现出来了。

ASCII编码只占用1个字节,最多只能表示256个字符,我大中华区10万汉字怎么表示,日语韩语拉丁语怎么表示?所以90年代又制定了一套新的规范,将全世界范围内的字符统一使用一种方式在计算机中表示,这就是Unicode编码(Unique
Code),也称统一码、万国码。

Unicode 是一个很大的集合,现在的规模可以容纳100多万个符号,每个符号的对应的二进制都不一样。Unicode 规定可以使用多个字节表示一个字符,例如
a 的编码为 01100001,一个字节就够了,”好“的编码为 01011001 01111101,需要两个字节。

为了兼容ASCII,Unicode 规定前0~127个字符与ASCII是一样的,不一样的只是128~255的这一段。

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

除了二进制,编程中也经常使用八进制和十六进制。

八进制有0~7共8个数字,基数为8,逢八进一,借一当八;十六进制中,用A来表示10,B表示11,C表示12,D表示13,E表示14,F表示15,因此有0~F共16个数字,基数为16,逢16进1,借1当16。例如:

八进制 3072 = 3×83 + 0×82 + 7×81 + 2×80 = 1536 + 0 + 56 + 2 = 1594
十六进制 E3F9 = 14×163 + 3×162 + 15×161 + 9×160 = 57344 + 768 + 240 + 9 = 58361

二进制、八进制、十进制、十六进制的对应关系
十进制二进制八进制十六进制十进制二进制八进制十六进制
000010101012A
111111101113B
2102212110014C
3113313110115D
41004414111016E
51015515111117F
61106616100002010
71117717100012111
8100010818100102212
9100111919100112313
在C语言中,八进制通常以“0”开头(注意是数字 0,而不是字母 o),例如 0307;十六进制通常以“0x”或“0X”开头(不区分大小写),例如 0xE27
或 0X89F。
前面两节对二进制、八进制和十六进制进行了说明,接下来讲一下不同进制之间的数字是如何转换的,这在编程中经常会用到,尤其是C语言。


其他进制向十进制转换

二进制、八进制和十六进制向十进制转换都是非常容易的,就是“按权相加”。

所谓“权”,也即“位权”。例如,十进制第1位的位权为100=1,第2位的位权为101=10,第3位的位权为102=100;而二进制第1位的位权为20=1,第2位的位权为21=2,第3位的位权为22=4。设数字所采用的进制为N(基数也是N),那么第
i 位的位权为 N(i-1)。

不同进制转换为十进制举例:
二进制:1001 = 1×23 + 0×22 + 0×21 + 1×20 = 8 + 0 + 0 + 1 = 9
二进制:101.1001 = 1×22 + 0×21 + 1×20 + 1×2-1 + 0×2-2 + 0×2-3 + 1×2-4 = 4 + 0 + 1 + 0.5 + 0 + 0 + 0.0625 = 5.5625
八进制:0302 = 3×82 + 0×81 + 2×80 = 192 + 0 + 2 = 194
八进制:0302.46 = 3×82 + 0×81 + 2×80 + 4×8-1 + 6×8-2 = 192 + 0 + 2 + 0.5 + 0.09375= 194.59375
十六进制:0Xea7 = 14×162 + 10×161 + 7×160 = 3751


十进制转换为二进制——辗除法

上节的表格中给出了简单的十进制和二进制的转换关系,要想获得更多的转换关系,可以使用辗除法。辗除法也就是“除模取余”法。除模取余就是将一个几进制的数转化成另一个进制时,
另一个进制的基数就是模,用将要转化的进制数除以模,取它的余数。

下图以十进制的“19”转换为二进制为例进行讲解:



图1:19 转换为二进制

如图所示,以2为除数,一直相除下去,直到商为0,余数则为求得的二进制数。

注意:余数要倒序排列,也就是说,最先求得的余数排在二进制的最后面,最后求得的余数排在二进制的最前面。上面的例子中,最后求得的二进制数为
10011。

虽然其他进制也可以按照辗除法来转换,但是比较麻烦,下面介绍更简单的方法。


二进制和八进制的转换

二进制向八进制的转换是每三位二进制数转换为一位八进制数,运算的顺序是从低位向高位依次进行,高位不足三位用零补充。以二进制“1011101”为例,如下图所示:



图2:二进制转八进制

转换的结果为:1011101 = 0135

八进制向二进制转换的思路是八进制的一位转换为二进制的三位,运算的顺序是从低位向高位依次进行。同样以八进制“0135”为例,如下图所示:



图3:八进制转二进制

转换的结果为:0135 = 1011101


二进制和十六进制的转换

二进制向十六进制转换时,四位转换成十六进制的一位,运算的顺序是从低位向高位依次进行,高位不足四位用零补。以“1110011”转换成十六进制为例,如下图所示:



图4:二进制转十六进制

转换的结果为:1001011101 = 0X25D

十六进制向二进制转换,就是把十六进制的一位转换成二进制的四位,注意运算的顺序是从低位向高位依次进行。同样以十六进制“0X25D”为例,如下图所示:



图5:十六进制转二进制

无论变量声明为有符号数还是无符号数,printf() 函数中只有当以 %u 格式输出时,才会作为无符号数处理;如果声明为 unsigned 却以 d%
输出,那么也是有符号数。
最后需要说明的是:不管是否有符号,%o、%x、%X、%#o、%#x、%#X 都是以无符号形式输出,读者可以亲自测试。


取值范围和数据溢出

short、int、long 占用的字节数不同,所能表示的数值范围也不同。以32位平台为例,下面是它们的取值范围:
数据类型所占字节数取值范围
short2-32768~32767,即 -215~(215-1)
unsigned short20~65535,即 0~(216-1)
int4-2147483648~2147483647,即 -231~(231-1)
unsigned int40~4294967295,即0~(232-1)
long4-2147483648~2147483647,即 -231~(231-1)
unsigned long40~4294967295,即0~(232-1)
当数值过大或过小时,有限的几个字节就不能表示,就会发生溢出。发生溢出时,最高位会被截去。

什么意思呢? 比如 一个4个水桶(作一个整体A)里边的水,向一个水桶B里边倒水,那么最终B里边最终只能存放一个水桶容量的水,其余的都溢出了.

但是反过来就没事.

 






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

C语言字符串
一、字符串基础
注意:字符串一定以\0结尾。
printf(“yang\n”);
其中yang为字符串常量,“yang”=‘y’+‘a’+‘n’+‘g’+‘\0’。字符串由很多的字符组成,通常使用字符数组来存储字符串,如char name[10]=“yang”;也可以以printf(name);的形式输出,即通过数组来访问字符串,但会有警告。因为默认情况下,printf函数只接受字符串常量作为参数(对变量并未写明)。
字符串的三种写法:
Char name[8]=“yang”;//数组占用了8个字节的存储空间,但是只含有5个字符。
Char name[8]={‘y’+‘a’+‘n’+‘g’+‘\o’};
Char name[8]={‘y’+‘a’+‘n’+‘g’+‘0’};
这三种写法在内存中的表现都是一样的。
 


Char name[]={‘y’+‘a’};前面不写个数,不是一个字符串,只能说是一个普通的字符数组。
char name[]=“yang”;
Name[1]=‘o’;把字符串的第二个元素值由a改成o。
 
二、字符串使用注意点
(1)分析代码,了解\0的作用。
Char name[]=“yang”;
Char name2[]={‘o’+‘k’};
Printf(“name2=%s”,name2);
%s:根据右边的参数,打印字符串(遇到\0为止)
上面代码的打印结果为:okyang
下面是内存情况分析:
 


问1:Char name[]=“y\0ng”;则打印结果为什么?(oky)
问2:此时打印name的值,使用%s是多少?Y\0ng还是y?
(2)Strlen函数
Strlen函数计算字符串的长度(字符数)但不包括\0,是字符数不是字数。比如一个汉字占三个字符。
Strlen(“haha”);//长度为4
Strlen(“哈haha”);//长度为7而不是5

char name[]=“it\0cast”;
Strlen(name);值为2,因为strlen从字符串的地址开始计算,直到遇到\0为止。
假设
Char name[]=“itcast”;
Char name2[]={‘o’+‘k’};
Int size=strlen(name);
此时size的值为8。

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

void 类型一般用于 函数返回值 和指针 中,暂时不加以说明.

枚举类型和指针类型对于初学之来说,不易理解,以后再讲.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: