04. C和数据
一、标识符
1.1、什么是标识符
标识符(identifier)是指用来标识某个实体的一个符号,在不同的应用环境下有不同的含义。在计算机编程语言中,标识符是用户编程时使用的名字,用来给变量、常量、函数等命名,以建立起名字与使用之间的关系。标识符通常由字母和数字以及其它字符构成。
在编程语言中,标识符就是程序员自己规定的代表一定含义的单词,比如变量名、常量名、函数名等。
1.2、标识符的命名规则
- 标识符只能由数字、字母(26个英文字母大小写)、下划线(_)组成;
- 标识符不能以数字开头;
- 不可以使用关键字作为标识符,但可以包含关键字;
- 标识符严格区分大小写;
#include <stdio.h>
int main(void)
{
int useId = 1;
int age = 10;
int minNum = 3;
int max_num = 30;
return 0;
}
标识符的命名建议见名知意;
二、常量
2.1、什么是常量
常量 指的是在计算机程序运行时,不会被程序修改的量;在 C语言 中,常量主要分为以下几种类型:
- 字面常量
- 整型常量,可以是十进制、八进制或十六进制的常量。前缀指定基数:0x 或 0X 表示十六进制,0 表示八进制,不带前缀默认表示 十进制。整型常量也可以带一个后缀,后缀是 U 和 L 的组合,U 表示无符号整数,L 表示长整数,后缀可以大写也可以小写,U 和 L 的顺序任意。例如:100,200,-100,0,037,0x5A
- 浮点型常量,由整数部分、小数点、小数部分 和 指数部分 组成,可以使用小数形式或者指数形式来表示浮点型常量。例如:3.14,0.125,-3.14,314159E-5
- 字符型常量,是括在单引号中的单个字符。字符常量可以是一个普通的字符,也可以是一个转义字符。例如:'a','A','\n'
- 字符串常量,是括在双引号中的字符序列。在字符串常量中,我们可以使用 '\' 实现换行。 例如:"hello","a","123"
const
修饰的常变量,本质上是变量,但是不能直接修改,有常量的属性#define
定义的标识符常量- 枚举常量
2.2、字面常量
【1】、整型字面常量
#include <stdio.h>
int main(void)
{
// 整型字面量
int i1 = 100;
int i2 = -100;
int i3 = 037;
int i4 = 0x5A;
printf("%d\n",i1);
printf("%d\n",i2);
printf("%d\n",i3);
printf("%d\n",i4);
return 0;
}
【2】、浮点型字面常量
#include <stdio.h>
int main(void)
{
// 浮点型字面量
double d1 = 3.14;
double d2 = -3.14;
double d3 = 314159E-5;
float f1 = 3.14f;
printf("%lf\n",d1);
printf("%lf\n",d2);
printf("%lf\n",d3);
printf("%f\n",f1);
return 0;
}
【3】、字符型字面常量
#include <stdio.h>
int main(void)
{
// 字符字面量
char c1 = 'a';
char c2 = 'A';
char c3 = '\n';
printf("%c\n",c1);
printf("%c\n",c2);
printf("%c\n",c3);
return 0;
}
【4】、字符串字面常量
#include <stdio.h>
int main(void)
{
// 字符串字面量
char str1[] = "hello";
char str2[] = "a";
char str3[] = "123";
char str4[] = "hello world";
char str5[] = "hello \
world";
printf("%s\n",str1);
printf("%s\n",str2);
printf("%s\n",str3);
printf("%s\n",str4);
printf("%s\n",str5);
return 0;
}
2.3、const修饰的常变量
#include <stdio.h>
int main(void)
{
// 使用const关键字定义常量
const double pi = 3.14;
// 常量赋值之后,不能更改
//pi = 3.1415926;
// 格式化输出,%lf输出双精度浮点型数据,默认保留6位小数
printf("pi = %lf\n",pi);
// .2f,保留两位小数
printf("pi = %.2lf\n",pi);
return 0;
}
2.4、define定义的标识符常量
#include <stdio.h>
// 宏定义常量
#define PI 3.1415926
int main(void)
{
// 标识符常量不能改变
// PI = 3.14;
// 格式化输出,%lf输出双精度浮点型数据,默认保留6位小数
printf("PI = %lf\n",PI);
// .2f,保留两位小数
printf("PI = %.2lf\n",PI);
return 0;
}
2.5、枚举常量
#include <stdio.h>
/* 枚举常量 */
enum Color
{
RED,
GREEN,
BLUE
};
int main(void)
{
enum Color color = BLUE;
return 0;
}
2.6、const和define定义常量的区别
- const 定义的常量带类型,define 不带类型;
- const 是在编译、运行的时候起作用,而 define 是在编译的预处理阶段起作用的;
- define 只是简单的替换,没有类型检查;
- const 常量可以进行调试的,而 define 是不能进行调试的,主要是因为在预编译阶段 define 定义的常量就已经替换掉了,调试的时候没有了;
- const 不能重定义,不可以定义两个一样的,而 define 通过 undef 可以取消某个符号的定义,在重新定义;
- define 可以配合 #indef、#ifndef、#endif 来使用,可以让代码更加灵活;
#include <stdio.h>
#define A 1
#define B A+3
#define C A/B*3
int main(void)
{
// C其实是A/A+3*3
printf("%d\n",C);
return 0;
}
三、变量
3.1、变量的概念
变量就是在程序的执行过程中,其值可能发生改变的量(数据);变量是内存中的一个存储区域(不同的数据类型,占用的空间大小也不一样),该区域的数据可以在同一类型范围内不断的改变,变量是程序中最基本的存储单元,包含 变量类型、变量名 和 存储的值。
3.2、变量的作用
变量的作用就是在内存中保存数据;我们可以使用变量名来访问这块区域的数据;
3.3、变量的定义
变量的定义:
[存储类型] 数据类型 变量名;
int a;
- 变量的 存储类型 可以是 auto、register、static 和 extern;
- auto 说明变量只能再某个程序范围内使用,通常再函数体内或函数中的复合语句里。(默认是随机值)。在函数体的某段程序内说明 auto 存储类型的变量可以省略关键字 auto。
- register 称为寄存器型,register 变量是想将变量放入 CPU 的寄存器中,这样可以加快程序的运行速度。如果申请不到就使用一般内存,同 auto。
- static 变量称为静态存储类型的变量,既可以在函数体内,也可在函数体外声明。(默认是 0)。
- extern 称为外部参照引用型,使用 extern 说明的变量可以被其它文件中的函数所引用。
- 变量的 数据类型 可以是基本数据类型,也可以是自定义的数据类型
register 变量必须是能被 CPU 所接受的类型。这通常意味着 register 变量必须是一个单个的值,并且长度应该小于或等于整型的长度。
我们不能使用 & 来获取 register 变量的地址;
3.4、变量的赋值
变量的赋值:
变量名 = 变量值;
a = 10;
变量可以在声明的同时赋值:
数据类型 变量名 = 变量值;
int a = 10;
- 数据类型:为空间中存储的数据,加入类型(限制)
- 变量名:为空间起的名字
- 数据值:存在空间里面的数值
#include <stdio.h>
int main(void)
{
// 定义变量
// 数据类型 变量名 = 数据值;
int a = 10,b = 20;
// 格式化输出,%d输出整型数据
printf("a = %d,b = %d\n",a,b);
return 0;
}
在 C 语言中每个变量必须 先声明,再初始化,后使用;
在同一个作用域中,变量名不能重复声明,但变量可以重新赋值;
一行上可以同时声明多个变量,使用 “,” 隔开;
3.5、变量的作用域和生命周期
所谓的变量的作用域就是变量的有效范围;变量的作用域为其定义所在的一对{}内,即出了大括号就不认识了;
局部变量的作用域
:是变量所在的局部范围;全局变量的作用域
:是整个工程;
变量的生命周期指的是变量的创建到变量销毁之间的一个时间段。
局部变量的生命周期
:进入局部范围生命开始,出局部范围生命结束;全局变量的生命周期
:整个程序的生命周期;
3.6、变量的分类
3.6.1、按数据类型分类
3.6.2、按变量定义位置分类
在一个函数内部定义的变量,只在本函数范围内有效。在复合语句内定义的变量,只在本复合语句范围内有效;
函数的形参也属于局部变量,作用范围仅限于函数内部的所有语句块;
如果一个变量在所有函数外部定义,那么这个变量就是全局变量。全局变量是可以在程序中的任何位置进行访问的变量;
当局部变量和全局变量名字冲突的情况下,局部优先。
四、数据类型
C语言的数据类型分为 基本数据类型、构造数据类型、指针类型 和 空类型。
4.1、基本数据类型
C 通过识别一些基本的数据类型来区分和使用这些不同的数据类型。K&C 给出了 7 个与类型相关的关键字。C90 标准添加了 2 个关键字,C99 标准又添加了 3 个关键字。
最初 K&C 给出的关键字 | C90标准 添加的关键字 | C99标准 添加的关键字 |
---|---|---|
int | signed | _Bool |
long | void | _Complex |
short | _Imaginary | |
unsigned | ||
char | ||
float | ||
double |
在 C 语言中,用 int 关键字来表示 基本的整数类型。后 3 个关键字(long、short 和 unsigned)和 C90 新增的 signed 用于提供基本整数类型的变式,例如 unsigned short int 和 long long int。char 关键字用于指定 字母 和 其它字符(如,#、$、%等)。另外,char 类型也可以表示较小的整数。float、double 和 long double 表示 带小数的数。 _Bool 类型表示布尔值(true 或 false),_Complex 和 _Imaginary 分别表示 复数 和 虚数。
4.1.1、整型类型
整形用于表示没有小数部分的数值,允许是负数。计算机以二进制数字存储整数。C 语言中提供了以下几个类型:short、int、long、long long;C 语言的整型常量默认是 int 型,如果要显示地声明 long 型常量需后加 'l' 或 'L' ,声明 long long 型常量需后加 'll' 或 'LL'。
数据类型 | 占用空间 |
---|---|
[signed] short [int](有符号短整型) | 2 字节,取值范围:-32768~32767 |
unsigned short [int](无符号短整型) | 2 字节,取值范围:0~65535 |
[signed] int(有符号整型) | 通常 4 字节,取值范围:-2147483648~-2147483647 |
unsigned int(无符号整型) | 通常 4 字节,取值范围:0~4294967295 |
[signed] long [int](长整型) | 4 字节(32位)或 8 字节(64位) |
unsigned long [int](无符号长整型) | 4 字节(32位)或 8 字节(64位) |
[signed] long long [int](长长整型) | 8 字节 |
unsigned long long [int](无符号长长整型) | 8 字节 |
可以使用 printf() 函数打印 int 类型的值。%d 指明了在一行中打印整数的位置。%d 称为 转换说明,它指定了 printf() 应使用什么格式显示一个值。格式说明字符串中的每一个 %d 都与待打印变量列表中相应的 int 值匹配,这个值可以是 int 类型的变量、int 类型的常量或其它任何值位 int 类型的表达式。
打印 unsigned int 类型的值,使用 %u 转换说明,打印 long 类型的值,试着用 %ld 转换说明,打印 short 类型的值,使用 %hd 抓转换说明。h 和 l 前缀都可以和 u 一起使用,用于表示无符号类型。
#include <stdio.h>
int main(void)
{
short int s = 10; // int可以省略
int i = 10; // int可以省略
long int l = 10; // int可以省略
long long int ll = 10; // int可以省略
signed int a = -10; // 定义一个有符号整数,signed可以省略
unsigned int b = 10; // 定义一个无符号整数
printf("%hd\n",s); // 输出短整型数据
printf("%d\n",i); // 输出一个整型数据
printf("%ld\n",l); // 输出一个长整型数据
printf("%lld\n",ll); // 输出一个长长整型的数据
printf("%d\n",a); // 输出一个有符号的10进制整型
printf("%u\n",b); // 输出一个10进制的无符号数
return 0;
}
我们可以使用 sizeof 关键字来计算数据类型在内存中占用的字节(byte)大小,它的语法格式如下:
sizeof(数据类型)
或
sizeof(变量名)
#include <stdio.h>
int main(void)
{
// sizeof计算数据类型在内存中占用的字节大小
// 语法格式:sizeof(数据类型) 或 sizeof(变量名)
// %zu 输出一个无符号整型数据
printf("短整型:%zu\n",sizeof(short));
printf("整型:%u\n",sizeof(int));
printf("长整型:%zu\n",sizeof(long));
printf("长长整型:%zu\n",sizeof(long long));
return 0;
}
整型的数据在内存中占的字节数与所选择的操作系统有关。虽然 C 语言标准中没有明确规定整型数据的长度,但 long 类型整数的长度不能短于 int 类型,short 类型整数的长度不能长于 int 类型,即 short <= int <= long < long long
。
通常,int 被设置为目标计算机而言最为 “自然” 的长度。自然长度指的是计算机处理起来效率最高的长度。如果没有非常有说服力的理由来选择其它类型,则应该使用 int 类型。如果变量的值不可能为负,则可以使用无符号类型,这样变量可以表示更大的数。如果知道变量可能表示的整数值大于 16 位整数的最大可能值,则推荐使用 long 类型。如果要存储的值超过 20 亿,推荐使用 long long 类型。由于 short 比 int 小,使用 short 可以节省内存。通常仅当有大型整型数组是,才有必要使用 short。
当一个小的数据类型赋值给一个大的数据类型,不会出错,因为编译器会自动转换。但当一个大的数据类型赋值给一个小的数据类型,那么就可能丢失高位。
4.1.2、浮点类型
浮点类型用于表示小数部分的数值。计算机把浮点数分成小数部分和指数部分来表示,而且分开存储这两部分。计算机在内部使用二进制和 2 的幂进行储存。C 语言中浮点类型常量默认是 double 类型,也可以在浮点数值后面添加后缀 'd' 或 'D' ;声明 float 类型的常量,需后加 'f' 或 'F'。声明 long double 类型的常量,需后加 'l' 或 'L'。double 型变量所表示的浮点数比 float 型变量更加精确。
因为在任何区间内都存在无穷多个实数,所以计算机的浮点数不能表示区间内的所有值。因此,浮点数通常只是实际值的近似值。浮点类型不能准确的表达一个浮点数,可能会有舍入误差。
浮点型常量的基本形式是:有符号的数字(包括小数点),后面紧跟 e 或 E,最后一个有符号数表示 10 的指数,如:-1.56E+12 和 2.87e-3。正号可以省略。可以没有小数点(如,2E5)或指数部分(19.28),但是不能同时省略两者。可以省略小数部分(如,3.E16)或整数部分(如,.45E-6),但是不能同时省略两者。
C99 标准提出了一种新的浮点型常量格式,即用十六进制表示浮点型常量,在十六进制数前面加上十六进制前缀(0x 或 0X),用 P 和 P 分别代替 e 和 E,用 2 的幂代替 10 的幂(p表示法),如 0xa.1fp10
数据类型 | 占用空间 |
---|---|
float(单精度类型) | 4 个字节,取值范围:1.2E-38 到 3.4E+38,6 位有效位 |
double(双精度类型) | 8 个字节,取值范围:2.3E-308 到 1.7E+308,15 位有效位 |
long double(长双精度类型) | 16 字节,取值范围:3.4E-4932 到 1.1E+4932,19 位有效位 |
printf() 函数使用 %f 转换说明 打印十进制计数法的 float double 类型浮点数,用 %e 打印指数计数法的浮点数。如果系统支持十六进制格式的浮点数,可用 a 和 A 分别代替 e 和 E。打印 long double 类型要使用 %Lf、%Le 或 %La 转换说明。
#include <stdio.h>
int main(void)
{
float f = 3.14f;
double d = 3.14;
long double ld = 3.14L;
printf("%f\n",f);
printf("%lf\n",d);
printf("%lf\n",ld);
printf("float:%zu\n",sizeof(float));
printf("double:%zu\n",sizeof(double));
printf("long double:%zu\n",sizeof(ld));
return 0;
}
C 语言规定,float 类型必须至少能表示 6 位有效数字,且取值范围最少是 1.0e-37 ~ 1.0e+37,float 表示的数值的范围比 long 还大。double 类型和 float 类型的最小取值范围相同,但至少必须能表示 10 位有效数字。一般情况下,double 占用 64 位而不是 32 位。C 只保证 long double 类型至少与 double 类型的精度相同;
浮点类型只能使用 long 说明符,其它说明符(short、signed、unsigned)都是不可用的;
4.1.3、字符类型
字符型变量用于存储一个单一字符,在 C 语言中用 char 表示,其中每个字符变量都会占用 1 个字节。char 类型的字面量值要用一对单引号(' ')括起来,内部只能写一个字符。
字符型变量实际上并不是把该字符本身放到变量的存储单元中去,而是将 该字符对应的 ASCII 编码放到变量的存储单元中。char 的本质就是一个 1 字节大小的整型,取值范围为:-128 ~ 127;我们可以直接给 char 类型的变量赋值一个整数,在输出时,可以按照 ASCII 码输出。char 类型的变量还可以进行运算,相当于一个整数。
数据类型 | 占用空间 |
---|---|
signed char | 1 字节,取值范围:-128 ~ 127 |
unsigned char | 1 字节,取值范围:0 ~ 255 |
printf() 函数用 %c 指明待打印的字符。如果用 %d 转换说明 打印 char 类型的变量,打印的是一个整数。而 %c 转化说明 告诉 printf() 打印该整数值对应的字符。
#include <stdio.h>
int main(void)
{
// 定义字符变量
char ch = 'a';
unsigned char uch = 97;
// 格式化输出,%c输出字符型数据
printf("字符:%c\n",ch);
// 打印字母对应的ASCII码
printf("ANSCII:%d\n",ch);
printf("%c\n",uch);
printf("%d\n",uch);
printf("字符型:%zu\n",sizeof(ch));
return 0;
}
在 C 语言中,有一些特定的字符,当它们前面有反斜杠时,它们就具有特殊的含义,这种字符称为 转义字符。
转义字符 | 含义 | ASCII码值(十进制) |
---|---|---|
\a | 警报 | 007 |
\b | 退格,将当前位置移到前一列 | 008 |
\f | 换页,当当前位置移到下页开头 | 012 |
\n | 换行,将当前位置移到下一行开头 | 010 |
\r | 回车,将当前位置移到本行开头 | 013 |
\t | 水平制表符,跳到下一个 tab 位置 | 009 |
\v | 垂直制表符 | 011 |
\\ | 代表一个反斜线字符,\ | 092 |
\' | 代表一个单引号字符,' | 039 |
\" | 代表一个双引号字符," | 034 |
\? | 代表一个问号,? | 063 |
\0 | 数字 0 | 000 |
\ddd | ddd 表示 1~3 个八进制的数字 | 3位 8进制 |
\xdd | dd 表示 2 个十六进制数字 | 3位 16进制 |
#include <stdio.h>
int main(void)
{
printf("hello world!\n");
printf("\thello\n");
printf("鲁迅说:\"这句话我从未说过\"\n");
printf("子曰:\'学而时习之,不亦说乎!\'\n");
printf("御坂美琴 夏娜\r木之本樱\n");
printf("\\\n");
printf("%%\n");
return 0;
}
signed 关键字一般用于 char 类型,因为其它基本整数类型在默认情况下都是有符号数。至于 char 是否是 signed 则因编译器而异。所以,char 可能等同于 signed char,也可能等同于 unsigned char;
4.1.4、布尔类型
C99 标准添加了 _Bool
类型,用于表示 布尔值,即逻辑值 true 和 false。因为 C 语言用值 1 表示 true,值 0 表示 false,所以 _Bool 类型实际上也是一种整数类型。但原则上它仅占 1 位存储空间。_Bool 类型的变量只能存储 1(真)或 0(假)。如果把其它非零数值赋值给 _Bool 类型的变量,该变量会被置为 1。
C99 提供了 stdbool.h
头文件,该头文件让 bool
成为 _Bool 的别名,而且还把 true
或 false
分别定义为 1 或 0 的符号常量。
#include <stdio.h>
#include <stdbool.h>
int main(void)
{
_Bool a = true;
bool b = false;
if(a)
printf("a is true\n");
else
printf("a is false\n");
if(b)
printf("b is true\n");
else
printf("b is false\n");
return 0;
}
4.1.5、复数和虚数类型
C99 标准支持 复数类型 和 虚数类型。C 语言中有 3 中 复数类型:float_Complex
、double_Complex
和 long double_Complex
。例如,float_Complex 类型的变量应包含两个 float 类型的值,分别表示复数的实部和虚部。C 语言的 3 中 虚数类型是 float_Imaginary、double_Imaginary 和 long double_Imaginary。
如果包含 complex.h 头文件,便可以 complex 代替 _Complex,用 imaginary 代替 _Imaginary,还可以用 I 代替 -1 的平方根。
4.2、基本数据类型转换
4.2.1、隐式类型转换
①、初始化和赋值进行的转换
C 语言允许将一种类型的值赋给另一种类型的变量。这样做时,值将被转换为接收变量的类型。此时,将一个值赋给取值范围更大的类型通常不会导致什么问题,只是占用更多的字节而已。然后,将一个大的值赋值给取值范围小的类型将对导致降低精度。
潜在的数值转换问题:
转换 | 潜在的问题 |
---|---|
将较大的浮点类型转换为较小的浮点类型 | 精度(有效位)降低,值可能超出目标类型的取值范围,在这种情况下,结果将是不确定的 |
将浮点类型转换为整型 | 小数部分丢失,原来的值可能超出目标类型的取值范围,在这种情况下,结果将是不确定的 |
将较大的整型转换为较小的整型 | 原来的值可能超出目标类型的取值范围,通常只复制右边的字节 ①、C语言 中,基本的转换规则如下: |
②、表达式中的转换
当同一个表达式中包含两种不同的算术类型时,C 语言将执行两种自动转换:首先,一些类型在出现时便会自动转换;其次,有些类型在于其它类型同时出现在表达式中时将被转换。
在计算表达式时,C 语言将 bool、char、unsigned char、signed char 和 short 值转换为 int。具体来说,true 被转换为 1,false 被转换为 0。这些转换被称为 整型提升(integral pormotion)。如果 short 比 int 短,则 unsigned short 被转换为 int。如果两种类型的长度相同,则 unsigned short 类型将被转换为 unsigned int。wchar_t 被提升为下列类型中第一个宽度足够存储 wchar_t 取值范围的类型:int、unsigned int、long 或 unsigned long。
当运算涉及两种类型时,较小的类型将被转换为较大的类型。
- 如果有一个操作数的类型时 long double,则将另一个操作数转换为 long double。
- 否则,如果有一个操作数的类型是 double,则将另一个操作数转换为 double。
- 否则,如果有一个操作数的类型是 float,则将另一个操作数转换为 float。
- 否则,说明操作数都是整型,因此执行整型提升。
- 在这种情况下,如果两个操作数都是有符号或无符号的,且其中一个操作数的级别比另一个低,则转换为级别高的类型。
- 如果一个操作数为有符号的,另一个操作数为无符号的,且无符号操作数的级别比有符号操作数高,则将有符号操作数转换为无符号操作数所属的类型。
- 否则,如果有符号类型则可以表示无符号类型的所有可能取值,则将无符号操作数转换为有符号操作数所属的类型。
- 否则,将两个操作数都转换为有符号类型的无符号版本。
类型的级别从高至低依次是
long double、double、float、unsigned long long、long long、unsigned long、long、unsigned int、int
。之所以 short 和 char 没有列出,是因为它们已经被升级到 int 或 unsigned int 。
#include <stdio.h>
int main(void)
{
char ch;
int i;
float f1;
f1 = i = ch = 'C';
printf("ch = %c, i = %d, f1 = %2.2f\n", ch, i, f1);
ch = ch + 1;
i = f1 + 2 * ch;
f1 = 2.0 * ch + i;
printf("ch = %c, i = %d, f1 = %2.2f\n", ch, i, f1);
ch = 1107;
printf("Now ch = %c\n", ch);
ch = 80.89;
printf("Now ch = %c\n", ch);
return 0;
}
- 第 9 行和 第 10 行:字符 'C' 被作为 1 字节的 ASCII 码值储存在 ch 中。整数变量 i 接受由 'C' 转换的整数,即按 4 字节储存 67。最后,f1 接受由 67 转换的浮点数 67.00;
- 第 12 行和第 15 行:字符变量 'C' 被转换成整数 67,然后加 1。计算结果是 4 字节整数 68,被截断成 1 字节储存在 ch 中。根据 %c 转换说明打印时,68 被解释成 'D' 的 ASCII 码。
- 第 13 行和第 15 行:ch 的值被转换为 4 字节的整数(68),然后 2 乘以 ch。为了和 f1 相加,乘积整数(136)被转换为浮点数。计算结果(203.00f)被转换成 int 类型,并储存在 i 中。
- 第 14 行和第 15 行:ch 的值('D',或 68)被转换为浮点数,然后 2 乘以 ch。为了做加法,i 的值(203)被转换为浮点类型。计算结果(339.00)被储存在 f1 中。
- 第 17 行和第 18 行:演示了类型降级的示例。把 ch 设置为一个超过其范围的值,忽略额外的位后,最终 ch 的值时字符 S 的 ASCII 码。或者,更确切地说,ch 的值是 1107 % 265,即 83。
- 第 20 行和第 21 行:演示了另一个类型降级的示例。把 ch 设置为一个浮点数,发生截断后,ch 的值是字符 P 的 ASCII 码。
有多种类型的数据混合运算时,系统首先会自动将所有数据转换成精度最大的那种数据类型,然后再进行计算;
若两种类型的字节数不同,转换成字节数大的类型,若两种类型的字节数相同,且一种有符号,一种无符号,则转成成无符号类型;
在赋值运算中,赋值号两边量的数据类型不同时,赋值号右边量的类型将转换成左边量的类型,如果右边变量的数据类型长度比左边长时,将丢失一部分数据,这样会降低精度,丢失的部分按四舍五入向前舍入;
4.2.2、强制类型转换
强制类型转换就是自动类型提升运算的逆运算;我们需要 使用强转符:() 来强制转换;它的格式如下:
(目标数据类型)被强转的数据;
#include <stdio.h>
int main(void)
{
int i1 = 353;
char ch = (char)i1;
float f = 3.14f;
double d = (int)f;
printf("%d\n",ch);
printf("%lf\n",d);
return 0;
}
强制类型转换可能会损失精度,导致数据错误;
强制类型转换操作不会改变操作数本身;
4.3、字符串类型
字符串(character string)是一个或多个字符的序列,它使用一对双引号包裹起来,以 '\0' 作为字符串的结束标志。C 语言中没有专门用于存储字符串的变量类型,我们可以使用 字符数组 来保存字符串,也就是使用一个一维字符数组保存字符串中的每一个字符。此时,编译器会自动为其添加 '\0' 作为结束符。
数组由连续的存储单元组成,字符串的字符被储存在相邻的存储单元中,每个单元储存一个字符。数组末尾位置的字符 '\0'。这是空字符(null character),C语言 用它标记字符串的结束。空字符不是数字 0 ,它是非打印字符,其 ASCII 码值是(或等价于)0。C 中的字符串一定以空字符结束。这意味着数组的容量必须至少比待存储字符串的字符数多 1。
#include <stdio.h>
int main(void)
{
char str[] = "hello world!";
// 格式化输出,%s输出字符串
printf("%s\n",str);
return 0;
}