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定义常量的区别

  1. const 定义的常量带类型,define 不带类型;
  2. const 是在编译、运行的时候起作用,而 define 是在编译的预处理阶段起作用的;
  3. define 只是简单的替换,没有类型检查;
  4. const 常量可以进行调试的,而 define 是不能进行调试的,主要是因为在预编译阶段 define 定义的常量就已经替换掉了,调试的时候没有了;
  5. const 不能重定义,不可以定义两个一样的,而 define 通过 undef 可以取消某个符号的定义,在重新定义;
  6. 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;
  • 变量的 存储类型 可以是 autoregisterstaticextern
    • 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 类型也可以表示较小的整数floatdoublelong 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

ASCII码表

  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 的别名,而且还把 truefalse 分别定义为 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_Complexdouble_Complexlong 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。

  当运算涉及两种类型时,较小的类型将被转换为较大的类型。

  1. 如果有一个操作数的类型时 long double,则将另一个操作数转换为 long double。
  2. 否则,如果有一个操作数的类型是 double,则将另一个操作数转换为 double。
  3. 否则,如果有一个操作数的类型是 float,则将另一个操作数转换为 float。
  4. 否则,说明操作数都是整型,因此执行整型提升。
  5. 在这种情况下,如果两个操作数都是有符号或无符号的,且其中一个操作数的级别比另一个低,则转换为级别高的类型。
  6. 如果一个操作数为有符号的,另一个操作数为无符号的,且无符号操作数的级别比有符号操作数高,则将有符号操作数转换为无符号操作数所属的类型。
  7. 否则,如果有符号类型则可以表示无符号类型的所有可能取值,则将无符号操作数转换为有符号操作数所属的类型。
  8. 否则,将两个操作数都转换为有符号类型的无符号版本。

类型的级别从高至低依次是 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;
}
posted @ 2023-02-19 12:10  星光映梦  阅读(68)  评论(0编辑  收藏  举报