前言
程序由数据和逻辑两部分组成.数据有两个层面上的含义:程序员角度他是一种客观存在的事物,比如屏幕上看见的一个点,一个图标,或者看不见的比如地址,函数,类等等.在硬件的角度,数据是寄存器或者寄存器的组合."数据"是一种"静态"的存在.而"逻辑"(或者需求,或者函数)需要通过数据的变化来展现.
数据的表示
从几个层面来看数据的表示
数据最重要的两个属性是地址和数据类型.变量和值相对没那么重要(当程序运行后传入的值可能会对程序运行结果产生影响).
变量
所谓"变量",有两层含义:一是他是可以变化的量,取决于给他的赋值.
二他是某个内存地址的标识符,所以变量在知道数据地址的前提下,并不是必须存在的.---因为可以用地址(指针)来表示变量. 但是指针名和变量名的意义是相同的:让程序员清楚知道他代表的数据的含义以及占据的内存空间(基本数据类型的变量).例如:
double money; //第1行
int number=10; //第2行
int *p=new int{20}; //第3行
第1行的写法: 数据类型 变量名;
程序员从中获得的信息:
新开辟了一块内存空间,占8个字节,表示money.内存空间在哪块未知;具体地址未知.
第2行写法:数据类型 变量名=值;
信息:新开辟了内存空间,占4个字节,表示number,赋值10;同样内存空间和具体地址未知.
第3行的写法: 指针类型 指针名=new 数据类型{值}
信息:在堆空间开辟了一块内存,大小4个字节,赋值20;在其他语句中可以用*p取得该地址值.
内存空间
内存空间为程序分配了三块:一是自动存储区,给自动变量,又被称为栈区,特点:后进先出.函数执行完毕后自动释放; 二是静态存储区,给静态变量:特点:在程序运行期间一直存在. 三是动态存储区,给new分配的内存空间,特点:可以用delete释放.
数据类型
数据类型可分为基本数据类型(内置数据类型)和复杂数据类型.复杂数据类型一般指结构和类.结构和类里包含基本数据类型成员或其他结构成员,类对象成员. 复杂结构类型和成员之间是一种包含关系.例如:
class person{
std::string name;
int age;
}
一个表示"人"的类,用string对象表示名称,用一个int变量表示年龄.
程序的组织
程序由多个文件所组成,文件又称作"翻译单元".每个翻译单元由头文件.h和源文件.cpp组成.为什么要这样设计呢?有利于分工.比如每个文件里明确完成什么样的工作,再交由程序员完成.
文件内定义了数据类型和函数,常量.---和类有着相同的组成
其中main()函数所在的文件称为"主文件",他是程序的入口.文件之间的数据默认不可见.通过预处理指令"#include+文件名",使其他文件的内容可见,又称为作用域扩展.
变量分类及作用域
1.变量有什么样的作用?
变量是变化的量,他起的作用是传递数据. 变量一定有数据类型.相同数据类型的变量才可以赋值.
变量和函数是紧密联系在一起的.变量用得最多的就是接收函数返回值和传入形参.在初学时常常为怎样传入参数而苦恼.有个简单的方法:形参是否能"等于"将要传入的变量.例如:
#include<iostream>
void show(const int* ivalue);
int main() {
using namespace std;
int a = 10;
int b = 20;
int* c = &b;
show(&a);
show(c);
}
void show(const int* ivalue) {
std::cout << *ivalue << std::endl;
}
上述代码中形参类型为const int *,形参是ivalue. 以下赋值成立:
const int* ivalue=&a; const int* ivalue=c;
所以可以把&a和c传给形参ivalue
---------本例是为了简要说明,实际上不会这样用.一般说来传指针表示要传数组或者数据集合,单个数据把值传进去即可.这里的形参应写成const int ivalue,传整型常量如3或者整型变量a,b都可以.
#include<iostream>
void show(const int ivalue);
int main() {
using namespace std;
int a = 10;
int b = 20;
int* c = &b;
show(a);
show(3);
show(*c);
}
void show(const int ivalue) {
std::cout << ivalue << std::endl;
}
2.作用域的概念
作用域指能被程序访问到的区域."在某个作用域内"表示数据可见可用.否则要加上作用域访问符"::"
3.变量分类
变量分为:全局变量,全局静态变量,临时变量,局部静态变量这几种.用得最多的是临时变量.
----这几种叫法沿用了C语言. 书面语言叫外部链接,内部链接,无链接等
1>全局变量
作用:在函数(一般是主文件中的函数)之间传递数据.作用域从定义位置到文件结束.
全局变量一般放在主文件的main函数之前.但小程序通常用main函数里开始部分定义,即main函数的临时变量来代替.如果全局变量用得比较多,可单独放到一个文件,再用预处理指令#include包含进主文件.
全局变量的const形式,一般叫做全局常量,是代替字面常量的符号常量,好处是避免文件中的硬编码以及增加程序可读性.
2>全局静态常量
作用:在文件内部的函数间传递数据.
当文件被包含入主文件或其他文件时,不可使用. 全局静态变量容易产生混淆,可以不用.
3>临时变量
作用:在函数内部传递数据.
作用域从定义到代码块结束(),函数调用结束后自动释放内存空间.
4>局部静态变量
作用:在调用函数间传递数据.
最常见的用法是在函数内部定义一个静态变量记录调用次数.
名称空间
当有多个文件加入程序,这些文件可能是由不同厂商提供,可能产生数据同名的情况.如果不加限制,则同名数据(类,函数)会产生冲突 ,导致不希望发生的结果.因此C++加入了名称空间namespace来解决这种情况.
定义:namespace{},在大括号里加入数据类型定义或者函数定义.
---说明:名称空间具有开放性,即可以在多个文件中使用同一个名称的名称空间.但为了方便管理,通常把名称空间放进一个文件里.
data.h
namespace myNameSpace{
struct mystruct{
double money;
int name;
}
void fun();
}
data.cpp
#include<iostream>
#include"data.h"
void fun(){
std::cout<<"it's a fun"<<std::endl;
}
main.h
#include<iostream>
#include"data.h"
int main(){
using myNameSpace::mystruct //using声明结构类型
using myNameSpace::fun //using声明函数
mystruct ms={100000000.00,"good"} //使用结构类型创建结构数据
fun(); //调用函数
}
using声明表示当前文件获得了数据类型或者函数的使用权,在作用域中不能有其他同名数据出现,否则不能通过编译. 通常推荐采用using声明来表明数据.
另外有一种格式叫using编译指令:
using namespace + 名称空间名;
//他的好处是方便,可以不用一个个using声明,但他不区分全局命名空间,局部变量,意思是在其使用数据处,可以定义其他同名变量,容易造成混淆.
自定义名称空间
using声明似乎解决了所有问题,但他不能避免过长的声明---如果需要声明的数据过多,会显得繁杂.所以有一种方法,就是自定义一个命名空间,然后用using编译指令导入到主文件中.
自定义名称空间可以使用using声明和using编译指令导入其他命名空间的数据或者整个命名空间.
mydata.h
#include<iostream>
#include"mydata2.h"
namespace myNameSpace {
using namespace otherNameSpace; //包含其他命名空间
using std::cout; //声明cout
using std::endl; //声明endl
}
mydata2.h
#include<iostream>
namespace otherNameSpace {
void fun() {
std::cout << "it's ok" << std::endl;
}
}
main.h
#include<iostream>
#include"mydata.h"
int main() {
using namespace myNameSpace; //使用using编译指令导入整个自定义命名空间
cout << "hello world" << endl;
fun();
}
---说明:按C++ Prime Plus Edition 6th上的写法会报错---把两个命名空间myNameSpace和OtherNameSpace放到一个文件"mydata.h"里在Vs里不可行.可能是VS版本已经不支持这种写法.但是问题不大,多写一个文件就解决了.
使用using编译指令导入命名空间的写法是不被推荐的,因为他可能会造成数据混淆.所以在用这种写法的时候,最好是程序员清楚的知道具体情况.或者不在主程序里另外使用数据.好处是程序看起来简洁. 实际运用中可以采用using编译指令和using声明相结合,根据实际情况使用.