Juconcurrent 学而不思则罔,思而不学则殆。

C语言学习杂记(2)—C的数据

2016-02-23

计算机的计算和存储都是数据。在C语言里,数据同样是基础,学好数据的知识是必须的。 先看一个最简单的例子

#include <stdio.h>

int main(void)
{
    int weight;
    float cost;
    float value;

    printf("please input your weight.\n");
    scanf("%d", &weight);
    printf("please input your single cost.\n");
    scanf("%f", &cost);
    value = weight * cost;
    printf("your total cost is %.2f\n", value);

    return 1;
}

效果图

C中的基本数据类型如下,而我们可以把他们分成两类(整数类型、浮点数类型)。 K&R关键字:int、long、short、unsigned、char、float、double C90新增:signed、void C99新增:_Bool、_Complex、_Imaginary 整数,就是不带小数点的数。浮点数,整数之间的那些数。

一、int类型

C之所以提供多种整数类型,原因在于为程序员针对不同用途场景提供多种选择。C的整数类型间的区别在于其提供数值的范围和是否可以取负。int是基本类型,我们可以根据任务和机器选择其他类型。

1、声明int类型。为变量赋值,可以在声明的时候赋值,还可以通过scanf的方式。
int param;
int cows, dogs;
int weight, cost = 3; // 尽量避免这样的声明,因为从字面上感觉weight也是被赋值为3了。实际上,weight仍然是未赋值状态。
scanf("%d", &cows);
2、十进制、八进制、二进制和十六进制

计算机内部数据表示使用的是二进制,它带来的好处是简单,它只有两个数值0和1。 十进制是我们日常的表示方法,我们人有十个手指头,数值为0-9。 虽然二进制很简单,但是书写起来却是很麻烦的一件事,所以我们可以把3个二进制位表示为八进制;把4个二进制位表示为十六进制。同二进制和十进制一样,八进制数值为0-7,十六进制数值为0-9、A-F。 声明进制如下:

十进制 八进制 十六进制
int a = 13 int a = 015 int a = 0xD

打印如下:

十进制 八进制 十六进制
%d %o %x
%d %#o %#x
3、其他整数类型(short、long、unsigned、signed修饰)

[a->signed|unsigned] | [b->short|long|long long] | [c->int] param 当a或者b存在时,可以省略c;如果类型本身为有符号数,可省略signed。 例如:

int a;
long int estate;
long johns;
short int eyes;
short count;
unsigned long etc;
signed int gg;
signed cool;
long long ago;

在声明long和无符号常量时,我们可以使用后缀u代表无符号,使用l或L代表长整形。比如:3uLL、3ULL、3ull、3ul、3Ull。但是我们一般使用L,而非l,因为l和大写的i很像。

