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

    xiaoxiao2026-04-09  5

    现在有一排水桶,一共有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 = 1Byte1024Byte = 1KB1024KB = 1MB1024MB = 1GB1024GB = 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 二进制、八进制、十进制、十六进制的对应关系 十进制 二进制 八进制 十六进制 十进制 二进制 八进制 十六进制000010101012A111111101113B2102212110014C3113313110115D41004414111016E51015515111117F611066161000020107111771710001211181000108181001022129100111919100112313 在C语言中,八进制通常以“0”开头(注意是数字 0,而不是字母 o),例如 0307;十六进制通常以“0x”或“0X”开头(不区分大小写),例如 0xE27 或 0X89F。 前面两节对二进制、八进制和十六进制进行了说明,接下来讲一下不同进制之间的数字是如何转换的,这在编程中经常会用到,尤其是C语言。

    其他进制向十进制转换

    二进制、八进制和十六进制向十进制转换都是非常容易的,就是“按权相加”。 所谓“权”,也即“位权”。例如,十进制第1位的位权为10 0 =1,第2位的位权为10 1 =10,第3位的位权为10 2 =100;而二进制第1位的位权为2 0 =1,第2位的位权为2 1 =2,第3位的位权为2 2 =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×2+ 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 类型一般用于 函数返回值 和指针 中,暂时不加以说明.

    枚举类型和指针类型对于初学之来说,不易理解,以后再讲.

    转载请注明原文地址: https://ju.6miu.com/read-1308661.html
    最新回复(0)