PS:文中占位符即格式说明符
1. 基础数据类型
C语言的基本数据类型是构建程序的基础,它们用于表示不同类型的数据,并决定了如何存储数据、数据的大小以及可以执行的操作。
C语言的基本数据类型包括:整型、浮点型、字符型。
先来点前置知识。
数据存储
在计算机中最小的数据单位,是位(bit) ,它表示一个二进制,只能是0或1。
而我们平时所说的字节(Byte) ,是由8个位组成的。1个字节等于8个位,它是计算机中用于计量存储容量的一种基本单位。
在计算机中,数据存储的基本单位是字节,而不是位。我们通常说文件大小、内存大小都是以字节为基本单位。
内存单位换算
| 单位 | 换算关系 | 实际大小 |
|---|---|---|
| 1 Bit(位) | 最小单位 | 0或1 |
| 1 Byte(字节) | 8 bits | 存储一个字符 |
| 1 KB(千字节) | 1024 Bytes | 约1000字节 |
| 1 MB(兆字节) | 1024 KB | 约100万字节 |
| 1 GB(吉字节) | 1024 MB | 约10亿字节 |
| 1 TB(太字节) | 1024 GB | 约1万亿字节 |
| 1 PB(拍字节) | 1024 TB | 约1000万亿字节 |
进入基本数据类型学习
1. 整型(Integer Types)
- 用于存储整数。
- 包括:int、short、long、long long(C99标准引入)。
- 可以加上符号修饰符:signed(有符号,默认)和unsigned(无符号)。
注:C99是C语言标准的一个版本,1999年发布,正式名称为ISO/IEC 9899:1999。
| 类型名 | 说明 | 典型大小(64位系统) | 格式说明符 | 取值范围 |
|---|---|---|---|---|
| short | 短整数 | 2字节 | %hd 或 %d | -32768~32767 |
| int | 整数 | 4字节 | %d | -2147473648~2147483647 |
| long | 长整数 | 8字节(Linux) | %ld | -2147473648~2147483647 |
| long long | 超长整数 | 8字节 | %lld | 19位数 |
- 不同的数据类型所表示的范围和内存大小都不一样,由编辑器来决定的。
- 他们的大小排序:short <= int <= long <= long long
- C语言中的整数默认为 int 类型
代码:
c
#include <stdio.h>
int main ()
{
// 整型:int、short、long、long long(C99标准引入)
// sizeof 是一个运算符(不是函数),用于计算数据类型或变量在内存中占用的字节数
// sizeof 的占位符为:%zu,%u,%lu(每个编辑器有所区别,逐一尝试)
// short 短整型
short a = 10;
// int 整型(最常用)
int b = 100;
// long 长整型(后缀L:数字结尾加L)
long c = 10000L;
// long long(C99) 超长整型 (后缀LL:数字结尾加LL)
long long d = 100000LL;
printf("短整型:%hd\n", a); // 占位符 %hd 或 %d
printf("整型:%d\n", b);
printf("长整型:%ld\n", c); // 占位符:%ld
printf("超长整型:%lld\n", d); // 占位符:%lld
printf("---------------------------------------------------\n");
// %u 打印不了的话,试下 %zu 或 %lu
printf("短整型占用字节为:%u\n", sizeof(a));
printf("整型占用字节为:%u\n", sizeof(b));
printf("长整型占用字节为:%u\n", sizeof(c));
printf("超长整型占用字节为:%u\n", sizeof(d));
printf("---------------------------------------------------\n");
return 0;
}
运行结果:

整数修饰符
- signed(有符号):包含负数、零、正数(默认,可省略)
- unsigned(无符号):只包含零和正数(需显示声明)
- signed 占位符:
%d; unsigned 占位符:%u - 位置:放在数据类型的前面(
unsigned int)
整数修饰符决定了整数类型的符号表示方式
代码
c
#include <stdio.h>
int main ()
{
unsigned short num1 = 23;
signed int num2 = -24; // signed一般省略
printf("%u\n", num1);
printf("%d\n", num2);
return 0;
}
运行结果

