Kodewick
第 2 课,共 30 课目录

变量和 auto

第 2 课,共 30 课 · 第 1 部分 · 起步 · 约 15 分钟

程序要记住一些东西:考试的分数、商品的价格、顾客的名字。变量就是一个有名字的格子,里面放一个值。在 C++ 里,用变量之前要说清楚两件事:它叫什么,放的是哪种值。

main.cpp
1#include <iostream>2 3int main() {4    int score = 90;5    std::cout << "分数:" << score << '\n';6    return 0;7}
输出
分数:90

int score = 90; 的意思是:要一个放整数(int)的格子,名字叫 score,先放进 90。std::cout << score 显示的是格子里的值,不是 score 这几个字母。

行尾的 '\n' 用的是单引号:它是一个字符,和 "\n" 一样会换行。下面马上会讲字符。

声明和赋值

int stock; 是声明变量:告诉编译器有这么一个变量,它放整数。stock = 12; 是赋值:往格子里放一个值。两步可以分开写,也可以像上面那样合成一行。

main.cpp
1#include <iostream>2 3int main() {4    int stock;5    stock = 12;6    std::cout << "库存:" << stock << '\n';7    stock = 7;8    std::cout << "库存:" << stock << '\n';9    return 0;10}
输出
库存:12
库存:7

赋值可以做很多次,新值换掉旧值。C++ 里的 = 不是「等于」,而是「把右边的值放进左边的变量」。点单步,看 stock 怎么从 12 变成 7。

先猜一猜

这段程序显示什么?

1#include <iostream>2 3int main() {4    int a = 5;5    int b = a;6    a = 9;7    std::cout << b << '\n';8    return 0;9}

几种基本类型

每个变量都有固定的类型,声明时写在名字前面,以后不能改。先认识最常用的五种:

类型放什么例子
int整数90、-3、0
double带小数点的数4.5、-0.25
char一个字符,写在单引号里'A'、'7'、'\n'
bool真或假true、false
std::string一串文字,写在双引号里"小林"、"苹果"

std::string 也来自标准库,要 #include <string>。一条 cout 语句可以连着显示好几个变量:

main.cpp
1#include <iostream>2#include <string>3 4int main() {5    std::string name = "小林";6    int count = 3;7    double price = 4.5;8    char size = 'M';9    bool paid = true;10    std::cout << name << " 买了 " << count << " 件,单价 " << price << '\n';11    std::cout << "尺码:" << size << ",已付款:" << paid << '\n';12    return 0;13}
输出
小林 买了 3 件,单价 4.5
尺码:M,已付款:1

cout 显示 double 时不会补多余的 0,4.5 就显示 4.5。bool 显示成 1(真)或 0(假);想显示成 true / false 怎么写,第 6 课讲。char 一次只放一个英文字母、数字或符号,汉字要放进 std::string。

先赋值,再使用

声明了变量却没给它值,格子里是什么?C++ 不管:里面可能是任何数,这次和下次还可能不一样。用这样的值是未定义行为。在普通的电脑上,程序会照样跑下去,显示一个莫名其妙的数。我们的引擎会停在出事的那一行,告诉你是哪个变量:

main.cpp
1#include <iostream>2 3int main() {4    int total;5    std::cout << "总数:" << total << '\n';6    return 0;7}
输出
总数:
use of uninitialized value

发生了什么: 停在第 5 行:「total」还没有赋值就被用了。真的 C++ 里这会是一个乱数(每次运行都可能不一样)。

改法很简单:声明的时候就给它一个值,比如 int total = 0;。std::string 不一样:不给值,它就是一个空字符串 "",可以放心用。

小技巧: 声明 int、double 这些变量时顺手给它一个值,就不会犯这个错。

常量 const

有些值定下来就不该再变,比如一周的天数。声明时在前面加 const,它就成了常量;以后谁想改它,编译器都不答应:

main.cpp
1#include <iostream>2 3int main() {4    const int DAYS_IN_WEEK = 7;5    std::cout << "一周有 " << DAYS_IN_WEEK << " 天\n";6    DAYS_IN_WEEK = 8;7    return 0;8}
输出
main.cpp: In function 'int main()':
main.cpp:6:18: error: assignment of read-only variable 'DAYS_IN_WEEK'
    6 |     DAYS_IN_WEEK = 8;
      |     ~~~~~~~~~~~~~^~~

read-only variable 是「只读的变量」:只能读,不能改。常量常用大写字母和下划线起名,一眼就能和普通变量分开。去掉最后那次赋值,程序就能运行了。

auto:让编译器推出类型