要打印这些类型时,我们可以考虑一些规则。signed使用%d,unsigned使用%u,long使用%l(小写的L),short使用%h,他们可以和进制结合起来(再复习一下,o表示八进制,x表示十六进制,#表示显示进制符号——0/0x)。 例如:

#include <stdio.h>

int main(void)
{
    unsigned int un = 30000000;
    short end = 200;
    long big = 65537;
    long long verybig = 12345678908642;
    printf("un = %u and not %d\n", un, un);
    printf("big = %ld and not %hd\n", big, big);
    printf("verybig = %lld and not %ld\n", verybig, verybig);
    
    return 1;
}

二、char类型

char类型使用一个字节来表示,一个字节有8个二进制位,所以最多有256个可能数,标准ASCII编码范围从0~127。而一些系统对其进行了扩展,但也是限定在8位之内。

1、声明
char response;
char iter, latan;
2、常量及初始化

char类型理论上仍然是一个数字,所以我们可以使用范围内的int来表示。另外,我们也可以使用字符用单引号引起来表示。例如:

char boild = 'A';
char let = 65;
char etc = '\n';
3、转义字符

正如\n所表示,有时我们需要转义字符,比如:回车、换行、跳格、制表符等。转义字符的声明是使用反斜杠+特殊说明来表示。这儿的特殊说明可以简单列举如下:

字符 意义
\n 换行
\b 退格
\0oo 八进制值(o表示一个八进制数字)
\xhh 十六进制值(hh表示一个十六进制数字)

上述表格中,我们尤其强调一下八进制值和十六进制值。我们为什么要这样表示,而不直接使用0oo和0xhh表示呢。有两个原因,一个是前者能很直观地表述程序员的意图(是一个字符,而非数字),另一个原因是前者可以方便地嵌入到字符串中,例如:”\007”。

三、_Bool

这个类型是c99才引入的,它只有两个值:0和1,1代表true,0代表false。

四、inttype.h,引入可移植类型

上述整数类型已经足够多了,但是它却不能很明确地表示int是4个字节,long long是8个字节,short是2个字节。为了解决这些问题,c99引入可选名字集合,以确定描述信息,前提是引用头文件inttype.h。例如:int16_t表示一个16位有符号整数类型,uint32_t表示一个32位无符号整数类型。 除了限制字长和有无符号,它还包含其他特性。速度特性,如:int_fast8_t。最小长度特性,如:int_least8_t。最大最小峰值,如:intmax_t和uintmax_t分别表示最大有符号整数和最大无符号整数。为打印提供的特定宏,如PRId16打印16位有符号值等。

五、浮点类型

c语言中,浮点类型包括:float、double、long double。而为了表示很大和很小的数,科学家研究出了科学计数法,例如:123.00使用1.23e2或1.23E2表示。e或E表示10的幂。如果系统支持c99的十六进制格式浮点数,则可以使用a或A代替e或E 浮点数的表示,一般使用以下格式表示: [+|-] | [小数点前] | [小数点.] | [小数点后] | [e|E + 整数表示10的幂] float和double的打印使用%f,long double使用%Lf,科学计数法使用%e。例如%e、%f、%Lf、%Le、%La

#include <stdio.h>

int main(void)
{
    float a = 33.234;
    printf("%%a is %a %%e is %e\n", a, a);

    return 1;
}

输出如下:

zhangfb@zhangfb-pc:~/workspace/formal/c/first$ gcc two.c zhangfb@zhangfb-pc:~/workspace/formal/c/first$ ./a.out %a is 0x1.09df3cp+5 %e is 3.323400e+01

浮点数和整数都存在上溢和下溢的问题,如:两个很大的数相加,超出实际能表示的最大数。浮点数和整数又不太一样,浮点数存在精度的问题,两个浮点数相乘,可能出现实际的值和数学计算出的值不一致的情况,例如3.33*2.333333,使用数学方法计算得出7.76999889,但是float在某些系统上最大的精度为6,也就是说只能表示小数点后6位,这时,最后两位89就会丢失。

六、复数和虚数

这两种类型,用得最多的是科学和工程领域,所以暂时不做说明。

总结

这儿,我以条例的方式,列出一些日常容易犯的错误和一些好的建议。

1、使用和类型相匹配的声明
int a = 3; // 推荐写法
int b = 3.3; // 应避免写法
int cost = 33.98; // 应避免写法,C会简单地舍弃小数点及其后面部分,而非四舍五入
float alpha = 32.3323499; // 应避免写法,float精度为6,所以会舍弃掉最后一位
2、类型前缀

一些有经验的程序员会有自己的变量命名规范,例如int类型的变量名为i_开头,unsigned short类型的变量名以us_开头。这种方式无分好坏,因人而异,比如在Java语言中,推荐变量名中不加入类型前缀。而C语言是推荐这种命名方式。

3、输入输出函数的变量个数确定

调用scanf和printf函数时,因为参数个数不固定,编译器不会检查个数和格式是否匹配,如果少写或多写了一些参数,会出现一些让人意外的情况。例如:

int a = 3;
float b = 33.2343;
int c, d;

printf("a is %d and b is %.2f\n", a);
printf("a is %d\n", a, b);
printf("please input c.\n");
scanf("%d", &c, &d);
printf("c is %d\n", c);
4、类型长度规范

整数类型:short <= unsigned short <= int <= unsigned int <= long <= unsigned long <= long long <= unsigned long long 浮点类型:float <= double <= long double


Content