2. 浮点型(Floating-Point Types)
- 用于存储小数。
- 包括:float(单精度)、double(双精度,默认)、long double(长双精度)。
| 类型名 | 说明 | 典型大小(64位系统) | 格式说明符 | 取值范围 |
|---|---|---|---|---|
| float | 单精度浮点数 | 4字节 | %f | 1.17510^ -38.~3.40210^38 |
| double | 双精度浮点数 | 8字节 | %lf | 2.22510^ -308~1.79710^308 |
| long double | 高精度浮点数 | 16字节 | %Lf |
代码
c
#include <stdio.h>
int main ()
{
// float 单精度小数(精确度小数点后6位)后缀:F
float a = 3.14F;
// double 双精度小数(精确度小数点后15位)
double b = 1.78;
// long double 高精度小数(精确度小数点后18位)后缀:L
long double c = 3.141592653589793L;
printf("%f\n", a);
printf("%lf\n", b);
printf("%Lf\n", c);
return 0;
}
此时我们打印出来就会发现,默认情况下控制台只显示小数点后6位,并且会进行四舍五入。

如果想打印更多位小数,我们可以用 %[.精度]格式符
c
printf("%.2f\n", a);
printf("%.2lf\n", b);
printf("%.15Lf\n", c);

这里我们也可以用 sizeof()来测量每一种数据类型占多少字节
c
#include <stdio.h>
int main ()
{
// float 单精度小数(精确度小数点后6位)后缀:F
float a = 3.14F;
// double 双精度小数(精确度小数点后15位)
double b = 1.78;
// long double 高精度小数(精确度小数点后18位)后缀:L
long double c = 3.141592653589793L;
printf("float占用字节为:%u\n", sizeof(a));
printf("double占用字节为:%u\n", sizeof(b));
printf("long double占用字节为:%u\n", sizeof(c));
return 0;
}
运行结果

PS: signed和unsigned不能用于浮点数,只能用于整数
- 浮点数类型总是有符号的,没有无符号浮点数这个概念。
- 因为浮点数的表示方式(IEEE标准)包含了符号位、指数位和尾数位。浮点数的设计必须能够表示正负小数,以及正负零、正负无穷大等特殊值。
知识补充ASCII码表
下面字符型所用到的取值范围是ASCII码,了解的可略过,直接看下面的字符型。
ASCII码表是什么?
ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是一套基于拉丁字母的电脑编码系统。它是最通用的信息交换标准,为每个字符(如字母、数字、标点、控制符)分配了一个唯一的数字编号。
说通俗点表达就是:可以把ASCII码表想象成一份"通用密码本"或"标准翻译手册"。
- 核心问题: 计算机只能存储和处理数字(0和1),它不认识"A"、"b"、"?"这些字符。
- 解决方案: 我们需要一个标准,规定好哪个数字代表哪个字符。比如,我们一致约定数字 65 就代表大写字母 A。
- 这个约定就是ASCII码。 它是一份全球计算机都认可的标准"合同",上面明确写着:
数字 65 对应 字母 A
数字 97 对应 字母 a
ASCII码分为可显字符和控制字符
-
可显示字符 : 就是那些能在屏幕或打印机上显示出一个具体形状(图形) 的字符。它们是我们阅读文本时实际看到的内容。
- 在ASCII码表中的位置:32 到 126 码位。
- 包括哪些:
- 空格: 码值是32。虽然看起来是"空"的,但它占一个位置,所以也是一个可打印的字符。
- 数字: 0到 9(48-57)
- 大写字母: A到 Z(65-90)
- 小写字母: a到 z(97-122)
- 标点符号: !, ?, ., ,等。
- 数学和特殊符号: +, -, =, @, #, $等。

