C 数据类型

C 语言中的数据类型,说白了就是变量的 “值” 的类型(如下图所示)。

C数据类型语法

在 C 语言中,共有以下 3 种数据类型。

C数据类型有哪些

本节先来介绍 C 语言的基本数据类型,然后在后面章节再去介绍其他数据类型。

C 整数类型

在 C 语言中,“整数类型” 也叫做 “整型”,比如 0、-100、100、2025 等都属于整型数据。对于整型来说,C 语言还进一步细分为 3 种子类型,如下表所示。

C 语言 3 种整型
关键字 说明
short 短整型
int 一般整型
long 长整型

提示: int 是 “integer(整数)” 的缩写,从英文意思的角度可以帮助我们更好地理解。在后面的学习中,小伙伴们可以多从这个角度出发。

short、int、long 这 3 个关键字都可以定义一个整型变量,那它们之间有什么区别呢?其实很简单,从名字上就可以看出来:它们的取值范围可能会不一样,如下表所示。

C 整型的取值范围
类型 范围
short -215~215-1,即 -32768~32767
int -231~231-1,即 -2147483648~2147483647
long -231~231-1,即 -2147483648~2147483647

整型在内存中是以二进制的方式来存放的。比如一般情况下,short 变量占用 2 个字节。然后在计算机中,一个字节占用 8 位(即 8 个二进制)。也就是说,一个 short 变量需要用 16 个二进制来表示。比如整数 10,在计算机中用二进制表示如下。

整数10如何使用二进制表示

那么 16 个二进制能表示多少个数字呢?答案很简单:216 个。也就是说,short 类型可以表示 216 个整数。由于我们不仅要表示正整数,也要考虑负整数,所以 short 类型的取值范围为 -215~215-1。

这里小伙伴就会问了:“这不对啊?short 类型能表示 216 个整数,它的取值范围不应该是 -215~215 吗?怎么是 -215~215-1 呢?”其实我们很容易把 0 给漏掉了。这里简单推一下就知道了,假如 short 类型能表示 22 个整数,那么它能够表示的整数有 4 个,也就是:-2、-1、0、1。此时 short 类型的取值范围不就是 -21~21-1 了吗?

在 C 语言中,short 变量占用 2 个字节(16 位),int 变量占用 4 个字节(32 位),long 变量占用 4 个字节(32 位)。需要注意的是,即使在 64 位 Windows 系统下,long 类型依然占用 4 个字节。只有在 Linux/macOS 的 64 位系统中,long 才占用 8 个字节。

可能小伙伴也发现了,上表中 int 和 long 的取值范围是一样的。实际上现在操作系统有 16 位、32 位、64 位,根据位数的不同,short、int、long 的取值范围也是不一样的。对于不同位数机器的取值范围,而 32 位机中 int 和 long 的取值范围是一样的。

实际上,整数类型的取值范围不仅会受到机器位数的影响,还会受到编译器的影响。现在大多数情况我们采用的都是 32 位机的标准。也就是说,就算你的电脑是 64 位的,但很可能也是使用 32 位机的标准。

对于整型的取值范围,我们了解一下就可以了,不需要去记忆,这一点非常重要。在实际开发中,要是忘记了,再回来查一下即可。

示例 1:使用整型

#include <stdio.h>

int main(void)
{
    int a = 10;
    printf("%d", a);
    return 0;
}

运行结果如下。

10

分析:

对于 short、int、long 这几种整型来说,在后面的学习中一般只会用到int,所以只需要关注 int 就可以了。然后在真实开发中,再根据实际需求去使用。

1. 无符号整型

实际上,C 语言中的整型其实还可以分成 2 种类型:① 有符号整型;② 无符号整型。所谓的有符号整型,指的是包含了该类型不仅包含正整数,也包括了负整数。因为负整数前面有一个负号(-),所以才叫 “有符号整型” 嘛。前面我们介绍的 short、int、long 都属于 “有符号整型”。

无符号整型通常用于表示非负数的情况,例如计数、数组索引等。在 C 语言中,无符号整型有 3 种,如下表所示。

C 无符号整型
类型 范围
unsigned short 0~216-1,即 0~65535
unsigned int 0~232-1,即 0~4294967295
unsigned long 0~232-1,即 0~4294967295

示例 2:使用无符号整型

#include <stdio.h>

int main(void)
{
    unsigned int year = 2025;
    printf("%d", year);
    return 0;
}

运行结果如下。

2025

分析:

在实际开发中,我们更多的是使用有符号整型。所以对于无符号整型,简单了解一下即可。

2. 数据溢出

我们都知道,short、int、long 这几种类型是有一定的取值范围的。当定义的整数超出它们的取值范围时,就会导致 “数据溢出” 的现象。

示例 3:整型的数据溢出

#include <stdio.h>

int main(void)
{
    short a = 32768;
    printf("%d", a);
    return 0;
}

运行结果如下。

-32768

分析:

