欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

后台开发面试C++(二)

程序员文章站 2022-06-13 12:41:46
...

目录

指针大小

c++内存分配方式

从静态存储区分配

在栈上创建

从堆上分配

c++中内存泄漏的常见情况

1. 在类的构造函数和析构函数中没有匹配的调用new和delete函数

2. 没有正确地清除嵌套的对象指针

3. 在释放对象数组时在delete中没有使用方括号

4. 指向对象的指针数组不等同于对象数组

c++局部变量可否与全局变量重名

全局变量、局部变量、静态全局变量、静态局部变量的区别

C++extern 作用

C++多重指针

C++中在头文件里定义的变量的作用范围是什么

1 在头文件中定义静态变量

2 在头文件中定义变量,但是不带初始化值。

3 在头文件中定义了带初始化值的变量。


指针大小

#include<iostream>
#include<cstdlib>
using namespace std;
int main()
{
	int a = 1;
	int *p1 = &a;
	cout << "int " << sizeof(p1) << endl;
	float b = 1.23;
	float *p2 = &b;
	cout << "float " << sizeof(p2) << endl;
	double c = 1.3456;
	double *p3 = &c;
	cout << "double" << sizeof(p3) << endl;
	system("pause");
	return 0;
	
 
}

win32:

后台开发面试C++(二)

win64:

后台开发面试C++(二)

32位为4字节,64位为8字节。

c++内存分配方式

从静态存储区分配

内存在程序编译的时候已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。

在栈上创建

在执行函数时,函数内局部变量的存储单元可以在栈上创建,函数执行结束时,这些内存单元会自动被释放。
栈内存分配运算内置于处理器的指令集,效率高,但是分配的内存容量有限。

从堆上分配

亦称为动态内存分配。
程序在运行的时候使用malloc或者new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。
动态内存的生命周期有程序员决定,使用非常灵活,但如果在堆上分配了空间,既有责任回收它,否则运行的程序会出现内存泄漏,频繁的分配和释放不同大小的堆空间将会产生内存碎片。

c++中内存泄漏的常见情况

1. 在类的构造函数和析构函数中没有匹配的调用new和delete函数

两种情况下会出现这种内存泄露:一是在堆里创建了对象占用了内存,但是没有显示地释放对象占用的内存;二是在类的构造函数中动态的分配了内存,但是在析构函数中没有释放内存或者没有正确的释放内存

2. 没有正确地清除嵌套的对象指针

3. 在释放对象数组时在delete中没有使用方括号

方括号是告诉编译器这个指针指向的是一个对象数组,同时也告诉编译器正确的对象地址值并调用对象的析构函数,如果没有方括号,那么这个指针就被默认为只指向一个对象,对象数组中的其他对象的析构函数就不会被调用,结果造成了内存泄露。如果在方括号中间放了一个比对象数组大小还大的数字,那么编译器就会调用无效对象(内存溢出)的析构函数,会造成堆的奔溃。如果方括号中间的数字值比对象数组的大小小的话,编译器就不能调用足够多个析构函数,结果会造成内存泄露。

释放单个对象、单个基本数据类型的变量或者是基本数据类型的数组不需要大小参数,释放定义了析构函数的对象数组才需要大小参数。

4. 指向对象的指针数组不等同于对象数组

 

对象数组是指:数组中存放的是对象,只需要delete []p,即可调用对象数组中的每个对象的析构函数释放空间

指向对象的指针数组是指:数组中存放的是指向对象的指针,不仅要释放每个对象的空间,还要释放每个指针的空间,delete []p只是释放了每个指针,但是并没有释放对象的空间,正确的做法,是通过一个循环,将每个对象释放了,然后再把指针释放了。

c++局部变量可否与全局变量重名

可以重名。在程序中如果出现了相同的两个变量,一个是局部变量,一个是全局变量,编译可以通过,但是打印出的值是局部变量的值,如果想打印全局变量的值的话,在全局变量之前加上“::”就可以了。