-
**控制字符:**这些字符不能在屏幕上显示出一个固定的形状。它们的作用是向计算机(或其外部设备,如打印机)发出一个控制命令,用于控制数据流的格式、排版或设备行为。
- 在ASCII码表中的位置:0 到 31 和 127。共33个。
- 包括哪些:
- LF - 换行: 码值10。命令计算机"将光标移动到下一行"。(在Unix/Linux/macOS中,一个LF就表示新行)。
- CR - 回车: 码值13。命令计算机"将光标移动到当前行的最左边"。(在Windows系统中,换行需要连续使用CR和LF两个字符 \r\n)。
- TAB - 制表符: 码值9。命令计算机"将光标跳到下一个制表位",相当于按一下键盘上的Tab键,会产生缩进效果。
- BS - 退格: 码值8。命令计算机"将光标回退一格"。(注意,早期这个命令可能不会删除字符,现在通常和删除功能联动)。
- 等等...,具体看图片

例子
假设你在文本编辑器里输入一行字 Hello,然后按了一下 Enter (回车) 键,再输入 World!。
计算机会这样存储(用转义符表示控制字符):Hello\nWorld!
- H, e, l, l, o是可显示字符。
- \n(换行符LF) 是控制字符。
- W, o, r, l, d, !是可显示字符。
当计算机显示这段内容时,它会:
- 显示可显示字符 Hello。
- 遇到控制字符 \n,就执行"换行"命令,把光标移到下一行。
- 在下一行显示可显示字符 World!。
最终你在屏幕上看到的就是两行:
Hello
World!
3. 字符型(Character Type)
- 用于存储字符。
- 实际上是存储字符的ASCII码(或其他字符编码)值,因此本质上也是一种整数类型。取值范围为ASCII码表中的字母、数字、英文符号
- 典型大小(64位系统):1字节
- 格式说明符:
%c(字符),%d(整数)
代码
c
#include <stdio.h>
int main ()
{
// ASCII码表中的小写字母
char a = 'a';
// ASCII码表中的数字
char b = '1';
// ASCII码表中的大写字母
char c = 'A';
// ASCII码表中的英文符号
char d = '.';
// char 可以声明整型,值是数字,没有加引号;
char e = 3;
// 占位符为 %c
printf("%c\n", a);
printf("%c\n", b);
printf("%c\n", c);
printf("%c\n", d);
// char 声明的整型用占位符:%d
printf("%d\n", e);
return 0;
}
运行结果

