NO.8|C++语言基础|静态变量|局部变量|内联函数|宏函数|i++|++i|new|malloc|const|define|函数指针|指针函数|指针|C++传值|const*|*const

![[Pasted image 20250318220403.png]]

说说静态局部变量,全局变量,局部变量的特点,以及使用场景

参考回答
  1. 首先从作用域考虑:C++里作用域可分为6种:全局,局部,类,语句,命名空间和文件作用域。
    全局变量:全局作用域,可以通过extern作用于其他非定义的源文件。
    静态全局变量 :全局作用域+文件作用域,所以无法在其他文件中使用。
    局部变量:局部作用域,比如函数的参数,函数内的局部变量等等。
    静态局部变量 :局部作用域,只被初始化一次,直到程序结束。
  2. 从所在空间考虑:除了局部变量在栈上外,其他都在静态存储区。因为静态变量都在静态存储区,所以下次调用函数的时候还是能取到原来的值。
  3. 生命周期: 局部变量在栈上,出了作用域就回收内存;而全局变量、静态全局变量、静态局部变量都在静态存储区,直到程序结束才会回收内存。
  4. 使用场景:从它们各自特点就可以看出各自的应用场景,不再赘述

说说内联函数和宏函数的区别

参考回答

区别:

  1. 宏定义不是函数,但是使用起来像函数。预处理器用复制宏代码的方式代替函数的调用,省去了函数压栈退栈过程,提高了效率;而内联函数本质上是一个函数,内联函数一般用于函数体的代码比较简单的函数,不能包含复杂的控制语句,while、switch,并且内联函数本身不能直接调用自身。
  2. 宏函数是在预编译的时候把所有的宏名用宏体来替换,简单的说就是字符串替换 ;而内联函数则是在编译的时候进行代码插入,编译器会在每处调用内联函数的地方直接把内联函数的内容展开,这样可以省去函数的调用的开销,提高效率
  3. 宏定义是没有类型检查的,无论对还是错都是直接替换;而内联函数在编译的时候会进行类型的检查,内联函数满足函数的性质,比如有返回值、参数列表等
答案解析
//宏定义示例  
#define MAX(a, b) ((a)>(b)?(a):(b))  
MAX(a, "Hello"); //错误地比较int和字符串,没有参数类型检查  
//内联函数示例  
#include <stdio.h>  
inline int add(int a, int b) {  
	return (a + b);
} 
int main(void) {  
	int a;  
	a = add(1, 2);  
	printf("a+b=%d\n", a);  
	return 0;  
} 
//以上a = add(1, 2);处在编译时将被展开为:a = (a + b);

