重温C语言(2)之数据

Feb 2, 2020


一 数据类型

数据就是代表某些信息的数字和字符。 按计算机的储存方式可分为两大基本类型:整数类型和浮点数类型。

1 关键字

初始 C90 C99
int signed _Bool
long void _Complex
short   _Imaginary
unsigned    
char    
float    
double    

2 存储单元

首先得记住,计算机内部都是以二进制进行编码的。

  • bit: 位,最小的存储单元,可以储存0或1。位是计算机内存的基本构成块;
  • byte: 字节,是常用的计算机存储单位。对于几乎所有的机器,1字节均为8位。
  • word:字,设计计算机时给定的自然存储单元,对于8位计算机1字长只有8位。后来快速发展,已经从8位、16位、32位、发展到现在的64位。计算机的字长越大,其数据转移越快,允许的内存访问也更多。

3 整数

整数是没有小数部分的数。计算机用二进制数字存储整数。例如数字7的二进制存储是00000111

4 浮点数

有小数点的值就是浮点数。 因为在任何区间内(如,1.0到2.0之间)都存在无穷多个实数,所以计算机的浮点数不能表示区间内所有的值。浮点数通常只是实际值的近似值,比如,7.0可能被储存为浮点值6.99999。

二 基本数据类型

int、long、short、unsigned、char、float、double、signed、_Bool、_Complex和_Imaginary。

1. int

有符号整型,可以是正整数、负整数或0。 一般而言,储存一个int要占用一个机器字长。即16位计算机1个int值占16位(-3276832768),32位计算机用32位存储一个int值,64位计算机用32位存储一个int值。 ISO C规定int的取值范围最小为-3276832767

(1)进制

相对于十进制,我更喜欢八进制和十六进制。8和16都是2的幂次方,而10不是,通俗说八进制和十六进制记数系统在表达与计算机相关的值时很方便。例如16位中的十进制65536用十六进制表示是10000,十六进制的每一位数由4位二进制组成,例如5的二进制是0101,6的二进制是0110,因此十六进制56的位组合是 01010110。

在C语言中,用特定的前缀表示使用哪种进制。0x或0X前缀表示十六进制值,所以十进制数16表示成十六进制是0x10或0X10。与此类似,0前缀表示八进制。

下面代码显示了三种进制:

#include <stdio.h>
int main(){
    int x = 73;
    printf("十进制 = %d,八进制 = %o,十六进制 = %x\n", x, x, x);
    printf("十进制 = %d,八进制带前缀 = %#o,十六进制带前缀 = %#x", x, x, x);
    return 0;
}

c5545a5fe35d8a8d1e559a141c3dff40

(2)其他整数类型

  • short:有符号类型,占用的存储空间可能比int类型少,常用于较小数值的场合以节省空间;
  • long:有符号类型,占用的存储空间可能比int多,适用于较大数值的场合;
  • long long:有符号类型,占用的存储空间可能比long多,适用于更大数值的场合,该类型至少占64位;
  • unsigned int:间写 unsigned int, 无符号整型,只适用于非负值,用于表示正负号的位现在用于表示另一个二进制位,所以无符号整型可以表示更大的数,16位unsignedint允许的取值范围是0~65535。

根据机型的不同,各种整数类型占用的空间也不同: 最早 short 16位,int 16位,long 32 位; 后来 short 16位, int 32位,long 32位; 现在使用了64位的处理器 short 16位, int 16或32位(根据计算机自然存储单元定),long 32位, long long 64位。

溢出:表示值超出了该类型的代表范围。比如当类型的值达到最大值时,二进制存储的所有位全是1即1111…111, 在加 1 的话就会造成溢出,所有为进位变成了0,最高位的1超出了类型的二进制位数就会被抛弃,所以最大值加1的结果就是变成了最小值。

    unsigned short us = -1;
    printf("%d\n", us); // 65535

2. char

用于存储字符。计算机使用特定的整数来存储特定的字符,所以 char 类型实际存储的是整数,在ASCII码中,65代表A。

商用的统一码(Unicode)创建了一个能表示世界范围内多种字符集的系统,目前包含的字符已超过110000个。

C 语言定义char类型占用的位数是一个字节。

    printf("%c\n", 65); // A
    printf("%c\n", 'A');  // A
转义序列 含义
\a 警报
\b 退格
\f 换页
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符

3. _Bool

布尔值即true和false,c语言用1表示true,0表示false。技术层面是只占1位存储空间的整数类型。

4. 可移植类型:stdint.h和inttypes.h

C99新增了两个头文件stdint.h和inttypes.h,以确保C语言的类型在各系统中的功能相同。 精确宽度整数类型(exactwidthintegertype):如int32_t表示整数类型的宽度正好是32位。

5. float, double, long double

    printf("int 类型有 %d 字节\n", sizeof(int));
    printf("char 类型有 %d 字节\n", sizeof(char));
    printf("long 类型有 %d 字节\n", sizeof(long));
    printf("long long 类型有 %d 字节\n", sizeof(long long));
    printf("double 类型有 %d 字节\n", sizeof(double));
    printf("long double 类型有 %d 字节\n", sizeof(long double));
    printf("_Bool 类型有 %d 字节\n", sizeof(_Bool));
    printf("float 类型有 %d 字节\n", sizeof(float));

int 类型有 4 字节
char 类型有 1 字节
long 类型有 8 字节
long long 类型有 8 字节
double 类型有 8 字节
long double 类型有 16 字节
_Bool 类型有 1 字节
float 类型有 4 字节

三 算法前瞻

/**
 * 有一根27厘米的细木杆,
 * 在第3厘米、7厘米、11厘米、17厘米、23厘米这五个位置上各有一只蚂蚁。
 * 木杆很细,不能同时通过两只蚂蚁。开始时,蚂蚁的头朝左还是朝右是任意的,
 * 它们只会朝前走或调头,但不会后退。当任意两只蚂蚁碰头时,两只蚂蚁会同时调头朝反方向走。
 * 假设蚂蚁们每秒钟可以走一厘米的距离。编写程序,求所有蚂蚁都离开木杆的最短时间和最长时间。
 */
void antCode() {
    int antSize = 5;
    double nums[] = {3, 7, 11, 17, 23};
    printf("sizeof(nums)=%d\n", antSize);
    double lineSize = 27;

    double max = 0;
    double min = nums[0];
    for (int i = 0; i < antSize; ++i) {
        double left = nums[i];
        double right = lineSize - nums[i];
        printf("%d: left=%f, right=%f\n", i, left, right);
        max = fmax(max, fmax(left, right));
        min = fmax(min, fmin(left, right));
    }

    printf("max=%f; min = %f\n\n\n\n\n", max, min);
    
}
/**
 * 找出符合如下条件的 9位数:
 * 这个数包括了 1 ~ 9这 9个数字。这个 9位数的前 n位都能被 n整除,若这个数表示为 abcdefghi,则 ab可以被 2整除, abc可以被 3整除…… abcdefghi可以被 9整除。
 */
void nineNumber(){

    for (int i = 1; i < 10; ++i) {
        nineNumberLogic(i, 2);
    }

}

void nineNumberLogic(int a, int n){
    if (n > 9) {
        printf("%d\n", a);
        return;
    }
    int first = a * 10;
    // 这里可以判断奇偶数来进一步提高效率
    for (int i = 1; i < 10; ++i) {
        int b = first + i;
        if (b % n == 0) {
            nineNumberLogic(b, n + 1);
        }
    }
}