用 sizeof()查看占多少字节
c
printf("%u\n", sizeof(char));
// 打印结果为:1
4. 空类型(Void Type)
- 表示"无类型"或"空"。
- 常用于函数返回值(表示函数不返回任何值)或指针(void*,可以指向任何类型的数据)。
- 函数返回类型为void:例如,一个函数只是执行一些操作而不需要返回值,可以将其返回类型声明为void。
c
#include <stdio.h>
// 函数声明为void表示不返回值
void main () {
int a = 1;
printf("%d\n", a);
// 不需要return语句,或使用 return;(不带值)
}
- 函数参数:当函数不接受任何参数时,参数列表应声明为void。
c
#include <stdio.h>
// 参数列表使用void表示函数不接受任何参数
int getNumber(void) {
return 42;
}
int main() {
int num = getNumber(); // 正确
// int num = getNumber(123); // 错误:有参数
printf("Number: %d\n", num);
return 0;
}
- 指针类型:void* 是一种通用指针类型,可以指向任何类型的数据。但是,void* 指针不能直接解引用,因为编译器不知道它指向的数据类型,必须先转换为具体的指针类型。
等到后面写指针再详解。
2. 标志符
标志符是用来给变量、函数、数组、结构体等我们自定义元素的名称。
通俗来讲就是你给程序里的各个"东西"起的名字。
就像现实生活中:
- 你养了一只狗,给它取名叫"旺财"。
- 你家住在"幸福路1号"。
在C语言程序里:
- 你有一个用来存年龄的"盒子"(变量),你给它取名叫 age。
- 你有一个用来计算总价的"机器"(函数),你给它取名叫 calculate_total_price。
旺财、幸福路1号就是现实中的"标识符"。
age、calculate_total_price就是C语言程序里的标识符。
标识符规则
- 组成字符: 字母(A-Z, a-z)、数字(0-9)、下划线(_)
- 首字符限制: 必须以字母 或下划线开头,不能以数字开头。
- 长度限制: C89标准要求至少支持前31个字符有效(编译器可能忽略超长部分)。C99标准要求至少支持前63个字符。
- 区分大小写: age和 Age被视为不同的标识符。
- 禁止使用关键字: 不能与C语言的32个关键字(如 int、if、return等)冲突。
关键字列表(C89标准),不用特地记,后面会接触到
c
auto break case char const continue default do double
else enum extern float for goto if int long register
return short signed sizeof static struct switch typedef
union unsigned void volatile while
一些错误示例:
1age: 数字开头age$:包含非法字符 $int:与关键字冲突my-variable:包含非法字符 -
命名的一些软性建议:
- 可读性: 使用有意义的名称,目的是让你和别人(包括三天后的你自己)能看懂。
- 差名字:a, x1, tmp(谁知道这是干嘛的?)
- 好名字:studentAge, filePath, isValid(一看就知道是存什么的)
- 风格一致:
- 驼峰命名:calculateAverage(第一个单词首字母小写,后面单词首字母大写)
- 蛇形命名:calculate_average(单词间用下划线连接)
- 全大写常量:MAX_SIZE(表示这个值固定不变)
- 避免以下划线开头: 如 _name可能被系统库保留,易引发冲突。
总结一下:
-
C语言标识符,就是你在编程时,为了方便使用和管理,给你用到的各种东西(变量、函数等)起的名字。
-
起名的规矩很简单:用字母、数字、下划线组合,别用数字开头,别跟系统的关键字重名。
PS:起文件名时,全部小写,单词之间用下划线隔开,开头可以用数字。
3. 键盘录入 scanf
基本用法
在C语言中,键盘录入通常指的是从标准输入(通常是键盘 )读取用户输入的数据。最常用的函数是scanf,但也可以使用getchar、gets(不安全,不推荐)、fgets等函数。
下面我们将重点介绍 scanf 的使用方法:
- scanf函数:(scanner format 的缩写)是C语言中最常用的输入函数,它根据格式字符串从标准输入读取数据。
- 作用 :获取用户在键盘上输入的数据,并赋值给变量
- 基本语法 :
scanf("格式字符串", 变量地址); - 使用scanf读取基本数据类型(如int, float, char)时,需要在变量前加上
&(取地址运算符),字符数组除外。 - scanf读取字符串时,遇到空格、制表符或换行符会停止读取。
代码
c
#include <stdio.h>
int main ()
{
// 1. 定义一个变量(整数)用来接收数据
int a;
// 2. 键盘录入
// %d 是整型的格式说明符,也就是占位符
// &:是scanf读取基本数据类型时,用到的固定格式
// a:把输入的整数赋值给这个变量
scanf("%d", &a);
// 打印一下
printf("%d\n", a);
return 0;
}
此时运行会发现,有一个报错:warning C4996: 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
1> e:\develop\vc\vc\include\stdio.h(304) : 参见"scanf"的声明
这是一个编译警告,意思大概就是:scanf 不安全,建议使用 scanf_s 或定义 _CRT_SECURE_NO_WARNINGS。
解决方案:
- 使用 scanf_s 代替 scanf,但注意 scanf_s 不是标准C函数,可移植性差。我们先pass掉。
- 在文件开头添加 #define _CRT_SECURE_NO_WARNINGS 来禁用这个警告。
- 使用编译器选项 /D _CRT_SECURE_NO_WARNINGS。
我们先来试下第二个:禁用安全警告(在文件开头添加)
c
// 在此处添加
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main ()
{
int a;
scanf("%d", &a);
printf("%d\n", a);
return 0;
}
运行一下,成功弹出 cmd。此时cmd是没有内容的,需要我们用键盘输入一个整数。然后按回车键,就会打印你输入的数字了。
第一行是键盘输入的,第二行是printf打印的

