C++ 自学教程 LearnCPP 第1.3章 初窥变量,初始化,和赋值

C++ 自学教程 第1.3章 初窥变量,初始化,和赋值


前言: 从这一节开始,每一节教程的最后可能附上一个小测试。我不会用CSDN的做那种点击再显示的功能,就选择把答案加个几行放在最后了。有什么不理解的也欢迎留言探讨。阅读愉快。


对象

C++程序创建,读取,改变,和销毁对象。对像(object)是一段被储存某数据的内存。你可以把对象想象为一个邮箱,或者一个小房间。你可以用它来存储和读取信息。所用电脑都有程序可使用的记忆,也叫随机获取内存(RAM)。当一个对象被定义时,一段内存会被留用给它。

大部分我们在C++中使用的对象以变量的形式出现。

变量

一个叙述语句,比方x=5; 就是个最简单的例子。就像你所猜想的那样,我们把5赋值给了x。那什么是x呢?一个变量。

C++中,变量(variable)也就是一个有名字的对象。

在这一小节里,我们只考虑整数变量。整数(integer)就是一个不带小数的数字,比如-12,-1,0,4。整数变量就是一个存储整数的变量。

为了生成一个变量, 我们通常使用一种特别的声明叙述(被叫做定义)。举个栗子,

int x;

当CPU执行这行叙述时,RAM中一段内存会被分配给x(也就是初始化)。假设变量x被赋给内存位140。无论在哪个叙述或表达式中看见了x,程序知道它应该查找内存位140来获取x的值。

最常见的对变量执行的操作就是赋值。我们使用赋值符号,也就是常见的等号= 来给变量赋值。比如:

x = 5;

当CPU执行这个叙述时,它的意思等价于“将数值5放到内存位140去。”
后面的程序可以用std::cout把这个数值显示在屏幕上:

std::cout << x;  // prints the value of x (memory location 140) to the console

左值和右值

在C++中,变量是左值的一种。左值(l-value)是在内存中有固定地址的数值。因为所有变量都有固定地址,所有变量都是左值。左值的名字得名于它们必须被放置在赋值符号的左侧。当我们赋值的时候,等号左侧必须是一个左值。也就是说,类似于5=6的叙述会导致编译错误,因为5不是一个左值。数字5没有固定内存,所以不能把别的值赋给它。5就是5,它的数值也不能被改写。当某数值被赋给了一个左值,这个左值现有的数值就被覆盖了。

与左值相反的是右值(r-value)。右值就是指没有固定地址的数值。常见的右值有常数(比如5),表达式(比如2+x)。右值通常具有临时性,并在执行完其所在的叙述语句后会被销毁。

下面是几个赋值叙述语句:

int y;      // define y as an integer variable
y = 4;      // r-value 4 evaluates to 4, which is then assigned to l-value y
y = 2 + 5;  // r-value 2 + r-value 5 evaluates to r-value 7, which is then assigned to l-value y

int x;      // define x as an integer variable
x = y;      // l-value y evaluates to 7 (from before), which is then assigned to l-value x.
x = x;      // l-value x evaluates to 7, which is then assigned to l-value x (useless!)
x = x + 1;  // l-value x + r-value 1 evaluate to r-value 8, which is then assigned to l-value x.

让我们仔细看看最后一个赋值语句,这一句比较难理解。

x = x + 1;

在这句叙述中,变量x被使用了两次。在赋值符号左侧,x是一个左值变量(带有内存的变量),它指代了某个数值。在赋值符号右侧,x中存储的数值被提取出来(这里等于7)。当程序执行这句叙述时,它等价于:

x = 7 + 1;

显而易见,最终数值8被赋给了变量x。

在现在这个阶段,你不用考虑太多左值或者右值,不过我们以后还会再探讨他们。

这里的重点在于,赋值符号的左侧必须有个能代表内存的东西。赋值符号的右侧都会被估值为一个数字。

初始化和赋值

C++新手很可能会将初始化和赋值这两个关联概念搞混。
在某个变量定以后,它可以通过赋值运算被赋值:

int x; // this is a variable definition
x = 5; // assign the value 5 to variable x

C++允许你在定义一个变量的同时给它赋值,这个叫做初始化(initialization)

int x = 5; // initialize variable x with the value 5

一个变量只有在定义时才能被初始化。

尽管这两个概念很近似,他们最终能得到的结果也很相似。我们以后会看到有些变量必须被初始化而不支持赋值。所以这里先预先明确他们的区别。

