C Primer Plus ---- 学习笔记_第3章 数据和C

  • 关键字int、short、long、unsigned、char、float、double、_Bool、_Complex、_Imaginary;
  • 运算符 ---- sizeof();
  • 函数 ---- scanf_s();
  • 整数类型和浮点数类型的区别;
  • 如何书写整型和浮点型常数,如何声明这些类型的变量;
  • 如何使用printf()和scanf_s()函数读写不同类型的值

3.1 示例程序

/*platinum.c   -- your weight in platinum */
#include <stdio.h>
int main(void){

float weight;   /*你的体重 */
float value;    /* 相等重量的白金价值 */

printf("Are you worth your weight in platinum?\n");
printf("Let's check it out.\n");
printf("Please enter your weight in pounds: ");

/* 获取用户输入 */
scanf_s("%f", &weight);
/* 假设白金的价格是每盎司$1700 */
/* 14.5833用于把英镑常衡盎司转换为金盎司 */
value = 1700.00 * weight * 14.5833;

printf("Your weight in platinum is worth $%.2f.\n", value);
printf("You are easily worth that! If platinum prices drop,\n");
printf("eat more to maintain your value.\n");

return 0;

}

        scanf_s()函数用于读取键盘的输入。%f说明scanf_s()要读取用户从键盘输入的浮点数,&weight告诉scanf_s()把输入的值赋给名为weight的变量。scanf_s()函数使用&符号表明找到weight变量的地址。注意,scanf_s()函数是C11标准中引入的新函数,其作用与老版scanf()函数相似,也可以实现用户输入功能。但是scanf_s()函数比scanf()函数更加安全可靠,scanf_s()多了一个缓冲区大小的参数,比如,在读取字符串时,应该用下面的方式:

char str[100];
scanf_s("%s", str, 100);  //指定要读取的字符数为100

3.2 变量与常量数据

  • 常量 ---- 在整个程序的运行过程中没有变化,如14.5833
  • 变量 ---- 在程序运行期间可能会改变或被赋值,如weight