写 auto 代替类型,编译器会看 = 右边的值,推出变量是什么类型:

main.cpp
1#include <iostream>2 3int main() {4    auto count = 3;5    auto price = 4.5;6    auto grade = 'A';7    auto total = price * count;8    std::cout << count << " " << price << " " << grade << " " << total << '\n';9    return 0;10}
输出
3 4.5 A 13.5

3 是整数,所以 count 是 int;4.5 带小数点,price 是 double;'A' 是字符,grade 是 char;price * count 的结果是 double,total 也是。点单步,看每个变量出现时的值。

auto 不是「什么都能放」:类型在声明的那一刻就定死了。

先猜一猜

这段程序显示什么?

1#include <iostream>2 3int main() {4    auto people = 3;5    people = 3.9;6    std::cout << people << '\n';7    return 0;8}

int、double 这种短类型,这门课照样写出来,读起来更清楚。以后遇到很长的类型名,auto 就很省事了。

注意: auto name = "小林"; 推出来的不是 std::string,而是 C 风格的字符串。要字符串,就写 std::string name = "小林";。

花括号初始化

给变量初始值还有一种写法:把值放在花括号里,int score{90};。它和 = 90 的结果一样,但多了一道检查:值放不进去,编译器就报错,而不是悄悄丢掉一部分。

main.cpp
1#include <iostream>2 3int main() {4    int people{3.9};5    std::cout << people << '\n';6    return 0;7}
输出
main.cpp: In function 'int main()':
main.cpp:4:16: error: narrowing conversion of '3.8999999999999999e+0' from 'double' to 'int' [-Wnarrowing]
    4 |     int people{3.9};
      |                ^~~

narrowing conversion 是「变窄的转换」:double 的 3.9 放进 int 要丢掉小数,花括号不允许。(报错里的 3.8999999999999999e+0 就是 3.9:大多数小数在电脑里存得不完全准。)这门课里,普通变量用 =;后面讲 std::vector 这类容器时会用到花括号。

起名的规矩

变量名由字母、数字和下划线 _ 组成,还有几条规矩:

规矩可以不行
只用字母、数字和 _total_pricetotal-price
不能以数字开头day22day
不能有空格max_scoremax score
不能用 C++ 自己的词countint

大写和小写是不同的字母,score 和 Score 是两个变量:

main.cpp
1#include <iostream>2 3int main() {4    int score = 90;5    int Score = 60;6    std::cout << score << " 和 " << Score << '\n';7    return 0;8}
输出
90 和 60

能这么写,不代表应该这么写:两个名字只差大小写,很容易看错。名字要说清楚它放的是什么:price 比 p 好,max_score 比 ms 好。

练一练

写好代码,点检查。提示随便看,实在想不出来再看答案。

练习 1

一件商品

声明三个变量:std::string 的 name 是 "牛奶",double 的 price 是 6.5,int 的 stock 是 20。用它们显示 牛奶:6.5 元,还剩 20 瓶。

要显示
牛奶:6.5 元,还剩 20 瓶
exercise1.cpp
1#include <iostream>2#include <string>3 4int main() {5 6    return 0;7}
输出
点「运行」或按 Ctrl+Enter
练习 2

用 auto 算总价

用 auto 声明 total,值是 price * count,然后显示 总价:13。

要显示
总价:13
exercise2.cpp
1#include <iostream>2 3int main() {4    double price = 6.5;5    int count = 2;6 7    return 0;8}
输出
点「运行」或按 Ctrl+Enter
练习 3

修好它:放不进去的价格

这段程序编译不过。改好它,让它显示 价格:19.9。

要显示
价格:19.9
exercise3.cpp
1#include <iostream>2 3int main() {4    int price{19.9};5    std::cout << "价格:" << price << '\n';6    return 0;7}
输出
点「运行」或按 Ctrl+Enter

这一课学会了

  • 变量先声明再用:int stock; 声明,stock = 12; 赋值,也可以合成 int stock = 12;。
  • = 是把右边的值放进左边的变量;再赋值,新值换掉旧值。
  • int 放整数,double 放小数,char 放一个字符,bool 放真假,std::string 放一串文字。
  • 一条 cout 语句用几个 << 就能连着显示几样;bool 显示成 1 或 0。
  • 用没赋过值的 int 是未定义行为;声明时就给它一个值。
  • const 让变量变成常量,改它会编译错误。
  • auto 让编译器从右边的值推出类型,类型推出来就固定了。
  • 花括号初始化 int n{3}; 不允许变窄,int n{3.5} 编译错误。
  • 名字用字母、数字和 _,不以数字开头,不用 C++ 自己的词,大小写不同。