规则:当给一个变量初始值时,优先使用初始化而不是赋值。

未被初始化的变量

与许多编程语言不同,C++不会自动给大部分变量赋值。所以当一个内存位被分配给了一个变量,这个变量的默认值时之前存储在这个内存里的任意值!一个未被初始化的变量又被称为.. 未被初始化的变量(uninitialized variable)。(不好意思这里确实是一句废话。。)

注意,有些编译器,比如Visual Studio,在调试模式下会初始化内存,但这不会在发行版本(release build configuration)中初始化。

使用未初始化的变量有时会导致无法预测的结果,比如:

#include "stdafx.h" // Uncomment if Visual Studio user
#include <iostream>

int main()
{
    // define an integer variable named x
    // 定义一个名为x的整数变量
    int x; // this variable is uninitialized

    // print the value of x to the screen (who knows what we'll get, because x is uninitialized)
    // 把x的值输出到屏幕上
    std::cout << x;

    return 0;
}

在这个例子中,电脑会把某个未被使用的内存位分配给x。并把里面存储的数值发送给std::cout,然后把这个数值显示出来。不过会打出哪个值呢?答案是“天晓得!”这个数字可能你每次运行的时候都不一样。作者使用visual studio 2013编译器运行这段程序时,得到的结果是7177728,第二次得到的5277592

如果你想要试试自己运行这个程序,确保你是用的是发行模式。否则上述程序会输出你编译器的初始内存值(visual studio用的是-858993460)。

如果你的编译器拒绝运行这个程序,并报错说x未被初始化,下面给出了一个绕开这个报错的方法:

// #include "stdafx.h" // Uncomment if Visual Studio user
#include <iostream>

void doNothing(const int &x)
{
}

int main()
{
    // define an integer variable named x
    int x; // this variable is uninitialized

    doNothing(x); // make compiler think we're using this variable

    // print the value of x to the screen (who knows what we'll get, because x is uninitialized)
    std::cout << x;

    return 0;
}

使用未初始化的变量是新手程序员常犯的错误。不幸的是,这个错误也是最难被调试的错误之一。因为很可能你的程序还是可以顺利运行,并且结果可能看上去还比较合理(如果刚好内存中存储的数字是0之类的)。

幸运的是,现代编译器探测到这些未被初始的变量时,会在编译时提供相关的警告。比如说用visual studio 2005运行上述程序时就会得到以下错误信息:

c:vc2005projectstesttesttest.cpp(11) : warning C4700: uninitialized local variable ‘x’ used

这里的最佳规范是初始化你的所有变量。这确保了你的变量总能得到一个固定值,这样更利于编译。

规则:确保你的所有变量都是已知值(无论是用初始化还是赋值)。

未定义行为

使用未被初始化的变量是我们接触到的第一个未定义行为(undefined behavior)。未定义行为也就是执行一段未被语言完整定义的程序得到的结果。在这个例子里,C++无法规定当你使用一个没有已知值的变量时会得到什么结果。所以,当你的程序这么做的时候,未定义行为就发生了。

执行未定义行为的代码通常有以下几个特征:
• 你的程序总是生成不正确的结果
• 你的程序每次执行都会得到不同的结果
• 你的程序得到不一致的结果(有时候对,有时候错)
• 你的程序好像前面运行的很顺利,但后来得到的结果不对
• 你的程序崩溃了,或者立即崩溃或者后来崩溃
• 你的程序在一些编译器上可用,在另一些上不可用
• 你的程序一开始可以用,但后来在一些无可紧要的改动后无法编译了

或者,你的程序也最终生成了正确结果。未定义行为的本质是你总是不能确定最后的结果是什么,无论是每次都是这样还是这是不是因为你改变了别的东西。

如果你编写C++的时候不够小心,很多情况下都可能导致未确定行为。我们会确保在后续课程标明这样的点。留心类似的例子,并确定你不会犯这样的错误。

规则:注意规避可能导致未定义行为的情况。


小测试:
这些程序最终会在屏幕上输出什么?

int x = 5; // this is an initialization
x = x - 2; // this is an assignment
std::cout << x << std::endl; // #1

int y = x;
std::cout << y << std::endl; // #2

// x + y is an r-value in this context, so evaluate their values
std::cout << x + y << std::endl; // #3

std::cout << x << std::endl; // #4

int z;
std::cout << z << std::endl; // #5






~
~
~




1) 3
2) 3
3) 6
4) 3
5) 结果不确定


说明: 这系列笔记是基于网上一个英文教程LearnCPP

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值