#include<iostream>
using namespace std;
int a;      //定义全局变量
int main()
{
    int a = 3;      //定义局部变量并赋值
    cout<<"a = "<<a<<endl;
    ::a = 2;    //给全局变量赋值
    cout<<"a = "<<::a<<endl;
}
输出结果为:
a = 3;
a = 2;

全局变量、局部变量、静态全局变量、静态局部变量的区别

C++变量根据定义的位置的不同的生命周期,具有不同的作用域,作用域可分为6种:全局作用域,局部作用域,语句作用域,类作用域,命名空间作用域和文件作用域。

从作用域看:

全局变量具有全局作用域。全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件需要用extern 关键字再次声明这个全局变量。

静态局部变量具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。

局部变量也只有局部作用域,它是自动对象(auto),它在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用执行结束后,变量被撤销,其所占用的内存也被收回。

静态全局变量也具有全局作用域,它与全局变量的区别在于如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被static关键字修饰过的变量具有文件作用域。这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量。

从分配内存空间看:
全局变量,静态局部变量,静态全局变量都在静态存储区分配空间,而局部变量在栈里分配空间

static 全局变量:改变作用范围,不改变存储位置

static 局部变量:改变存储位置,不改变作用范围

C++extern 作用

文件中定义的全局变量的可见性扩展到整个程序是在链接完成之后,而在编译阶段,他们的可见性仍局限于各自的文件。
编译器的目光不够长远,编译器没有能够意识到,某个变量符号虽然不是本文件定义的,但是它可能是在其它的文件中定义的。
虽然编译器不够远见,但是我们可以给它提示,帮助它来解决上面出现的问题。这就是extern的作用了。 extern的原理很简单,就是告诉编译器:“你现在编译的文件中,有一个标识符虽然没有在本文件或本文件当前位置中定义,但是它是在别的文件中或本文件其它位置定义的全局变量,你要放行!”

C++多重指针

    int ab = 10;
    int *ac = &ab;
    int **ad = &ac;
    cout<<" *ac = " << *ac<<endl;
    cout<<" ac = " << ac<<endl;
    cout<<" ad = " << ad<<endl;
    cout<<" *ad = " << *ad<<endl;
    cout<<" **ad = " << **ad<<endl;

首先来分析一下代码,ab是一个int变量
ac是一个指针,存放了ab的地址,ac的值是一个地址
定义一个多重指针ad,又叫指向指针的指针,把ac的地址赋值给ad

看一下运行结果:

后台开发面试C++(二)

我对*的理解是取值(非初始化时和变量一起使用)。
*ac:取出ac指向的地址存放的值 10
ac存放了一个地址
ad也是一个地址,存放了ac指针的地址
*ad:取出存放的指针ac
**ad:取出*ad指针指向的值,也就是ac指向的值


C++中在头文件里定义的变量的作用范围是什么

根据头文件中变量的定义形式,作用范围有所不同,有如下几种情况:

1 在头文件中定义静态变量

static TYPE var = init_value;
其中= init_value部分可以省略。
等效于在每个引用该头文件的源文件中,定义一个变量名为var, 类型为TYPE的静态全局变量。每个文件中的var变量均归属于本源文件,各文件中的互不相同。
作用域为引用头文件的源文件范围内。

2 在头文件中定义变量,但是不带初始化值。

TYPE var;
这种情况下,相当于定义了一个全局变量var, 同时在所有引用该头文件的源文件中声明。
其作用域为整个项目的所有源文件。
在引用了该头文件的源文件中可以直接使用var, 在没有引用该头文件的源文件中,可以通过
extern TYPE var;
进行声明,从而使用var。

3 在头文件中定义了带初始化值的变量。

TYPE var = init_value;
当项目中,只有一个源文件中引用了该头文件时,等同于在源文件中定义了这个全局变量,可在该文件中使用var。 在其它源文件中可以通过
extern TYPE var;
进行声明,从而使用var。所以这种情况下变量的作用域也是整个项目。
需要注意的是,这种形式一旦在超过一个源文件中引用该头文件,则会按照在不同文件中定义同名全局变量处理,这时会编译出错,自然也就没有作用域的说法了。应该在头文件中声明,在任意一个源文件中定义。