第4节:核心知识2

174 阅读12分钟

1. 数据类型

1.1 sizeof 运算符

目标

  • 会查看变量、类型占用内存大小

  • 每种数据类型,都有自己固定的占用内存大小和取值范围。


具体展开讲解前,我们先来看下,C 语言提供的查看变量或类型占用内存大小的运算符,sizeof


  • 语法 1:sizeof(变量名)
  • int a = 10;

printf("%llu\n"sizeof(a));
//sizeof(a) 获取 a 变量占用内存大小。
可以用 printf 显示出来
// 查看 sizeof 返回的占用内存大小,需要使用 
%llu 格式符

  • 语法 2:sizeof(类型名)

printf("%llu\n"sizeof(double)); 
// 也可以使用 sizeof 直接查看某种类型占用的内存大小

1.2 数值型


1.2.1 整型


目标:选用不同类型存整数


1.2.3 基础信息


数据类型字节数格式符数据范围最小值宏最大值宏
short(短整型)2字节%hd-2^15 ~ 2^15-1SHRT_MINSHRT_MAX
int(整型)4字节%d-2^31 ~ 2^31-1INT_MININT_MAX
long(长整型)4字节%ld-2^31 ~ 2^31-1LONG_MINLONG_MAX
long long(长长整型)8字节%lld-2^63 ~ 2^63-1LLONG_MINLLONG_MAX
unsigned short(无符号短整型)同 short%hu0 ~ 2^16-10USHRT_MAX
unsigned int(无符号整型)同 int%u0 ~ 2^32-10UINT_MAX
unsigned long(无符号长整型)同 long%lu0 ~ 2^32-10ULONG_MAX
unsigned long long(无符号长长整型)同 long long%llu0 ~ 2^64-10ULLONG_MAX
  • 上表中列出的占用字节数和取值范围,是大多数情况下各种类型的取值。

  • 由于,C 标准没有具体规定以上各类数据所占用的字节数。因此,在不同系统、编译器下,数据类型占用的字节数会有所不同。

  • 比如:int 类型,在 Turbo C 环境占 2 字节,取值范围与 short 相同。 而在 Visual C 环境下是 4 字节。 再如:long 类型,相同的 gcc 编译器下,在 Windows 系统中占 4 字节,而在 Linux 系统中占 8 字节。

  • 可以使用 sizeof 查看 数据类型 占用内存的大小。

  • 可以引入头文件 #include <limits.h> 借助宏来查看 数据类型 在当前平台上 对应的最小、最大值。


#include <stdio.h>
#include <limits.h>

int main(void)
{
printf("short 大小 = %llu\n", sizeof(short));
printf("short 最小值 = %hd, 最大值 = %hd\n", SHRT_MIN, SHRT_MAX);
printf("unsigned short 最小值 = 0 最大值 = %hu\n", USHRT_MAX);
printf("\n");
printf("int 大小 = %llu\n", sizeof(int));
printf("int 最小值 = %d,最大值 = %d\n", INT_MIN, INT_MAX);
printf("unsigned int 最小值 = 0, 最大值 = %u\n", UINT_MAX);
printf("\n");

    printf("long 大小 = %llu\n", sizeof(long));
    printf("long 最小值 = %ld, 最大值 = %ld\n", LONG_MIN, LONG_MAX);
    printf("unsigned long 最小值 = 0 最大值 = %lu\n", ULONG_MAX);
    printf("\n");

    printf("long long 大小 = %llu\n", sizeof(long long));
    printf("long long 最小值 = %lld, 最大值 = %lld\n", LLONG_MIN, LLONG_MAX);
    printf("unsigned long long 最小值 = 0, 最大值 = %llu\n", ULLONG_MAX);
    printf("\n");

    return 0;

}

1.2.4 验收案例

  • 编写程序,选择合适的类型 定义变量 存储:人类年龄、中国人口数量 和 地球年龄(约 45.5 亿), 并借助宏 打印 选用的类型对应无符号数 最大值,证明你的选择无误。

1.2.5 bool 型

目标:知道 bool 类型两种取值

  • C 语言在设计之初是没有布尔类型的,使用 1 和 0,对应表示真、假。
  • 但,其他编程语言像 C++、java 都设计有布尔数类型。 C 语言在 1999 年推出的新标准(C99)中,也加入了 布尔类型。用 true 来代表 1,为真;用 false 来代表 0,为假。
  • 使用时,需要引入头文件 #include <stdbool.h>

#include <stdbool.h>

int main(void)
{
printf("%d, %d\n"truefalse); // 1, 0
return 0;
}

虽然语法上与其他语言一致,但 C 语言每次在使用时需先引入头文件,较为麻烦。 因此,一些老 C 工程师还是喜欢直接在程序中用 1 和 0 来表示 真和假。


1.2.6 实型