short 变量取值最大值为 32767,由于这里的 32768 已经超过 32767 了,此时就会导致数据溢出问题。对于整型的数据溢出,C 语言一般不会提供任何提示,而是简单地给出一个不正确的结果。所以在实际开发中,小伙伴们一定要注意数字的大小,避免数据溢出而产生难以察觉的 bug。

接下来我们可以使用数据溢出的特点,来判断当前电脑中 long 类型的取值范围采用的是哪一种标准。

示例 4:判断使用哪一种标准

#include <stdio.h>

int main(void)
{
    long a = 2147483648;
    printf("%d", a);
    return 0;
}

运行结果如下。

-2147483648

分析:

从结果可以看出来,当一个 long 类型变量取值为 2147483648(也就是比 2147483647 大 1),此时数据就溢出了。也就是说,当前使用的是 32 位机的标准。

C 浮点数类型

在 C 语言中,浮点数类型也叫做 “浮点型”。浮点型指的是 “带小数的类型”,比如 0.0、1.0、-10.1、3.14 等都属于浮点型数据。浮点型又叫做 “实型”,也就是实数。对于浮点数来说,它是由整数部分和小数部分组成的,非常的简单。

1. 浮点型的表示方式

对于浮点型来说,它有 2 种表示方式:① 十进制数方式;② 指数方式。十进制数方式很简单了,比如 3.1415。而指数方式就是使用 “e” 或 “E” 组成来表示的,比如 2.1E5,等价于 2.1×105、-3.0E8 等价于 -3.0×108

在实际开发中,指数方式用得很少,我们只需要重点关注十进制数方式就可以了。

示例 5:不正确的浮点数

2025      // 缺少小数部分
E8        // E 前面必须要有数字
2.8E      // E 后面必须要有数字

2. 浮点型的两种类型

对于浮点型来说,C 语言又进一步分为 float 和 double 这 2 种类型。float 类型又叫做 “单精度类型”,double 类型又叫做 “双精度类型”,它们的取值范围如下表所示。

浮点型的取值范围
类型 精度 范围
float 6 位 3.4×10-38 ~ 3.4×1038
double 15 位 -1.7×10-308~1.7×10308

float 类型的精度是 6 位,指的是有效数字是 6 位,而不是精确到小数点后 6 位。这一点大家一定不要搞错了。比如 123.456789 会保留前面 6 个数字(123456),而不是保留小数点的后 6 位(456789)。对于精度位数这个问题,我们不必过多关注,如果你发现有一些奇怪的现象,也不用大惊小怪。

对于浮点型来说,当精度要求不严格时(比如带一位小数的温度),float 类型是很适合的类型。double 类型提供更高的精度,对绝大多数程序来说都已经够用了。

实际上,除了 float 和 double,还有一种 long double 类型。long double 支持极高的精度,估计这辈子你也没有什么机会用到,所以小伙伴们也不用在意这个。

注意: float 和 double 类型在表示浮点数时存在精度限制,因此不适合进行精确的数值比较。比如 0.1 + 0.2 在计算机中可能不等于 0.3,这是新手最容易遇到的 “灵异事件”。

示例 6:使用 float 类型

#include <stdio.h>

int main(void)
{
    float a = 3.1415;
    printf("%f", a);
    return 0;
}

运行结果如下。

3.141500

分析:

如果想要使用 printf() 函数输出一个 float 类型,我们应该使用的是 “%f” 格式,而不是使用 “%d” 格式。“%f” 中的 “f” 其实就是 “float” 的意思。其中,“%f” 会保留 6 位小数。

// 正确
printf("%f", a)

// 错误
printf("%d", a)

C 字符类型

在 C 语言中,字符类型也叫做 “字符型”。下面将先介绍字符型的语法,然后再进一步介绍 ASCII 码的使用。

1. 字符型简介

在 C 语言中,我们可以使用 char 关键字来定义字符型变量。需要注意的是,C 语言中的字符型都是单个字符,而不包括多个字符(即字符串)。如果想要表示一个字符串,我们需要借助后面介绍的 “数组” 来实现。

示例 7:使用字符型

#include <stdio.h>

int main(void)
{
    char a = 'A';
    printf("%c", a);
    return 0;
}

运行结果如下。

A

分析:

对于字符来说,我们必须使用英文单引号来表示,而不能使用英文双引号来表示。如果使用英文双引号来表示字符,程序就会报错。C 语言在这一点上和其他编程语言(比如 PythonJavaScript 等)是不一样的。

// 正确
char a = 'A';

// 错误
char a = "A";

此外,字符型变量的值只能是单个字符,而不能是多个字符,比如 'AB' 就是错误的。从上面也可以知道,C 是一门语法比较严格的语言,这一点和其他语言不一样。

示例 8:引号内都是字符

#include <stdio.h>

int main(void)
{
    char a = '+';
    printf("%c", a);
    return 0;
}

运行结果如下。

+

分析:

“+” 在 C 语言中是用于两数相加的运算符,但这里我们使用单引号括起来,它就不再是运算符了,而是属于一个字符。实际上,不管任何符号只要用单引号括起来,那么它就只是一个字符,而失去了原来的意义。比如 * 是一个乘号运算符,但是 '*' 却是一个字符型数据。8 是一个整型数据,但是 '8' 却是一个字符型数据。

2. ASCII 码

在 C 语言中,对于字符来说,它是以 “整数” 的方式存储在计算机中的。实际上,官方为每一个字符都定义了一个对应的整数。比如想要存储一个字符 'A',那么我们其实就是将 'A' 对应的整数 65 存储在计算机中。对于字符所对应的 “整数”,我们又叫做 ASCII 码,小伙伴们可查阅一下 “ASCII 码表” 都有哪些字符。

提示: ASCII (American Standard Code for Information Interchange) 码是美国标准信息交换代码,它使用 7 位二进制数表示 128 个字符。在 C 语言中,char 类型通常占用 1 个字节(8 位),因此可以表示扩展 ASCII 码中的字符。

这里就有人问了:“为什么不直接把字符存储呢?而是先找到它对应的整数,然后再存储那个整数呢?这不是更加麻烦吗?” 大家别忘了,任何数据都是以 “二进制” 的方式存储在计算机中的。字符是不能直接存放在计算机中的,所以正确的做法是将字符转换成整数,然后再把这个整数存到内存中去(其实就是存二进制)。所以现在大家应该知道为什么要搞一个 ASCII 码这样的东西出来了吧?

一个字符的 ASCII 码,简单来说就是该字符所对应的整数是什么。最后需要说明的是,对于附录 B 这个表,只是为了方便查询而已,我们并不需要去记忆。不过对于 ASCII 码,我们需要知道以下几点结论。

  • 比较两个字符的大小,其实比较的是它们对应的 ASCII 码大小。
  • 对于 A ~ Z 来说,A 的 ASCII 码最小,Z 的 ASCII 码最大。字母越靠后,ASCII 码越大。同样地,对于 a ~ z 来说,a 的 ASCII 码最小,z 的 ASCII 码最大。
  • ASCII 码大小排序:[0~9] < [A~Z] < [a~z],也就是:数字 < 大写字母 < 小写字母。

示例 9:查看字符的 ASCII 码

#include <stdio.h>

int main(void)
{
    char a = 'A';
    printf("%d", a);
    return 0;
}

运行结果如下。

65

分析:

由于 ASCII 码本身是一个整数,所以如果想要使用 printf() 输出一个字符对应的 ASCII 码,我们可以使用 “%d” 格式。另外对于输出格式,我们在后面的 “C 输出” 这一节再详细介绍。

从技术上来看,char 类型本质上也是一种整数类型。为什么这样说呢?比如字符 'A' 对应的 ASCII 码是 65,如果我们想要将字符 'A' 存储到内存中,本质上是把 65 存到内存中。

此外,C 语言是区分大小写的,比如 'a' 和 'A' 就是两个不同的字符。我们可以使用 printf() 函数输出它们各自的 ASCII 码就知道了,结果也是不一样的。

示例 10:空格的 ASCII 码

#include <stdio.h>

int main(void)
{
    char a = ' ';
    printf("%d", a);
    return 0;
}

运行结果如下。

32

分析:

在 C 语言中,空格也是一个字符。char a = ' '; 表示 a 的值是一个空格符号。特别注意一点,''(无空格)和 ' '(有空格)这两个是不一样的。

如果单引号之间什么都没有,那么它表示一个空字符,一般情况下我们不允许将一个空字符赋值给一个变量。如果单引号之间有一个空格,那么它就表示一个空格符。

C 数据类型的常见问题

1. 为什么 C 语言要求在定义所有变量时都要指定变量的类型,而像 Python、JavaScript 等语言却不需要呢?

所谓指定变量的类型,也就是分配多少存储空间(即字节数)给该变量。在计算机中,数据是存放在存储单元中的,它是具体存在的,所以我们必须给它分配存储空间。

实际上 Python、JavaScript 底层还是使用 C/C++ 来写的,虽然它们本身不需要指定变量的类型,但在这些语言的底层,本质上还是要指定类型的,只不过语言的开发者早就写好逻辑帮我们自动指定类型而已。

2. 对于整数类型,为什么 C 语言还要设置 short、int、long 这么多种呢?直接使用 long 这一种不就可以了吗?而 long 的范围也足够大了,完全可以把 short、int 表示的整数包含进来了。

如果只使用 long 这一种,那么每一个整型都要用到 4 个字节来存储。如果一个项目中大多数数据都是比较小的,比如学生年龄都是 100 以内,这个时候还使用 4 个字节来存储,就非常浪费内存空间了。

所以为了方便根据实际需求来定制,C 语言才提供了多种范围的类型来给我们选择。大家要清楚一点:内存才是最贵的

上一篇: C 标识符

下一篇: C 转义字符

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号