1、使用时的一些注意事项:

  • 使用宏定义一定要注意错误情况的出现,比如宏定义函数没有类型检查,可能传进来任意类型,从而带来错误,如举例。还有就是括号的使用,宏在定义时要小心处理宏参数,一般用括号括起来,否则容易出现二义性
  • inline函数一般用于比较小的,频繁调用的函数,这样可以减少函数调用带来的开销。只需要在函数返回类型前加上关键字inline,即可将函数指定为inline函数。
  • 同其它函数不同的是,最好将inline函数定义在头文件,而不仅仅是声明,因为编译器在处理inline函数时,需要在调用点内联展开该函数,所以仅需要函数声明是不够的。
    2、内联函数使用的条件:
  • 内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率 的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。以下情况不宜使用内联:
    (1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。
    (2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。
  • 内联不是什么时候都能展开的,一个好的编译器将会根据函数的定义体,自动地取消不符合要求的内联。

说说运算符i++和++i的区别

#include <stdio.h>  
int main(){  
	int i = 2;  
	int j = 2;  
	j += i++; //先赋值后加  
	printf("i= %d, j= %d\n",i, j); //i= 3, j= 4  
	i = 2;  
	j = 2;  
	j += ++i; //先加后赋值  
	printf("i= %d, j= %d",i, j); //i= 3, j= 5  
}
  1. 赋值顺序不同:++ i 是先加后赋值;i ++ 是先赋值后加;++i和i++都是分两步完成的。
  2. 效率不同:后置++执行速度比前置的慢。
  3. i++ 不能作为左值,而++i 可以
int i = 0;  
int* p1 = &(++i);//正确  
// int* p2 = &(i++);//错误  
++i = 1;//正确  
// i++ = 1;//错误
  1. 两者都不是原子操作

说说new和malloc的区别,各自底层实现原理

参考回答
  1. new是操作符,而malloc是函数。
  2. new在调用的时候先分配内存,在调用构造函数,释放的时候调用析构函数;而malloc没有构造函数和析构函数。
  3. malloc需要给定申请内存的大小,返回的指针需要强转;new会调用构造函数,不用指定内存的大小,返回指针不用强转。
  4. new可以被重载;malloc不行
  5. new分配内存更直接和安全。
  6. new发生错误抛出异常,malloc返回null
答案解析

malloc底层实现:
当开辟的空间小于 128K 时,调用 brk()函数;当开辟的空间大于 128K 时,调用mmap()。malloc采用的是内存池的管理方式,以减少内存碎片。先申请大块内存作为堆区,然后将堆区分为多个内存块。当用户申请内存时,直接从堆区分配一块合适的空闲快。采用隐式链表将所有空闲块,每一个空闲块记录了一个未分配的、连续的内存地址。

new底层实现:
关键字new在调用构造函数的时候实际上进行了如下的几个步骤:

  1. 创建一个新的对象
  2. 将构造函数的作用域赋值给这个新的对象(因此this指向了这个新的对象)
  3. 执行构造函数中的代码(为这个新对象添加属性)
  4. 返回新对象

说说const和define的区别

参考回答

const用于定义常量;而define用于定义宏,而宏也可以用于定义常量。都用于常量定义时,它们的区别有:

  1. const生效于编译的阶段;define生效于预处理阶段。
  2. const定义的常量,在C语言中是存储在内存中、需要额外的内存空间的;define定义的常量,运行时是直接的操作数,并不会存放在内存中。
  3. const定义的常量是带类型的;define定义的常量不带类型。因此define定义的常量不利于类型检查

说说C++中函数指针和指针函数的区别

参考回答
  1. 定义不同
    指针函数本质是一个函数,其返回值为指针。
    函数指针本质是一个指针,其指向一个函数。
  2. 写法不同
  3. 用法不同
    用法参考答案解析
答案解析
//指针函数示例  
typedef struct _Data{  
	int a;  
	int b;  
}Data;  

//指针函数  
Data* f(int a,int b){  
	Data * data = new Data;  
	//...  
	return data;  
} 

int main(){  
	//调用指针函数  
	Data * myData = f(4,5);  
	//Data * myData = static_cast<Data*>(f(4,5));  
	//...  
} 

//函数指针示例  
int add(int x,int y){  
	return x+y;  
} 

//函数指针  
int (*fun)(int x,int y);  

//赋值  
fun = add;  

//调用  
cout << "(*fun)(1,2) = " << (*fun)(1,2) ;  
//输出结果  
//(*fun)(1,2) = 3

说说const int *a, int const *a, const int a, int *const a, const int *const a分别是什么,有什么特点

  1. const int a; 指的是a是一个常量,不允许修改。
  2. const int *a; a指针所指向的内存里的值不变,即(*a)不变
  3. int const *a;const int *a;
  4. int *const a; a指针所指向的内存地址不变,即a不变
  5. const int *const a; 都不变,即(*a)不变,a也不变

说说使用指针需要注意什么

参考回答
  1. 定义指针时,先初始化为NULL。
  2. 用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。
  3. 不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。
  4. 避免数字或指针的下标越界,特别要当心发生“多1”或者“少1”操作
  5. 动态内存的申请与释放必须配对,防止内存泄漏
  6. 用free或delete释放了内存之后,立即将指针设置为NULL,防止“野指针”
答案解析

(1)初始化置NULL
(2)申请内存后判空
(3)指针释放后置NULL

int *p = NULL; //初始化置NULL  
p = (int *)malloc(sizeof(int)*n); //申请n个int内存空间  
assert(p != NULL); //判空,防错设计  
p = (int *) realloc(p, 25);//重新分配内存, p 所指向的内存块会被释放并分配一个新的内存地址  
free(p);  
p = NULL; //释放后置空  
int *p1 = NULL; //初始化置NULL  
p1 = (int *)calloc(n, sizeof(int)); //申请n个int内存空间同时初始化为0  
assert(p1 != NULL); //判空,防错设计  
free(p1);  
p1 = NULL; //释放后置空  
int *p2 = NULL; //初始化置NULL  
p2 = new int[n]; //申请n个int内存空间  
assert(p2 != NULL); //判空,防错设计  
delete []p2;  
p2 = nullptr; //释放后置空

说说内联函数和函数的区别,内联函数的作用

参考回答
  1. 内联函数比普通函数多了关键字inline
  2. 内联函数避免了函数调用的开销;普通函数有调用的开销
  3. 普通函数在被调用的时候,需要寻址(函数入口地址);内联函数不需要寻址。
  4. 内联函数有一定的限制,内联函数体要求代码简单,不能包含复杂的结构控制语句;普通函数没有这个要求。
    内联函数的作用:内联函数在调用时,是将调用表达式用内联函数体来替换。避免函数调用的开销。
答案解析

在使用内联函数时,应注意如下几点:

  1. 在内联函数内不允许用循环语句和开关语句。
    如果内联函数有这些语句,则编译将该函数视同普通函数那样产生函数调用代码,递归函数是不能被用来做内联函数的。内联函数只适合于只有1~5行的小函数。对一个含有许多语句的大函数,函数调用和返回的开销相对来说微不足道,所以也没有必要用内联函数实现。
  2. 内联函数的定义必须出现在内联函数第一次被调用之前

简述C++有几种传值方式,之间的区别是什么

参考回答

传参方式有这三种:值传递、引用传递、指针传递

  1. 值传递:形参即使在函数体内值发生变化,也不会影响实参的值;
  2. 引用传递:形参在函数体内值发生变化,会影响实参的值;
  3. 指针传递:在指针指向没有发生改变的前提下,形参在函数体内值发生变化,会影响实参的值;
答案解析

值传递用于对象时,整个对象会拷贝一个副本,这样效率低;而引用传递用于对象时,不发生拷贝行为,只是绑定对象,更高效;指针传递同理,但不如引用传递安全。
代码示例

//代码示例  
#include <iostream>  
using namespace std;  
void testfunc(int a, int *b, int &c){
//形参a值发生了改变,但是没有影响实参i的值;但形参*b、c的值发生了改变,影响到了实参*j、k的值  
	a += 1;  
	(*b) += 1;  
	c += 1;  
	printf("a= %d, b= %d, c= %d\n",a,*b,c);//a= 2, b= 2, c= 2  
} 
int main(){  
	int i = 1;  
	int a = 1;  
	int *j = &a;  
	int k = 1;  
	testfunc(i, j, k);  
	printf("i= %d, j= %d, k= %d\n",i,*j,k);//i= 1, j= 2, k= 2  
	return 0;  
}

简述const(星号)和(星号)const的区别

//const* 是常量指针,*const 是指针常量  

int const *a;  //a指针所指向的内存里的值不变,即(*a)不变
int *const a;  //a指针所指向的内存地址不变,即a不变
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值