3.3 数据:数据类型关键字

        如果数据是常量,编译器一般通过用户书写的形式来识别类型(如42是整数,42.100是浮点数),但是对于变量而言,要在声明时指定其类型。C语言的基本类型关键字如下:

  • int 关键字 ---- 表示基本的整数类型。后3个关键字(long、short和unsigned)和C90新增的signed用于提供基本整数类型的变式,例如unsigned short int 和 long long int
  • char 关键字 ---- 指定字母和其他字符(如,#、$、%和 *),char类型也可表示较小的整数
  • floatdoublelong double 表示带小数点的数
  • _Bool类型表示布尔值(true 或 false)
  • _Complex 和 _Imaginary 分别表示复数和虚数

        通过这些关键字创建的类型,按计算机存储方式可分为两大基本类型:整数和浮点数类型

位、字节和字

  • 位 bit ---- 可以存储0或1,计算机内存的基本构成块
  • 字节 byte ---- 通常1字节为8位,可表示0~255的整数或一组字符
  • 字 word ---- 个人计算机字长已增长至64位,字长越大,数据转移越快,允许的内存访问更多

3.3.2 整数

        和数学概念一样,在C语言中,整数是没有小数部分的数,计算机以二进制数字存储整数。例如,整数7以二进制写是111,,因此,在8位字节中存储该数字,需要把前5位都设置为0,后3位设置成1,如图:

3.3.3 浮点数

        浮点数与数学中实数的概念差不多。2.75、3.16E7、7.00 和 2e-8 都是浮点数。注意,在一个值后面加上一个小数点,该值就成为一个浮点值。所以7是整数,7.00是浮点数。

        计算机把浮点数分成小数部分和指数部分来表示,而且分开存储这两部分。下图演示了一个存储浮点数的例子,当然,计算机在内部使用二进制和2的幂进行存储,而不是10的幂。

整数类型和浮点数类型的实际区别

  • 整数没有小数部分,浮点数有小数部分
  • 浮点数可以表示的范围比整数大
  • 对于一些算数运算(如两个很大的数相减),浮点数损失的精度更多
  • 因为在任何区间内都存在无穷个实数,所以计算机的浮点数不能表示区间内所有的值。浮点数通常只是实际值的近似值。例如,7.0可能被存储为浮点值6.99999
  • 过去,浮点运算比整数运算慢,现在许多CPU都包含浮点处理器,缩小了速度上的差距

3.4 C语言基本数据类型

3.4.1 int 类型

        int 类型是有符号整型,即 int 类型的值必须是整数,可以是正整数、负整数或零。int 的取值范围最小为 -32768 ~ 32767。一般而言,系统用一个特殊位的值表示有符号整数的正负号。

  1. 声明int变量                                                                                                                                单独声明每个变量:                                                              int erns;                                    在 int 后面列出多个变量名,变量名之间用 逗号分隔:        int hogs, cows, goats;                  以上声明创建了变量,可通过赋值函数以及初始化给变量提供值。 
  2. 初始化变量         为变量赋一个初始值                                                                                      在C语言中,初始化可以直接再声明中完成,只需在变量名后面加赋值运算符(=)和待赋给变量的值即可,int cows = 32, goats = 14;
  3. int 类型常量        C语言把大多数整型常量视为int类型,但是非常大的整数除外
  4. 打印 int 值                                                                                                                                可以使用printf()函数打印 int 类型的值,%d指明了在一行中打印整数的位置,%d为转换说明,它指定了printf()应使用什么格式来显示一个值。注意,使用printf()函数时,要确保转换说明的数量与待打印的数量相等。
  5. 八进制和十六进制                                                                                                                      通常,C语言都假定整型常量是十进制数。在C语言中,用特定的前缀表示使用哪种进制。0x 或 0X 前缀表示十六进制值,所以十进制16表示成十六进制是0x10 或 0X10。与此类似,0 前缀表示八进制,例如,十进制数16表示成八进制是020
  6. 显示八进制和十六进制                                                                                                               在C程序中,既可以使用也可以显示不同进制的数。不同进制要使用不同的转换说明。以十进制显示数字,使用 %d;以八进制显示数字,使用 %o以十六进制显示数字,使用 %x 。另外,要显示各进制数的前缀 0、0x 和 0X,必须分别使用 %#o、%#x 和 %#X

3.4.2 其他整数类型

        C语言提供3个附属关键字修饰基本整数类型:short、long 和 unsigned。应记住以下几点:

  • short int 类型占用的存储空间可能比 int 类型少,常用于较小数值的场合以节省空间,short 是有符号类型;
  • long int 占用的存储空间可能比 int 多,适用于较大数值的场合,是有符号类型;
  • long long int 占用的存储空间可能比 long 多,适用于更大数值的场合。该类型至少占64位,是有符号类型;
  • unsigned int 只用于非负值的场合。这种类型与有符号类型表示的范围不同。例如,16位unsigned int 允许的取值范围是 0 ~ 65535
  • 在C90标准中,添加了unsigned long int 和 unsigned short int 类型,C99标准又添加了 unsigned long long int
  • 在任何有符号类型前面添加关键字 signed,可强调使用有符号类型的意图。
  1. 声明其他整数类型        unsigned int players;
  2. 使用多种整数类型的原因                                                                                                          个人计算机上最常见的设置是,long long 占64位,long 占32位,short 占16位,int 占16位或32位(依计算机的自然字长而定)。实际使用中,有些类型之间通常有重叠。C标准对基本数据类型只规定了允许的最小大小。                                                                                      int 类型的选择:unsigned 类型的数常用于计数,因为计数不用负数,而且unsigned可表示更大的正数。对于那些 long 占用空间比 int 大的系统,使用 long 类型会减慢运行速度,因此,如非必要,请不要使用 long 类型。另外需要注意一点:如果在 long 类型和 int 类型占用空间相同的机器上编写代码,当确实需要32位的整数时,应使用 long 类型,以便把程序移植到16位机后仍然可以正常工作。类似,如果确实需要64位的整数,应使用 long long 类型。如果在 int 设置为32位的系统中要使用16位的值,应使用 short 类型以节省存储空间。使用short 类型的另一个原因是,计算机中某些组件使用的硬件寄存器是16位。
  3. long 常量和 long long 常量                                                                                                     通常,代码中使用的数字被视为 int 类型。如果值太大,编译器会依次视为 long int 类型、unsigned long 类型、long long 或 unsigned long long 类型。                                                  八进制和十六进制常量被视为 int 类型,如果值太大,编译器会依次使用 unsigned int 类型、long 、unsigned long 、long long 和 unsigned long long 类型。                                              有些情况下,需要编译器以 long 类型存储一个小数字。要把一个较小的常量作为 long 类型对待,可以在值的末尾加上 l(小写的 L)或 L 后缀。因此,在 int 为16位,long 为32位的系统中,会把7作为16位存储,把 7L 作为32位存储,该后缀也可用于八进制和十六进制整数。类似地,可使用 ll 或 LL后缀表示 long long 类型的值,u 或 U 后缀表示 unsigned long long    整数溢出:当达到能表示的最大值时,会重新从起点开始
  4. 打印 short、long、long long 和 unsigned 类型                                                                    打印unsigned int 类型的值,使用 %u 转换说明;打印 long 类型的值,使用 %ld转换说明。在 x 和 o 前面可以使用 l 前缀,%lx 表示以十六进制格式打印 long 类型整数,%lo 表示以八进制格式打印 long 类型整数。注意,虽然C允许使用大写或小写的常量后缀,但是在转换说明中只能用小写。                                                                                                                      C语言有多种printf()格式。对于short类型,可以使用 h 前缀,如 %hd、%ho 。h 和 l 前缀都可以和 u 一起使用,用于表示无符号类型,例如 %lu 表示打印unsigned long类型的值。        在使用printf()函数时,切记检查每个待打印值都有对应的转换说明,还要检查转换说明的类型是否与待打印值的类型相匹配。

3.4.3 使用字符:char类型

        char类型用于储存字符(如,字母或标点符号),但从技术层面看,char类型实际储存的是整数而不是字符。计算机使用数字编码处理字符,即用特定的整数表示特定的字符,最常用的编码是ASCII编码。在ASCII码中,整数65代表大写字母A。标准ASCII码的范围是0~127,只需7位二进制数即可表示。通常,char类型被定义为8位的存储单元

        C语言把1字节定义为char类型占用的位(bit)数,因此无论是16位还是32位系统,都可以使用char类型。

  1. 声明char类型变量              char itable,latan;
  2. 字符常量和初始化              char grade = 'A';                                                                              在C语言中,用单引号括起来的单个字符被称为字符常量,单引号必不可少。实际上,字符是以数值形式储存的,所以也可以使用数字代码值来赋值。但是最好使用字符常量,因为不是所有系统都使用ASCII码。
  3. 非打印字符                                                                                                                                单引号只适用于字符、数字和标点符号,有些ASCII字符打印不出来。例如,一些代表行为的字符(如,退格、换行、终端响铃或蜂鸣)。C语言提供了3种方法表示这些字符。                                                                                                                                                               第1种方法是使用ASCII码,例如,蜂鸣字符的ASCII值是7,     char beep = 7;                                                                                                                                                                       第2种方法是,使用特殊的符号序列表示一些特殊的字符,即转义序列。把转义序列赋给字符变量时,必须用单引号把转义序列括起来,char nerf = '\n';                                                        如果要用八进制ASCII码表示一个字符,可以在编码值前面加一个反斜杠并用单引号括起来。例如,如果编译器不识别警报字符,可以使用ASCII码来代替, beep = '\007';                  可以省略前面的0,'\07' 甚至 '\7' 都可以。即使没有前缀 0 ,编译器在处理这种写法时,仍会解释为八进制。                                                                                                                                                                                                                                                                             从C90开始,C语言提供了第3种选择,用十六进制形式表示字符常量,即反斜杠后面跟一个x 或 X,再加上1~3位十六进制数字。例如,Ctrl + P字符可表示为 '\x10' 或 '\x010' 。                使用ASCII码时,注意数字和数字字符的区别。例如,字符4对应的ASCII码时52,'4' 表示字符4,而不是数值4。                                                                                                                  关于转义序列无论是普通字符还是转义序列,只要是双引号括起来的字符集合,就无需用单引号括起来。如果要在转义序列和ASCII码之间选择,优先选择转义序列。如果要使用ASCII码,要写成 '\032' ,能更清晰表达使用字符编码的意图,还可以嵌入C的字符串中。
  4. 打印字符      注意:printf()函数中的转换说明决定了数据的显示方式,而不是储存方式           %d   打印的是一个整数(一个字符变量实际上被储存为1字节的整数值)                               %c   打印该整数值对应的字符                                                                                                 
  5. 有符号还是无符号      取决于编译器如何实现char类型,可查阅limits.h头文件                      根据C90标准,C语言允许在关键字char 前面使用signed 或 unsigned。这样无论编译器默认char是什么类型,signed char 表示有符号类型,unsigned char 表示无符号类型。这在用char 类型处理小整数时很有用,如果只用char处理字符,char前面无需使用任何修饰符

3.4.4 _Bool 类型

        C99标准添加了_Bool类型,用于表示布尔值,即逻辑值 true 和 false。C语言用值1表示true,值0表示false,所以_Bool类型实际上也是一种整数类型,但原则上仅占用1位存储空间。

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

        C99新增了两个头文件 stdint.h 和 inttypes.h,以确保C语言的类型在各系统中的功能相同。

        C语言为现有类型创建了更多类型名。这些新类型名定义在 stdint.h 头文件中。例如,int32_t表示32位的有符号整数类型。在使用32位 int 的系统中,头文件会吧 int32_t 作为 int 的别名。不同的系统也可以定义相同的类型名。

        C标准提供了一些字符串宏来显示可移植类型。例如,inttype.h 头文件中定义了PRId32字符串宏,代表打印32位有符号值的合适转换说明(如d或l)。

printf("me32 = %d\n", me32);

//参数PRId32被定义在inttypes.h中的“d”替换

printf("me32 = %" PRId32 "\n", me32);

3.4.6 float、double 和 long double

        C语言中的浮点类型有 floatdoublelong double 类型。浮点类型能表示包括小数在内更大范围的数。浮点数的表示类似于科学计数法。该记数系统常用于表示非常大或非常小的数。示例:

        C标准规定,float 类型必须至少能表示6位有效数字,且取值范围至少是10^{-37}\sim 10^{+37}\mathrm{}。前一项规定指 float 类型必须至少精确表示小数点后的6位有效数字。后一项规定用于方便地表示过大或过小的数字。通常,系统储存一个浮点数要占用32位,其中8位用于表示指数的值和符号,剩下的24位用于表示非指数部分及其符号。

        C语言提供的另一种浮点类型是 double(意为双精度)double 类型和 float 类型的最小取值范围相同,但至少必须能表示10位有效数字。一般情况下,double占用64位,一些系统将多出来的32位全部用来表示非指数部分,这不仅增加了有效数字的位数(即提高了精度),还减少了舍入误差。另一些系统把其中的一些位分配给指数部分,以容纳更大的指数,从而增加了可表示数的范围。无论哪种方法,double类型的值至少有13位有效数字,超过了标准的最低位数规定。

        C语言的第3种浮点类型是 long double,以满足比double类型更高的精度要求。不过,C只保证 long double类型至少与double类型的精度相同。

  1. 声明浮点型变量             float planck = 6.63e-34;
  2. 浮点型常量            -1.56E+12         2.87e-3       2E5      19.28                                                  在代码中,可用多种形式书写浮点型常量。浮点型常量的基本形式是:有符号的数字(包括小数点),后面紧跟 e 或 E,最后是一个有符号数表示10的指数。正号可省略可以没有小数点或指数部分但是不能同时省略两者可省略小数部分或整数部分,但不能同时省略两者。                                                                                                                                            不要在浮点型常量中间加空格                                                                                                  默认情况下,编译器假定浮点型常量是double类型的精度在浮点数后面加上 f 或 F 后缀可覆盖默认设置,编译器会将浮点型常量看作 float 类型,如 2.3f。使用 l 或 L 后缀使得数字成为 long double类型。没有后缀的浮点型常量是double类型。                                                    C99标准添加了一种新的浮点型常量格式,用十六进制表示浮点型常量,即在十六进制数前加上十六进制前缀(0x 或 0X),用 p 和 P 分别代替 e 和 E,用2的幂代替10的幂(即,p计数法),如 0xa.1fp10 表示的是(10 + 1/16 + 15/256)\times 1024
  3. 打印浮点值             %f         %e  %E          %a     %A              %Lf    %Le   %La                    %f   ---- 打印十进制记数法的float和double类型浮点数                                                              %e  ---- 打印指数记数法的浮点数                                                                                              如果系统支持十六进制格式的浮点数,可用 a 和 A 分别代替 e 和 E                                         %Lf、%Le 或 %La  ---- 打印 long double 类型                                                                        给那些未在函数原型中显示说明参数类型的函数传递参数时,C编译器会把float类型自动转换成double类型
  4. 浮点值的上溢和下溢                                                                                                                  现在C语言规定,上溢时,会给赋一个表示无穷大的特定值,而且printf()显示该值为 inf  或 infinity(或者具有无穷含义的其他内容)。下溢时会导致损失原末尾有效位上的数字。  C语言把损失了类型全精度的浮点值称为低于正常的值。现在,C库已提供了用于检查计算是否会产生低于正常值的函数。                                                                                                    另一个特殊的浮点值NaN(not a number的缩写)                                                                    浮点数舍入错误

3.4.7 复数和虚数类型

        C语言有3种复数类型:float_Complex、double_Complex和long double_Complex

        C语言的3种虚数类型:float_Imaginary、double_Imaginary和long double_Imaginary

        如果包含complex.h头文件,便可用complex代替_Complex,用imaginary代替_Imaginary,还可以用 I 代替 -1 的平方根。

3.4.8 其他类型

        C语言还有一些从基本类型衍生的其他类型,包括数组、指针、结构和联合。

3.4.9 类型大小

        sizeof 是C语言的内置运算符以字节为单位给出指定类型的大小。C99和C11提供 %zd 转换说明匹配sizeof的返回类型。一些不支持C99和C11的编译器可用 %u  %lu 代替 %zd

3.5 使用数据类型

        编写程序时,应注意合理选择所需的变量及其类型。通常,用 int 或 float 类型表示数字,char 类型表示字符。在使用变量之前必须先声明,并选择有意义的变量名。初始化变量应使用与变量类型匹配的常数类型。

        把一个类型的数值初始化给不同类型的变量时,编译器会把值转换成与变量匹配的类型,这将导致部分数据丢失。

        许多程序员和公司内部都有系统化的命名约定,在变量名中体现其类型。例如,用 i 前缀表示int 类型,us 前缀表示 unsigned short 类型。这样,一眼就能看出来 i_smart 是 int 类型的变量。

3.6 参数和陷阱

        C语言用逗号分隔函数中的参数要确保转换说明的数量、类型与后面参数的数量、类型相匹配。现在,C语言通过函数原型机制检查函数调用时参数的个数和类型是否正确。但是,该机制对printf() 和 scanf_s() 不起作用,因为这两个函数的参数个数是可变的。

3.7 转义序列示例

/* escape.c -- 使用转义序列 */
#include<stdio.h>
int main(void){

    float salary;

    printf("\aEnter your desired monthly salary:");     /* 1 */
    printf(" $_______\b\b\b\b\b\b\b");                 /* 2 */
    scanf_s("%f", &salary);
    printf("\n\t$%.2f a month is $%.2f a year.", salary, salary * 12.0);        /* 3 */
    printf("\rGee!\n");                                /* 4 */

    return 0;
}

        第2条语句中,7个退格字符使的光标左移7个位置,即把光标移至7个下划线字符的前面,紧跟在美元符号后面。通常,退格不会擦除退回所经过的字符。键入字符会替换下划线字符。第4条printf()语句以 \r 开始,这使得光标回到当前行的起始处。然后打印Gee!

        C标准明确规定了何时把缓冲区中的内容发送到屏幕:当缓冲区满、遇到换行字符或需要输入的时候(从缓冲区把数据发送到屏幕或文件被称为刷新缓冲区)。

  • 30
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值