C/C++_零基础c++从入门到精通

C/C++_零基础c++从入门到精通问: int a[3]; // 一维数组char b[3][5]; // 二维数组float c[3][5][7]; // 三维数组 比较a+1,b+1,c+1;c[2][3][4]相对数组起始地址的偏移 答:a+1代表a[1]的地址,是一级指针,要去a+1里面…

问:

int a[3];          // 一维数组
char b[3][5];      // 二维数组
float c[3][5][7];  // 三维数组

比较a+1,b+1,c+1;c[2][3][4]相对数组起始地址的偏移

答:a+1代表a[1]的地址,是一级指针,要去a+1里面的内存,只需cout<<*(a+1)即可;

b+1代表b[1]的地址,是二级指针,指向从b[1][0]开始的之后的一段内存,若要取出内容,需要用2个星号,因为是二级指针,**(b+1)代表b[1][0],*(*(b+1)+1)代表b[1][1];

c+1代表c[1]的地址,是三级指针,指向从c[1][0][0]开始的地址,若要取出内容,需要3个星号,因为是三级指针,***c代表c[0][0][0]。我们用cout<<c,cout<<*c,cout<<**c,这三次的输出结果一样,但含义不同;

这里需要注意的一个问题:由于b是char型的,用cout输出跟b有关的信息会有所不同。cout<<**b:输出b[0][0]这个字节,b[0][0]里面保存的是该字节的ASCII码;cout<<*b:输出的是从b[0][0]开始的字符串,到空字符null(ASCII码为0)为止;cout<<b:输出指针b本身的值,即b[0][0]的地址;

我们测试以下语句:

cout<<sizeof(c)<<endl;
cout<<sizeof(*c)<<endl;
cout<<sizeof(**c)<<endl;
cout<<sizeof(***c)<<endl;

得出的结果为:420     140     28    4

c是三级指针,指向整个数组区域,3*5*7=105,105*4=420

*c是二级指针,指向从c[0][0][0]开始到c[0][4][6]结束的一段,5*7=35,35*4=140

**c是一级指针,指向从c[0][0][0]开始到c[0][0][6]结束的一段,7*4=28

***c是指针所指向内容float,sizeof(***c)相当于sizeof(float)

c[2][3][4]地址偏移的计算:2*5*7+3*7+4=95,95*4=380,偏移量为380个字节

问:构造函数与拷贝构造函数相关

答:拷贝构造函数与构造函数一样,若不自定义,会调用默认的函数进行操作,默认的拷贝构造函数可以完成拷贝,默认的构造函数可以完成构造。

一旦自定义了构造函数,就不能调用默认的函数了。比如自定义了带参数的构造函数,这时去使用无参数的构造函数时会报错。构造函数里无语句也可构造对象。

一旦自定义了拷贝构造函数,同样不能调用默认的拷贝构造函数了。与构造函数不同的是,拷贝构造函数里什么都不写,此时完成不了拷贝。拷贝构造函数在以下4种情况调用:1.初始化Cat cat1(cat2);    2.初始化Cat cat1 = cat2;(cat2 = cat1非初始化而是赋值时,不调用拷贝函数,而是调用默认的赋值函数,若Cat类中有new语句,则需要自定义赋值函数,同默认的拷贝函数,默认的赋值函数也是位拷贝)    3.函数参数fun(cat1);     4.函数返回return cat1;

拷贝构造函数也是构造函数,当对象初始化Cat cat1(cat2);此时不调用构造函数,而是调用拷贝构造函数完成构造和初始化的功能。

问:静态成员变量相关

答:在类内的只是静态变量的声明,静态变量的定义必须在类外,声明:static int x;  定义:int CLASSNAME::x = 1;  在类外使用静态变量时,可以用CLASSNAME::x或者对象名.x来调用,对象名1.x对象名2.x是一样的,因为静态变量属于整个类。

问:全局变量和全局静态变量的区别

答:他们都是在全局数据区,唯一一个重要的区别就是,static全局只对当前文件有效,不支持extern被外部引用,在开发中的全局变量应声明为static,防止其他文件同名变量对此变量的使用。

问:返回引用与返回非引用相关

答:若返回局部变量的引用,将会出问题,i和j在函数结束后生存周期到,返回它们的引用得不到想要的结果。

int &Max(int i, int j)
{
  return i>j ? i : j;
}

调用函数时,函数会为 输入的实参建立一个副本,该副本属于临时变量,返回时就返回这个副本,然后将该临时变量释放。

#include <iostream>
using namespace std;
class CText
{
public:
    ~CText()
    {
        cout<<"析构了"<<this<<endl;
    }
};
CText& fRefer(CText &a)
{
    return a;
}
CText fNoRefer(CText &a)
{
    return a;
}

int main(int arge,char*argv[ ])
{
    CText a;
    cout<<"a的地址:"<<&a<<endl;
    cout<<endl<<"------引用类型返回值------"<<endl;
    a=fRefer(a);
    cout<<endl<<"------非引用类型的返回值------"<<endl;
    a=fNoRefer(a);//此处会析构一个与a地址不一样的内存,说明析构的临时变量
    cout<<endl<<"------main结束------"<<endl;
    return 0;
}

参看下面的例子:由于重载运算符=函数返回的不是引用,所以将返回值++没有意义,返回的是临时变量,待该临时变量赋值给别的变量后,这个临时变量的使命就完成了,就被释放了。

class CText
{
public:
    ~CText()
    {
        cout<<"析构了"<<this<<endl;
    }
    CText operator++()
    {
        x++;
        return *this;
    }
    CText operator=(CText &obj)
    {
        x = obj.x;
        return *this;
    }
private:
    int x;
};
int main(int arge,char*argv[ ])
{
    CText a(1),b(2);
    (b = a)++;
    return 0;
}

问:对象在内存中的布局如何

答:这是一个比较大的问题,有许多种情况,这里给出一种最简单的情况

1.类的数据成员之间的间隔是类中最大数据类型的整数倍

2.数据不能跨越间隔存储

3.成员变量的保存顺序与声明顺序有关

class A
{
    char a;
public:
    short b;
    char c;
};

A中short型最大,占2个字节,所以就2字节为基本单位扩展,这里A占6个字节,我们换一下顺序就可以提高利用率:

class A
{
    char c;
    char a;
public:
    short b;
};

这里A占4个字节

当我们考虑继承时,情况又会如何呢?

class A
{
    char a;
public:
    short b;
    char c;
};

class B:public A
{
public:
    int d;
};

A占6个字节,B占12个字节,不要以为A中的私有变量在B中就不会出现

继承时,要按照B的要求进行对齐,B中的int占4个字节,所以要把A占的6个字节补齐为8个字节,内存图如下:

C/C++_零基础c++从入门到精通

今天的文章C/C++_零基础c++从入门到精通分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/54135.html

(0)
编程小号编程小号
上一篇 2023-08-29 17:30
下一篇 2023-08-29

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注