目标:

  • 会选用浮点型变量存小数 实型表示有符号的十进制小数,在计算机内部以浮点方式表示(小数点是浮动的),因此也叫浮点型。
  • 常见实型有两种: float (单精度)、 double (双精度)
  • 实型数据没有八、十六进制,也没有 unsigned 无符号形式。在计算机底层采用的是近似计算,实现比较复杂,且不同平台处理方式不同。我们这里只学习它基本的知识。
1.2.6.1 基础信息
类型字节数格式符有效数字常量后缀
float (单精度)4%f6~7f
double (双精度)8%lf15~16
  • float (单精度) : 此类型占用4个字节,使用格式符 %f 进行输出,能提供大约6到7位的有效数字精度。在C/C++中声明单精度浮点常量时,例如 3.14f,可以在数值后添加后缀 f
  • double (双精度) : 此类型占用8个字节,推荐使用格式符 %lf 进行输出(尽管 %f 在很多情况下也可用于double类型的数据),能提供大约15到16位的有效数字精度。在C/C++中,默认的浮点类型就是double类型,声明时无需特殊后缀,如需显式指定,则可以使用后缀 d,例如 3.143.14d

我们直接书写的小数常量,如 6.23,系统默认看做 double 类型。如想指明为 float 类型,需加后缀 f,6.23f。

  • 6~7:

    • 整数部分 + 小数部分 <= 6 位, 准确。
    • 整数部分 + 小数部分 == 7 位,可能准确,也可能不准确。
    • 整数部分 + 小数部分 > 7 位。大多不准确。

  • 15~16:

    • 整数部分 + 小数部分 <= 15 位, 准确。
    • 整数部分 + 小数部分 == 16 位,可能准确,也可能不准确
    • 整数部分 + 小数部分 > 16 位。大多不准确。 显示小数时,%f 和 %lf 默认保留 6 位小数。 如需指定小数位数,使用格式符 %.nf ,n 为几,表示精确到小数点后几位,会对 n+1 位做 4 舍 5 入。

#include <stdio.h>

int main(void)
{
float f = 1.23456789101112131415f// 定义有 20 位小数的 float 变量
double d = 1.23456789101112131415// 定义有 20 位小数的 double 变量

    printf("f=%.20f\n", f);
    printf("d=%.20lf\n", d);

    return 0;

}

1.2.6.2 验收案例
  • 已知 圆周率 π 的值为 3.14159265358979323846。选择一种浮点数类型定义变量保存 π 值,并打印输出变量,要求正确保留小数点后 8 位数据。

1.2.7 字符型

目标:会在程序中使用字符型数据

1.2.7.1 基础信息

C 语言定义 char 类型来表示字符数据。 其本质依然是存储数值,因此与数值型类似,也有有符号、无符号之分。占用 1 个字节内存大小。 暂时无法在飞书文档外展示此内容

1.2.7.2 ASCII

char 类型在程序中,最常用来表示字符。其本质依然是一个数字,但每个值都对应一个固定的字符,共定义了 128 个字符。称之为 ASCII 码 (American Standard Code for Information Interchange) 美国信息交换标准代码。


ASCII值控制字符ASCII值字符ASCII值字符ASCII值字符
0NUL32(space)64@96
1SOH33!65A97a
2STX34"66B98b
3ETX35#67C99c
4EOT36$68D100d
5ENQ37%69E101e
6ACK38&70F102f
7BEL39'71G103g
8BS40(72H104h
9HT41)73I105i
10LF42*74J106j
11VT43+75K107k
12FF44,76L108l
13CR45-77M109m
14SO46.78N110n
15SI47/79O111o
16DLE48080P112p
17DC149181Q113q
18DC250282R114r
19DC351383S115s
20DC452484T116t
21NAK53585U117u
22SYN54686V118v
23TB55787W119w
24CAN56888X120x
25EM57989Y121y
26SUB58:90Z122z
27ESC59;91[123{
28FS60<92\124
29GS61=93]125}
30RS6294126~
31US63?95_127DEL

上表中有 6 个字符对应的 ASCII 较为常见,建议大家记下,会为后续写代码提供很多方便。

字符ASCII 码字符ASCII 码
0\n(换行符)10
空格32048
A65a97

需注意的是,我们从键盘键入的所有内容都是字符。如,键入数字 7,实际是字符 ‘7’,真正存储在计算机内的是 55(字符 7 的 ASCII 码值),而如果我们键入了 35,实际上这是两个字符。真正存储在计算机内的是 51 和 53(字符 3 和 字符 5 的 ASCII 码值)。 我们可以用 printf 结合 格式符 %c,显示字符。 如果用 %d,就显示 其 ASCII 值了。

#include <stdio.h>

int main(void)
{
char ch = 53;
printf("ASCII 为:%d, 字符为:%c\n", ch, ch);
return 0;
}
1.2.7.3 转义字符