除了上面在文件上头添加#define _CRT_SECURE_NO_WARNINGS,我们还可以用第三个方法在项目设置中禁用,这样就可避免用到scanf的文件都要去添加#define _CRT_SECURE_NO_WARNINGS。
- 点击项目文件夹名,右击,选中"属性"

- 弹出一个"属性页"的框,选中右边的预处理器,然后点"预处理器定义"的值的右边向下箭头的图标,选中编辑

- 弹出一个"预处理器定义"的框框,在第一个文本框里,光标定位到最后一行的尾部,按回车键,跳到下一行,输入
_CRT_SECURE_NO_WARNINGS,按下确定按钮,关闭弹框。

设置完后,文件上头去掉#define _CRT_SECURE_NO_WARNINGS,也能正常运行了。
c
#include <stdio.h>
int main ()
{
int a;
printf("请输入一个整数:");
scanf("%d", &a);
printf("变量a里的值为:%d\n", a);
return 0;
}

scanf 录入字符串
当我们声明字符类型时,它只能存一个字节,但我们想存入多个字符时,怎么办?我们可以通过字符数组来表示
- 格式:数据类型 变量名 [内存大小] = 字符串
char str[内存占用多少字节] = "aaa" - 内存占用大小的计算方式:
英文 :1个字母、符号、数字 占用一个字节;
中文 :在vs或vc编辑器中,默认情况下,一个中文占用;两个字节
结束标记:占一个字节
aaa:三个字母占三个字节,加上结束标记占一个字节,一共占4个字节。代码:char str[4] = "aaa";
你好:两个中文占四个字节,加上结束标记占一个字节,一共占5个字节。代码:char str[5] = "你好";
但有时我们并不知道到底需要多少字节时,我们可以把内存大小(中括号里的数字)写大一点。如:char str[100];
代码:
c
#include <stdio.h>
int main ()
{
// 1. 定义变量记录名字
char my_name[100];
// 2.键盘录入名字
printf("请输入名字:\n");
scanf("%s", &my_name);
// 3.打印输出
printf("我的名字是:%s\n", my_name);
return 0;
}
运行结果:输入名字,按回车

字符串字面量
上面在数组(中括号)里填入数字式属于显示字符串。但我就是不想填入数字呢,只给个数组行不行?也行,这个属于字符串字面量形式
- 格式:
char str[] = "aaa" - 以空字符结尾,编译器会自动在末尾添加'\0'(空字符)。
char str[] = "Hello";内存布局:['H','e','l','l','o','\0']
同时录入多个数据
- 格式:scanf("格式字符串1 格式字符串2 ", 变量地址1, 变量地址2);,如:
scanf("%d %f ", &a, &b); - 前面的占位符和后面的变量个数需要一一对应,%d 对应 &a,%f 对应 &b
- 第一个参数,两个占位符之间可以用空格或逗号隔开,在我们输入数据的时候,也要跟代码一样用空格或逗号隔开,表明这还是两个数据。
代码
c
#include <stdio.h>
int main() {
int a;
float b;
char c[10];
printf("请输入一个整数、一个浮点和一个字符串:");
// 注意:除了字符串(字符数组)外,其他变量前面都需要加上&符号,表示取地址。
scanf("%d %f %s", &a, &b, c);
printf("整数:%d,浮点数:%f,字符串:%s\n", a, b, c);
return 0;
}
运行结果:输入10 1.34 你好,按回车键

注: scanf 的第一个参数是不能写换行的,如:scanf("%d \n", &num)