三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

C Primer Plus——第三章 数据和C

C Primer Plus——第三章 数据和C

本章介绍C语言中数据的表示方式,包括变量与常量、基本数据类型、存储方式及类型相关的操作。

一、示例程序

先看一个使用不同数据类型的简单程序:

#include <stdio.h> int main(void) { int num = 100; // 整型 float pi = 3.14159f; // 单精度浮点型 char ch = 'A'; // 字符型 double large = 1.23e12; // 双精度浮点型 printf("整数: %d\n", num); printf("浮点数: %.5f\n", pi); printf("字符: %c (ASCII %d)\n", ch, ch); printf("科学计数: %e\n", large); return 0; }

通过这个程序,可以直观看到几种基本数据类型的声明和使用方式。

二、变量与常量数据

  1. 变量:程序中用来存储数据的命名存储区域,其值在运行过程中可以改变。
    • 必须先声明后使用,声明时确定类型和名称,可选初始化。
    • int count = 0;
  2. 常量数据:程序运行期间值不能改变的量。
    • 字面常量:直接写出的数值,如1003.14'A'
    • 符号常量:使用#defineconst定义,如#define PI 3.14159const double PI = 3.14159;

三、数据:数据类型关键字概览

C语言通过数据类型关键字来定义变量的类型,主要分为以下几类:

  • 基本类型关键字intlongshortunsignedsignedcharfloatdouble_Bool
  • 复数与虚数类型(很少直接使用):_Complex_Imaginary
  • 类型修饰与扩展signedunsignedshortlong可以和intchar组合产生变体。

这些关键字决定了数据在内存中的存储方式和占用空间。

3.1 计算机存储方式:整数与浮点数

  • 位(bit):最小的存储单元,可以存储0或1。
  • 字节(Byte):最常用的计算机存储单位,1字节 = 8位
  • 字(Word):计算机设计的自然存储单位,通常为16位、32位或64位,取决于体系结构。

3.2 整数存储

  • 整数以二进制补码形式存储,能精确表示其范围内的每一个值。

3.3 浮点数存储

  • 浮点数被分成符号位、指数部分和尾数部分来存储(遵循IEEE 754标准)。
  • 浮点数在表示很大或很小的数时非常有优势,但不能精确表示所有实数,算术运算时可能产生舍入误差。

四、C语言基本数据类型

4.1int类型

  • 有符号整数,通常占用一个机器字长(现今多为32位或64位)。
  • 声明示例:int age;int year = 2026;
  • 打印:用%d输出十进制整数。
  • 八进制和十六进制输出:
    • %o:八进制,不带前缀。
    • %x%X:十六进制,不带前缀。
    • 若想显示前缀,使用%#o(显示0)、%#x(显示0x)或%#X(显示0X)。
int num = 255; printf("十进制: %d\n", num); // 255 printf("八进制: %#o\n", num); // 0377 printf("十六进制: %#x\n", num); // 0xff

4.2 其他整数类型

C语言提供多种整数变体以适应不同范围需求:

类型含义常见大小(位)打印格式(十进制)
short intshort短整型16%hd
long intlong长整型32/64%ld
long long int长长整型64%lld
unsigned int无符号整型与int相同%u
unsigned short无符号短整型16%hu
unsigned long无符号长整型32/64%lu
unsigned long long无符号长长整型64%llu

使用注意事项:

  • C标准只规定了各类型最小允许范围,具体大小由实现决定。可借助sizeof获取字节数。
  • longint占用空间相同的平台上,若希望代码可移植,应使用long来存储可能超过int范围的数。
  • 长整数常量后缀:Ll(如100L表示long类型);LL表示long long。也可用于八进制或十六进制常量。
  • 无符号常量后缀:Uu,可与L组合,如100UL表示unsigned long
  • 溢出问题:有符号整数溢出属于未定义行为;无符号整数溢出会回绕(取模)。
  • 打印八进制或十六进制长整型:%lo%lxshort类型八进制用%ho
long long big = 1234567890123LL; printf("%lld\n", big); unsigned long ul = 4000000000UL; printf("%lu\n", ul);

4.3char类型

  • 用于存储字符,但实际上存储的是字符对应的数值(ASCII码或扩展编码)。占用1字节(8位)。
  • 字符常量:用单引号括起来,如'A''9''$'
  • 字符是以数值形式存储的,'A'在ASCII中对应整数65。C将字符常量视为int类型。
  • 打印字符:用%c输出字符本身,也可用%d输出其对应的整数编码。
char c = 'A'; printf("字符: %c, 编码: %d\n", c, c); // 输出: 字符: A, 编码: 65
  • 有符号/无符号char默认可能是有符号或无符号,由编译器决定。显式声明可用signed char(通常范围-128~127)和unsigned char(0~255)。
  • 非打印字符:一些控制字符无法直接输入,使用转义序列表示。常用转义序列如下:
转义序列含义ASCII值(十进制)
\a警报(响铃)7
\b退格8
\f换页12
\n换行10
\r回车13
\t水平制表9
\v垂直制表11
\\反斜杠92
\'单引号39
\"双引号34
\0oo八进制值(oo为1~3位八进制数字)
\xhh十六进制值(hh为1~2位十六进制数字)

示例:

