二:C 语言语法基础——变量、数据类型、输入输出

一、回顾与本篇目标

上一篇你写了人生中第一个 C 程序,编译并运行了它。你知道了 C 程序必须有 main 函数,语句以分号结尾,编译是把源代码变成可执行文件的过程。

这一篇我们要正式进入 C 语言的语法学习。如果你已经会 JavaScript 或 Python,你会发现 C 的语法既熟悉又陌生——熟悉的是运算符和表达式(加减乘除都一样),陌生的是变量声明必须指定类型,而且这个类型是终身不变的。

本篇的目标:

  1. 掌握 C 语言中变量的声明和初始化方式
  2. 理解 C 的基本数据类型以及它们占用的内存大小
  3. 学会用 printf 进行格式化输出
  4. 学会用 scanf 获取用户输入
  5. 掌握 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 基本相同:

  • 只能包含字母、数字、下划线。
  • 不能以数字开头。
  • 区分大小写:ageAge 是两个不同的变量。
  • 不能用 C 的关键字(如 intifforreturn 等)。
  • 命名风格:C 社区习惯用下划线命名法——user_nametotal_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 严格区分 intfloat/double
  • Pythonint 理论上有无限精度,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 字节。%zusizeof 返回值的专用格式符(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 intlong 就是 long int。日常开发中,intdouble 是最常用的,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 直接传给 scanfscanf 拿到的是 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 语言没有 truefalse 关键字(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 的 ifforwhile 和你熟悉的 JavaScript 几乎一样,但有些细节需要留意。

下一篇预告

下一篇——《条件判断与循环——if、for、while》:if/else if/else 分支结构、for 循环(C 的经典三要素写法)、whiledo...while 循环、breakcontinue、以及 switch 语句。同时对比 JavaScript 和 Python 中对应的写法。

C/C++ 零基础入门,每周更新。

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容