C/C++面试知识点总结

1.关键字

(1)C语言中的#和##

#可以将宏定义中的传入参数名转换为双引号括起来的参数名字符串,必须置于宏定义的参数名前
##是将宏定义的多个形参转换成一个实际的参数名

#define STRCPY(a, b)   strcpy(a ## _p, #b)
int main()
{
    char var1_p[20];
    char var2_p[30];
    strcpy(var1_p, "aaaa");
    strcpy(var2_p, "bbbb");
    STRCPY(var1, var2);//转换为strcpy(var1_p,"var2")
    STRCPY(var2, var1);
    printf("var1 = %s\n", var1_p);//var1=var2
    printf("var2 = %s\n", var2_p);//var2=var1
        return 0;
}  

(2)关键词volatile的使用场景

1.并行设备的硬件寄存器,因为存储器映射的硬件寄存器随时可能被外设硬件修改,声明指向设备寄存器的指针时要用volatile,防止编译器对这个地址的数据假设。
2.一个中断服务程序中修改的供其他程序检测的变量,保证编译器每次存储变量,直接从变量的内存地址进行读取
3.多线程应用被几个任务共享的变量

(3)关键词static的作用

总的来说,static能够更改变量和函数的作用域,只在内存中分配一次,分情况讨论如下
在函数体内,一个被声明的静态局部变量在函数反复调用维持值不变
在模块内,在函数体外,一个被声明的静态全局变量,只能被模块内的函数访问
在模块内的静态函数,只能被模块内被其他函数调用

(4)extern作用

extern可以对变量做外部全局变量说明,即使全局变量的定义在调用处的后面。
extern ”C“可以告诉编译器将这部分代码按照c代码进行编译,而不是c++

#ifndef __INCvxWorksh /*防止该头文件被重复引用*/
#define __INCvxWorksh
#ifdef __cplusplus//告诉编译器,这部分代码按C语言的格式进行编译,而不是C++的
extern "C"{
#endif
 
/*…*/
 
#ifdef __cplusplus
}
 
#endif
#endif /*end of __INCvxWorksh*/

(5)const的作用