printf("第一行\n第二行\t缩进后\a警告声"); char single_quote = '\''; char backslash = '\\'; printf("%c %c", single_quote, backslash);
  • 关于\a:“活跃位置”指显示设备上下一个字符将出现的位置\a触发警报声,但不改变活跃位置(即不移动光标)。
  • 字符串:用双引号括起来的字符序列,无需单引号。例如"Hello, World!"

4.4_Bool类型

  • C99引入的布尔类型,只能存储值0(假)或1(真)。若包含<stdbool.h>头文件,可直接使用booltruefalse
_Bool flag = 1; #include <stdbool.h> bool done = false;
  • 任何非零值赋值给_Bool变量都会被转换为1

4.5 可移植类型(stdint.h 和 inttypes.h)

  • 为了解决各平台整数大小不一致问题,C99引入了精确宽度整数类型,定义在<stdint.h>中。它们是可选的(如果平台不支持则不会定义)。
  • 常见类型:
    • 精确宽度:int32_tuint16_t等。
    • 最小宽度:int_least8_t(至少8位)、int_least32_t等。
    • 快速宽度:int_fast16_t等,追求运算速度。
    • 最大宽度:intmax_tuintmax_t
  • 打印这些类型时,使用<inttypes.h>中定义的字符串宏。例如PRId32是打印int32_t的格式说明符。
#include <inttypes.h> int32_t val = 1000; printf("%" PRId32 "\n", val); // 输出 1000

4.6 浮点型:floatdoublelong double

  • float:单精度,通常4字节,有效数字约6-7位。
  • double:双精度,通常8字节,有效数字约15-16位。
  • long double:扩展精度,依赖实现。
  • 浮点型常量:默认以double类型存储。若希望指定为float,添加后缀fFlong doublelL
  • 科学计数法:-1.56E+12表示 -1.56×10¹²,87e-3表示 0.087。
  • 十六进制浮点常量(C99):0xa.1fp10a.1f(十六进制)对应十进制 10 + 1/16 + 15/256,乘以 2¹⁰ 即1024。
float f = 3.14f; double d = 2.718281828; long double ld = 1.23456789L; printf("%.10f %.10f %.10Lf\n", f, d, ld);

4.7 复数与虚数类型

  • C99引入了复数算术的支持(若编译器实现),包含类型float _Complexdouble _Complexlong double _Complex,以及可选的关键字_Imaginary
  • 在包含<complex.h>后可用complex宏及I表示虚数单位。
  • 实际编程中较少直接使用,多用于数值计算领域。

4.8 其他类型

  • void:无类型,主要用于函数返回、函数参数、通用指针。
  • enum:枚举类型,定义命名整数常量。
  • 派生类型:数组、指针、结构体、联合体等。

4.9 类型大小:sizeof运算符

  • sizeof字节为单位给出指定类型或变量的大小。
  • 语法:sizeof(类型)sizeof 变量,返回size_t类型(通常用%zu打印)。
printf("int: %zu 字节\n", sizeof(int)); printf("double: %zu 字节\n", sizeof(double)); int a; printf("a: %zu 字节\n", sizeof a);

五、使用数据类型

类型转换与赋值

  • 把浮点数赋给整数变量时,直接丢弃小数部分(不进行四舍五入),只保留整数部分。
int i = 3.99; // i 的值为 3
  • 不同类型数值在运算时会进行隐式类型转换,通常向更高级别提升(如intdouble)。
  • 强制类型转换:(类型)表达式,如(int)3.99结果为3。

六、参数匹配与陷阱

使用printfscanf时,参数必须与格式字符串中的占位符严格匹配,否则会产生未定义行为:

  • 类型不符(如用%d打印long),可能导致输出错误或崩溃。
  • 参数数量与占位符不一致也会出现问题。
  • 编译器可能不会检查这些错误,需程序员格外小心。

七、转义序列示例与缓冲区刷新

7.1 程序运行情况

下面的程序展示了部分转义序列的效果:

#include <stdio.h> int main(void) { printf("AB\bC\n"); // 输出 A C? (退格将B擦除,可能显示为 AC) printf("12345678\rABCD\n");// 输出 ABCD5678? (回车回到行首,覆盖1234) printf("Alert sound\a\n"); // 发出警告声 return 0; }

实际输出可能因终端而异。

7.2 刷新输出

  • printf默认将输出发送到缓冲区,然后根据一定条件将缓冲区内内容刷新(flush)到屏幕。
  • 缓冲区的刷新时机:
    • 缓冲区满。
    • 遇到换行符\n(行缓冲模式下)。
    • 程序正常结束。
    • 需要输入时(如scanf之前,输出会被刷新)。
    • 显式调用fflush(stdout)

为了确保信息立即显示,可在必要处使用换行符或fflush

八、关键概念

ASCII码(American Standard Code for Information Interchange):用数值表示字符的标准编码方案。标准ASCII使用7位编码,可表示128个字符(0~127)。例如'0'为48,'A'为65,'a'为97。C语言char类型通常基于ASCII或扩展编码(如Latin-1、UTF-8起始段)处理字符。

理解字符与数字的对应关系是掌握C语言输入输出和字符串处理的基础。

总结

  • 数据以变量或常量的形式存储,变量需声明类型。
  • 常用基本类型:intcharfloatdouble,以及它们的修饰变体。
  • 字符通过ASCII码存储,转义序列表示特殊字符。
  • sizeof用于确定类型大小;类型转换需注意精度损失。
  • 格式化输出时注意占位符与参数匹配,了解缓冲区刷新机制有助于控制输出时序。
← 返回列表