C++基础——使用变量

C++基础——使用变量

了解变量使用之前,除了知道变量的基本概念和定义之外,
还需要先了解一下关于内存存储的基本概念

在c++的内存结构中,一共有五个区域,简单讲一下

#堆存储区: 自动释放 先进后出 定义 类名 变量名 = 值; 在所在作用域声明定义,程序离开作用域自动释放 例如:

{
    int a = 10; //定义
} 
//释放
//离开作用域后就被释放了

void p(int a) // a定义
{
    std::cout << a << std::endl; // a释放
}
通常就是在代码块里使用,再就是函数参数。
// 自动释放是理解了,先进后出再说一下

例如:
class A {};
class B {};

{
    A a;
    B b;
}

// 构造和析构调用的顺序是 A() B() ~B() ~A()
这个就是先进后出

指针和数组的应用
指针变量表示的是内存的地址,既然地址都是一个无符号的64位数字,为啥还会有类型的区分呢?
主要作用就是指针的遍历
例如
int a[3] = {1,2,3};
int* p = a;

for (int i = 0; i < 3; i++) {
    std::cout << *p << std::endl;
    p++;
}
// 打印 1,2,3
//这里的p++并不是做的简单的+1处理,而是向下移动一一个int的物理内存地址的大小。


再例如
l

ong*  p = (long*)a;
for (int i = 0; i < 3; i++) {
    std::cout << *p << std::endl; // 这里只能打印1,3 ,在第二次操作的时候会越界
    p++;
}
// 因为一个一次long会往下移动2个int位置,可以尝试打印出内存地址的变化。

// 在std::string 类里面用到了大量的指针遍历数组的方式,可以去看一下源码,这个非常重要。

#堆存储区:手动申请 手动释放
定义 类名* 变量名 = new 类名()
堆存储区的使用是c++最头痛的问题之一,释放早了容易崩溃,释放晚了容易导致漏掉。
还有深拷贝和浅拷贝的问题。不知道会不会有人把指针和堆存储区搞混了,这里再区分一下。
例如
A a;
A* p = &a;
// A() ~A() 这里的A* p只是一个指针变量,\
    存放在栈存储区,没有调用A(),相当于一个uint64_t类型。会自动释放
A* p = new A();
delete p;
// A() ~A() 这里的p是new运算符的返回值,保存着申请的堆空间的内存首地址

这里的p都是表示的地址,区别就在于一个是栈空间的地址,一个是堆空间的地址

#代码存储区 二进制数据,存放着函数的代码
这部分存储区主要存储的就是函数,定义一个类的话,类没必要为每个函数都申请空间。
毕竟函数不是变量,只是一个方法或者接口,不会改变的。

#全局存储区 存放着全局变量 常量 静态变量
类内的静态变量也不会占据类的大小,存放在全局存储区,只初始化一次
全局存储区,在代码块外部定义的变量,供全局使用。
常量存储区主要存放着用 #define, enum, 定义的常量 \
        关于常量需要知道的是 const 定义的变量虽然是常量,但是当它不是全局变量的到时候\
        存放在栈里面

#字符串存储区 相同的字符串类型,都公用一段内存数据
例如
 std::cout << &("hello") << " " << &("hello") << std::endl;
// 最终看到的结果是相同的,说明先后两次定义的字符串是用的同一个地址

讲完存储区之后,就可以看一部份实战的东西了
##常量符号的使用 const
const 的主要作用是将一个变量声明成一个常量,这种做法最大好处就是可以保护变量。
常常使用的方式就是和引用一起使用,这几乎成了配套使用的了。
在定义接口的时候,使用引用可以减少一次拷贝,但是引用的缺点是会引起值的改变。\
        这可能会给接口的使用者带来意想不到的危险。
例如
void print(int& a)
{
    std::cout << a ++ << std::endl; //这里的++不一定是有心之举,或许是摁错了
}

// 在笔误的情况下,这种错误是不容易被发现的,当你定义成了const之后,这种错误就会被规避掉
void print(const int& a) 
{
    std::cout << a ++ << std::endl; // error 常量不能改变
}

// 定义全局变量 除了#define之外,还可以用const来定义
例如
#define COUNT 10

const uint32_t count = 10;

uint32_t getCount();

int getIndex();

if (COUNT == getIndex()) {} // 不会有警告
if (count == getIndex()) {} // 警告,无符号和有符号比较

#define 只是做宏替换
const 因为自身有类型,所以也容易在调用的时候,发现一些函数调用的错误。

//建立安全稳定的系统,const绝对是一个神兵利器,作为一个框架或者基础模块的开发者\
    是必不可少的修炼课程

##静态变量的使用 static
将一个变量声明成静态变量,它的初始化就只能进行一次,同时,它的作用域也是确定的。
例如
test.cpp 有 static int a = 10;

main.cpp 无论如何都无法访问到test.cpp static int a;

再就是它静态属性,
class A
{
    public:
        static int a;
};

sizeof(A) = 1 //static int a存放在静态存储区

void p()
{
    static int a = 0;
    a++;
}

// 这个a可以统计这个函数调用的次数

简单的单例模式

class A
{
    private:
        A(){}
        A(const A& a) {}
    public:
        static A& getA()
        {
            static A a;
            return a;
        }
};
> // 可以保证这个类在整个程序中的唯一性,以全局的形式存在
> 
> ##全局变量的使用 extern 全局变量有多种访问方式 其中在.h中定义的变量可以通过 #include 引入.cpp文件,再通过展开的方式被.cpp调用 另一种方式则是在.cpp中定义的全局变量,另一个.cpp想调用,可以通过 extern
> 关键字声明 \
>         声明过后,链接器会在全局变量区查找相同的变量,并访问到对应的内存
> 
> 例如 head.h 定义了 int a = 10; 那么所有#incldue "head.h".cpp文件都可以访问到这个全局变量
再例如
test.cpp 定义了 int a = 10;
main.cpp想访问到这个 int a,则可以先声明 extern int a;\这样这个main.cpp就可以直接访问到这个test.cpp。
同理,函数也可以这样去做,这就可以让我们引起思考

这个全局的类类似于一个单例,但是又比单例更加灵活,可以通过定义这么一些全局变量,实现堆全局的影响。
例如
class Sun
{

};

Sun g_sun;

在main.cpp g_sun.init();

再别的.cpp文件 extern Sun g_sun;
那么这些类就可以调用这个g_sun的时候,不需要管什么时候调用的,因为调用的时候,g_sun的属性和状态就是全局的属性和状态。
就可以模拟一个真实的对象。

关于变量讲的基本就这些了,还有c++11的属性。这些东西等后面单独再讲一下。
把005006看完,关于变量的代码看懂用意一点问题没有。东西就这么些东西,具体怎么用,建议仔细阅读设计模式的一些思想。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小卷同學

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值