一、回顾与本篇目标
上一篇你写了人生中第一个 C 程序,编译并运行了它。你知道了 C 程序必须有 main 函数,语句以分号结尾,编译是把源代码变成可执行文件的过程。
这一篇我们要正式进入 C 语言的语法学习。如果你已经会 JavaScript 或 Python,你会发现 C 的语法既熟悉又陌生——熟悉的是运算符和表达式(加减乘除都一样),陌生的是变量声明必须指定类型,而且这个类型是终身不变的。
本篇的目标:
- 掌握 C 语言中变量的声明和初始化方式
- 理解 C 的基本数据类型以及它们占用的内存大小
- 学会用
printf进行格式化输出 - 学会用
scanf获取用户输入 - 掌握 C 的运算符和类型转换
二、变量声明:必须指定类型
这是 C 和 JavaScript/Python 最大的区别。在 JS 中,你可以这样写:
// JavaScript
let x = 10; // x 是数字
x = 'hello'; // 现在 x 是字符串了——完全没问题
Python 同样灵活:
# Python
x = 10
x = 'hello' # 同样没问题
C 语言不允许这种行为。每个变量在声明时就必须指定类型,而且这个类型终身不变:
// C
int x = 10; // x 被声明为 int 类型
x = 20; // 没问题,20 是整数
// x = "hello"; // 编译错误!不能把字符串赋给 int 类型的变量
变量声明的语法
类型 变量名 = 初始值;
初始值是可选的。如果不写初始值,变量里存的是垃圾值——这块内存之前残留的数据。所以在 C 中,养成声明时立即初始化的习惯非常重要:
int age = 28; // 声明并初始化
float price = 19.99;
char grade = 'A';
int count; // 只声明不初始化——count 里是垃圾值!
printf("%d\n", count); // 可能输出任意数字,每次运行都可能不同
变量命名规则
C 语言的变量命名规则和 Python/JavaScript 基本相同:
- 只能包含字母、数字、下划线。
- 不能以数字开头。
- 区分大小写:
age和Age是两个不同的变量。 - 不能用 C 的关键字(如
int、if、for、return等)。 - 命名风格:C 社区习惯用下划线命名法——
user_name、total_score。这和 Python 一样,和 JavaScript 的驼峰命名法不同。
三、C 的基本数据类型
C 语言的数据类型非常精简。最常用的只有四种:
| 类型 | 含义 | 占用内存(通常) | 取值范围(通常) | 示例 |
|---|---|---|---|---|
int |
整数 | 4 字节(32 位) | 约 -21 亿 到 +21 亿 | int age = 28; |
float |
单精度浮点数 | 4 字节(32 位) | 约 ±3.4 × 10³⁸,7 位有效数字 | float price = 19.99; |
double |
双精度浮点数 | 8 字节(64 位) | 约 ±1.7 × 10³⁰⁸,15 位有效数字 | double pi = 3.1415926535; |
char |
单个字符 | 1 字节(8 位) | -128 到 127 或 0 到 255 | char grade = 'A'; |
和 JavaScript/Python 的对比:
- JavaScript 只有
number一种数字类型,不区分整数和浮点数。C 严格区分int和float/double。 - Python 的
int理论上有无限精度,float是双精度。C 的int有固定范围,超出就会溢出。 - 占用内存:在 JS/Python 中你几乎不需要关心一个变量占多少字节。在 C 中,这是你必须关心的事情,尤其是在嵌入式或高性能场景。
用 sizeof 查看类型占用的内存
C 提供了一个 sizeof 运算符,可以直接查看任何类型占用的字节数:
#include <stdio.h>
int main() {
printf("int: %zu 字节\n", sizeof(int));
printf("float: %zu 字节\n", sizeof(float));
printf("double: %zu 字节\n", sizeof(double));
printf("char: %zu 字节\n", sizeof(char));
return 0;
}
在你的电脑上运行这段代码,看看输出。大多数现代系统上,int 是 4 字节,char 是 1 字节。%zu 是 sizeof 返回值的专用格式符(size_t 类型)。
int 的变体:short 和 long
C 还提供了 int 的变体来精确控制大小:
short int small_num = 32767; // 通常 2 字节,范围约 ±3.2 万
long int big_num = 2147483647; // 通常 4 或 8 字节
long long int huge_num = 9000000000000000000; // 至少 8 字节
int 关键字可以省略:short 就是 short int,long 就是 long int。日常开发中,int 和 double 是最常用的,float 只在需要节省内存时才用。
有符号和无符号
C 中的整数类型默认是有符号的——可以表示负数、零、正数。如果你确定一个变量永远不会是负数(比如年龄、数量),可以加上 unsigned 关键字,让取值范围翻倍(全部给正数):
unsigned int age = 28; // 0 到约 42 亿
unsigned char byte = 255; // 0 到 255
四、printf:格式化输出
上一篇我们已经用了 printf。现在来深入理解它。C 没有 Python 的 f-string 或 JavaScript 的模板字符串,你需要在字符串中用格式占位符来标记变量的位置:
int age = 28;
float height = 175.5;
char grade = 'A';
printf("年龄:%d 岁,身高:%.1f cm,等级:%c\n", age, height, grade);
输出:年龄:28 岁,身高:175.5 cm,等级:A
常用的格式占位符:
| 占位符 | 对应的类型 | 说明 |
|---|---|---|
%d 或 %i |
int |
有符号十进制整数 |
%u |
unsigned int |
无符号十进制整数 |
%f |
float / double |
浮点数(默认 6 位小数) |
%.2f |
float / double |
浮点数,保留 2 位小数 |
%c |
char |
单个字符 |
%s |
char[](字符串) |
字符串 |
%p |
指针 | 内存地址(后面会讲) |
%% |
— | 输出一个百分号本身 |
格式控制的高级用法:
int num = 42;
// 宽度控制:%5d 表示至少占 5 个字符,右对齐
printf("|%5d|\n", num); // | 42|
// 左对齐:%-5d
printf("|%-5d|\n", num); // |42 |
// 用 0 填充:%05d
printf("|%05d|\n", num); // |00042|
五、scanf:获取用户输入
scanf 是 C 标准库中用来读取用户输入的函数。它相当于 Python 的 input(),但用法完全不同。
基本用法
#include <stdio.h>
int main() {
int age;
printf("请输入你的年龄:");
scanf("%d", &age); // 注意:age 前面有 & 符号!
printf("你明年就 %d 岁了。\n", age + 1);
return 0;
}
逐行解释:
scanf("%d", &age):%d表示“我要读取一个整数”,&age表示“把它存到age这个变量的内存地址中”。&符号:这是 C 语言中最重要也最让初学者困惑的符号之一。它是取地址运算符——&age的意思是“变量age的内存地址”。scanf需要知道把读取到的数据存到哪里,所以需要传地址,而不是传值。
为什么需要 &?
如果你把 age 直接传给 scanf,scanf 拿到的是 age 里存的值(可能是垃圾值),它无法知道 age 这个变量在内存中的位置,就没办法把数据写进去。取地址运算符 & 让 scanf 能精确修改你的变量。
在 Python 中,age = int(input()) 看起来简单,是因为 Python 解释器在背后自动帮你处理了内存分配和地址传递。C 把这些细节全部暴露给你,让你自己控制。
读取不同类型的数据
int age;
float height;
char grade;
printf("请输入年龄、身高(厘米)和等级(用空格分隔):");
scanf("%d %f %c", &age, &height, &grade);
printf("年龄:%d,身高:%.1f,等级:%c\n", age, height, grade);
输入:28 175.5 A,三个值被空格分隔,scanf 自动解析。
scanf 的常见陷阱:
- 忘记写 &:
scanf("%d", age);会导致程序崩溃或写入错误的内存位置。这是 C 初学者第一常见的错误。 - 输入格式不匹配:如果你用
%d但用户输入了字母,scanf会失败,变量保持原值不变。检查scanf的返回值可以判断读取是否成功(scanf返回成功读取的项数)。 - 缓冲区问题:输入后按下的回车键会留在输入缓冲区中。如果之后要读取字符,可能会读到这个换行符。后面讲字符串处理时会详细讨论。
六、运算符
C 语言的运算符和 JavaScript/Python 基本一致,但有几个需要注意的点。
算术运算符
| 运算符 | 含义 | 示例 | 结果 |
|---|---|---|---|
+ |
加法 | 10 + 3 |
13 |
- |
减法 | 10 - 3 |
7 |
* |
乘法 | 10 * 3 |
30 |
/ |
除法 | 10 / 3 |
3(不是 3.333!) |
% |
取余数 | 10 % 3 |
1 |
C 语言除法的坑:整数除法得到整数!
这是从 Python 转过来的开发者最容易踩的坑:
int a = 10;
int b = 3;
int result = a / b;
printf("%d\n", result); // 输出 3,不是 3.333!
在 C 中,两个整数相除,结果还是整数(小数部分被直接丢弃,不是四舍五入)。这和 Python 3 不同(Python 3 的 / 总是返回浮点数,// 才是整除)。
要得到浮点数结果,需要至少把其中一个操作数变成浮点数:
float result = 10.0 / 3; // 3.333333
float result2 = (float)10 / 3; // 3.333333,强制类型转换
float result3 = 10 / 3.0; // 3.333333
比较运算符
和 JavaScript/Python 完全一致:==、!=、>、<、>=、<=。
int a = 10, b = 20;
printf("%d\n", a == b); // 0(C 中用 0 表示 false)
printf("%d\n", a < b); // 1(C 中用 1 表示 true)
注意:C 语言没有 true 和 false 关键字(C99 引入了 stdbool.h,但原始 C 用 0 表示假,非 0 表示真)。
逻辑运算符
| 含义 | JavaScript | Python | C |
|---|---|---|---|
| 并且 | && |
and |
&& |
| 或者 | || |
or |
|| |
| 取反 | ! |
not |
! |
C 的逻辑运算符和 JavaScript 完全一样——用符号而不是英文单词。这和 Python 的 and/or/not 不同。
自增和自减运算符
C 语言有 ++ 和 -- 运算符,和 JavaScript 一样:
int x = 10;
x++; // x 变成 11
x--; // x 变回 10
// 前置和后置的区别
int a = 5;
int b = a++; // b = 5, a = 6(后置:先赋值,再自增)
int c = ++a; // c = 7, a = 7(前置:先自增,再赋值)
Python 没有 ++ 运算符,需要用 x += 1。
七、类型转换
C 语言中,类型转换分为隐式转换和显式转换。
隐式类型转换(自动)
当表达式中同时出现不同类型的操作数时,C 会自动把“小”类型转成“大”类型:
int a = 10;
double b = 3.5;
double result = a + b; // a 被自动转成 10.0,result = 13.5
自动转换的规则:char → int → float → double(从“小”到“大”)。
显式类型转换(强制)
在值前面用括号指定目标类型:
int a = 10, b = 3;
float result = (float)a / b; // 把 a 强制转成 float,结果 3.333333
和 Python 的 float(a)、JavaScript 的 Number(a) 概念相同,语法不同。
八、综合演示:一个简单的计算器
下面这段代码综合运用了变量声明、输入输出、运算符:
#include <stdio.h>
int main() {
int num1, num2;
printf("===== 简单计算器 =====\n");
printf("请输入第一个整数:");
scanf("%d", &num1);
printf("请输入第二个整数:");
scanf("%d", &num2);
printf("\n--- 计算结果 ---\n");
printf("%d + %d = %d\n", num1, num2, num1 + num2);
printf("%d - %d = %d\n", num1, num2, num1 - num2);
printf("%d * %d = %d\n", num1, num2, num1 * num2);
// 除法:注意整数除法和浮点数除法的区别
printf("%d / %d = %d(整数除法)\n", num1, num2, num1 / num2);
printf("%d / %d = %.2f(浮点数除法)\n", num1, num2, (float)num1 / num2);
printf("%d %% %d = %d\n", num1, num2, num1 % num2);
return 0;
}
注意 printf 里输出 % 需要写成 %%——因为 % 被 printf 当作格式占位符的起始字符。
九、本篇动手练习
练习 1:年龄计算器
新建 practice2-1.c,让用户输入出生年份和当前年份,输出用户的年龄。
练习 2:温度转换
新建 practice2-2.c,让用户输入摄氏温度,转换成华氏温度(华氏度 = 摄氏度 × 9/5 + 32)并输出。注意:9/5 在 C 中是整数除法,结果是 1!思考怎么得到正确的浮点数结果。
练习 3:圆的面积和周长
新建 practice2-3.c,让用户输入圆的半径(可以是小数),输出圆的面积(π × 半径²)和周长(2 × π × 半径)。结果保留 2 位小数。π 可以写 3.14159。
练习 4:整数溢出实验
新建 practice2-4.c,声明一个 int 变量,赋值为 2147483647(int 的最大值),然后给它加 1,输出结果。观察溢出的现象——结果会变成一个很大的负数。这就是整型溢出。
十、本篇小结
这一篇你系统学习了 C 语言的基础语法:
- 变量声明:必须指定类型,类型终身不变。声明时最好立即初始化,否则变量里是垃圾值。
- 基本数据类型:
int(整数,4 字节)、float(单精度浮点,4 字节)、double(双精度浮点,8 字节)、char(字符,1 字节)。sizeof查看类型大小。 printf格式化输出:%d整数、%f浮点数、%c字符、%s字符串。%.2f保留两位小数。scanf输入:第二个参数必须加&取地址符。这是初学者最容易犯的错误。- 运算符:算术、比较、逻辑运算符和 JavaScript 基本一致。整数除法的结果是整数(小数被丢弃),这是和 Python 最大的不同。
- 类型转换:隐式转换自动进行(
int → double),显式转换用(类型)值语法。
下一篇,我们学习 C 语言的控制流——条件判断和循环。你会看到 C 的 if、for、while 和你熟悉的 JavaScript 几乎一样,但有些细节需要留意。
下一篇预告
下一篇——《条件判断与循环——if、for、while》:if/else if/else 分支结构、for 循环(C 的经典三要素写法)、while 和 do...while 循环、break 和 continue、以及 switch 语句。同时对比 JavaScript 和 Python 中对应的写法。
C/C++ 零基础入门,每周更新。












暂无评论内容