C 语言提供了一类特殊的字符,是由 \ 和特定字符组合而成,称之为 转义字符。他们都是 ==一个== 字符,如:

  • \n 这是 1 个字符。 代表 回车换行(回车键)。
  • \t 也是 1 个字符。代表 制表符 (Tab 键)。
  • \b 同样是 1 个字符。 代表 退格符(Backspace 键)。
  • \0 是一个字符。代表 空。对应 ASCII 值 0。
  • \ddd 是一个字符。ddd 对应 3 个八进制数(没有用 0 开头)。 如:\141 对应 ASCII 值为 97,代表 ‘a’。
  • \xhh 是一个字符。x 表十六进制,hh 对应 2 个十六进制数。 如:\x41 对应 ASCII 值为 65,代表 ‘A’。 \ 还可以在特定环境下,将一个字符还原其本身意。 比如,现在想在 printf(“%d\n”,10);输出 10 的时候,用 “” 把 10 包裹住。 如果直接写 printf(“ “%d” \n”,10);是会报错的。这时,可以使用 " 将 “ 进行转义,还原其本身意。 printf(""%d"", 10); // 这里的 " 看做一个双引号字符。 类似的还有:
  • \ 代表 单引号。
  • \ 代表 反斜杠。

1.2.8 字符输入输出

C 语言提供了专门的函数,方便在程序中 获取、输出 字符数据。


  • getchar():获取用户从键盘写入的一个字符。

    1. 程序执行到 getchar() 会暂停,等待用户键入字符数据。
    2. 一次 getchar() 调用,只读取一个字符。如用户键入多个字符,需要多次调用 getchar()读取。
    3. 函数调用完成,会返回实际读到的字符 对应的 ASCII 值。
    4. 用户键入字符结束,敲的回车键,对应‘\n’ 字符,也可以使用 getchar() 读取。
  • int ret = getchar();

  • putchar(ch):将 ch 对应的字符,输出到屏幕。


  1. ch 可以是变量也可以是常量。
  2. 一次 putchar() 调用,只写出一个字符(不含换行符 ‘\n’)。
  3. 函数调用完成,会返回实际写出的字符 对应的 ASCII 值。
  • char ch = 'A'; int ret = putchar(ch); 验收案例
  • 编写程序,使用 getchar 接收用户输入的 字符 a 和回车符。要求通过 ‘a’ 进行数学运算得到 ‘A’,只使用一个 prinf 函数打印 ‘A’ 和 回车符的 ASCII 值,使用 tab 符隔分数据。

2. 标识符

2.1 什么是标识符?

程序中,我们自己起的名字统称为标识符

2.2 标识符的硬性要求
  • 以数字、字母、下划线组成
  • 不能以数字开头
  • 不能是关键字
  • 区分大小写
2.3 标识符的软性建议

用英文单词,见名知意 变量名:全部小写 文件名:全部小写,单词之间用下划线隔开

3. scanf 输入

目标:接收用户输入数据
我们可以借助 getchar() 读取用键入的字符数据。 如果想要读取其他数据怎么办呢?C 语言提供了 scanf() 函数,可以结合 格式符 读取各种类型数据。 基础信息

  • 作用:从标准输入设备(键盘)上按格式获取数据。

  • 语法:scanf("格式控制字符串“, ......); 需指定头文件 #include <stdio.h>

    • 参 1: 必须是字符串,且必须包含 格式说明符(占位符)

      • 格式符 与 数据类型中使用方式一致。 常用的有 %d、%c、%f、%lf 等。
    • 后续参数(变参):个数,直接受 参 1 格式匹配符影响。

      • 对应 格式符的 必须是 变量地址(&变量名,可取变量地址),代表数据存放位置。
  • 示例: printf(“请输入一个字符:”); // 借助 printf 提示用户输入 char ch = 0; // 准备变量,存储数据 scanf("%c", &ch); // 使用变量地址,与 格式符对应

printf(“请输入三个整数,用逗号间隔:”);
int a, b, c; // 可以不赋初值。
scanf("%d,%d,%d", &a, &b, &c);

注意事项

  1. 不要在 scanf 的参 1 中,添加类似 printf() 的提示字符串和 \n 换行符。
  2. 键入数据时,数据个数、类型、顺序,必须与参 1 中占位符一一对应。
  3. 键入数据时,数据间的分割符,必须与 参 1 中 占位符的分割符一致。
  4. scanf 的返回值,代表格式符成功匹配数据的次数。(较少使用)
  5. VS2019 以后的版本编译时,会将 scanf 划为 “不安全函数”,爆出 C4996 错误,推荐你使用 s_scanf() 函数。
  6. 但,学习、练习、测试时,直接使用 scanf 很方便,可暂时屏蔽该错误。
  • 方法 1:在项目中设置:工程名 → 右键 → 属性 →C/C++→ 预处理器 → 预处理器定义 → 编辑 → 将 _CRT_SECURE_NO_WARNINGS 加入“预处理定义” 中
  • 方法 2:在每个.c 文件开头(第一行)添加宏:#define _CRT_SECURE_NO_WARNINGS