1.定义变量为常量
2.修饰函数的参数,表示在函数体内不能修改这个参数的值
3.修饰函数的返回值(只用来修饰指针变量,一般都是修饰内容不变

const char GetString()  //定义一个函数
char *str= GetString() //错误,因为str没有被 const修饰
const char *str=GetString() //正确

4.相比宏,const可以避免不必要的内存分配。宏在编译时每次替换都会分配内存空间,const只分配一次

#define PI 3.14159//该宏用来定义常量
const doulbe Pi=3.14159//此时并未将P放入只读存储器中
double i=Pi//此时为Pi分配内存,以后不再分配
double I=PI//编译期间进行宏替换,分配内存
double j=Pi//没有内存分配再次进行宏替换,又一次分配内存

(6)什么时候使用const

1.一般变量
2.修饰常数组
3.修饰常对象,对象常量,(对象不能被更新)
4.修饰常指针(指针常量即引用,常量指针)
5.修饰形参
6.修饰函数返回值
7.在另一个连接文件中引用const常量

(7)new/delete和malloc/free的区别

1.new/delete是c++中的操作符,malloc/free是库函数
2.new和delete对应于构造函数和析构函数,,malloc和free是内存分配
3.new返回指定类型的指针,并且可以自动计算申请内存的大小。而 malloc需要我们计算申请内存的大小,并且在返回时强行转换为实际类型的指针

(8)左值和右值的概念

左值可写,右值可读

(9)短路求值

提前判断如

#include <stdio.h>
int main()
{
 int i = 6;
 int j = 1;
 if(i>0||(j++)>0);//提前判断
 printf("%D\r\n",j);
 return 0; }

2.内存

(1)堆和栈的区别

1.申请方式(手动还是自动)
2.申请大小的限制
3.地址的生长方向(栈溢出可能会导致栈顶处的数据发生覆盖)
4.申请效率

(2)函数指针和指针函数

函数指针是一个指针,这个指针用来指向函数
定义方式为:

int(*p)(int, int);

使用如下:

# include <stdio.h>
int Max(int, int);  //函数声明
int main(void) {
    int(*p)(int, int);  //定义一个函数指针
    int a, b, c;
    p = Max;  //把函数Max赋给指针变量p, 使p指向Max函数
    printf("please enter a and b:");
    scanf("%d%d", &a, &b);
    c = (*p)(a, b);  //通过函数指针调用Max函数
    printf("a = %d\nb = %d\nmax = %d\n", a, b, c);
    return 0; }
int Max(int x, int y)  //定义Max函数
{
    int z;
    if (x > y)
    {
        z = x;
   }
    else
   {
        z = y;
   }
    return z; 
}

指针函数是一个返回值为指针类型的函数
定义为:

int *pfun(int, int);

使用方式为‘

#include <stdio.h>
float *find(float(*pionter)[4],int n);//函数声明
int main(void)
 {
     static float score[][4]={{60,70,80,90},{56,89,34,45},{34,23,56,45}};
     float *p;
     int i,m;
     printf("Enter the number to be found:");
     scanf("%d",&m);
     printf("the score of NO.%d are:\n",m);
     p=find(score,m-1);
     for(i=0;i<4;i++)
         printf("%5.2f\t",*(p+i));
  
     return 0;
 }
float *find(float(*pionter)[4],int n)/*定义指针函数*/
 {
     float *pt;
     pt=*(pionter+n);
     return(pt);
 }

数组名和指针的区别

1.数据保存方面
指针保存的是地址,内存访问偏移量为四个字节,无论其中保存的是何种数据,都是以地址类型进行解析
数组保存的数据,数组名表示的是第一个元素的地址,内存偏移量是保存数据类型的内存偏移量,只有对数组名取地址时,数组名才表示整个数组, 内存访问偏移量为整个数组的大小(sizeof(数组名))
2.数据访问方面
指针是间接访问,使用解引用,*
数组对数据访问是直接访问,通过下标或者数组名加偏移量
3.使用环境
指针多用于动态数据结构,(链表等)和动态内存开辟
数组用于存储固定个数且类型统一的数据结构和隐式分配

指针和引用的区别

相同:都是地址的概念,从内存分配上来看,两者都是占用内存的
不同:
1.指针是实体,引用是别名
2.引用只能初始化一次,不能为空,之后不可变,指针可变可空
3.sizeof得到的引用是指向的变量(对象)的大小,指针是指针本身的大小

野指针的产生及如何避免

1.野指针指向不可用内存,创建时没有初始化会随机指向
2.free或delete时,没有将指针指向null,因为只释放了内存
3.指针超过了变量的作用范围
避免:初始化,使用完进行null赋值,
malloc函数分配完内存后需注意:
a. 检查是否分配成功(若分配成功,返回内存的首地址;分配不成功,返回NULL。可以通过if语句来判断)
b. 清空内存中的数据(malloc分配的空间里可能存在垃圾值,用memset或bzero 函数清空内存)

智能指针的概念

智能指针是指向动态对象的指针类,主要有,
unique_ptr C++11引入用来替代auto_ptr,解决不安全问题(auto有拷贝语义,再次访问原对象,会程序崩溃,而unique提供了移动语义)不共享所管理的对象,
shared_ptr 是共享指针,允许多个指针指向同一个对象,除了包括指向对象的指针,还必须包括一个引用计数代理对象的指针
weak_ptr 是配合shared_ptr使用的,观测资源的引用计数,可以用于打破循环引用(比如两个类互相引用),解决内存泄漏的问题
weak_ptr不会增加引用计数,是不能直接访问对象的,访问可以通过lock()函数来创建shared_ptr来引用,shared_ptr能够保证在 shared_ptr 没有被释放之前,其所管理的资源是不会被释放的

预处理

define和const的区别

define是做文本替换,
1.内存区域不同:define常量的生命周期在编译期,不分配内存,存在于代码段,const常量存在于数据段,并在堆栈中分配空间,可以被调用传递
2.数据类型不同,define常量没有数据类型,const实际存在,并且可以编译器检查
3.define替换方便,但容易出错,const可读性强,便于维护和调试。

typedef和 define有什么区别

头文件的作用

通过头文件调用库功能,实现多文件编程,更加安全,对接口的实现进行加密。
提供类型安全检查,某个接口被实现和使用的时候,编译器可以指出错误

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值