【C++面试宝典】C/C++知识点补充

39 篇文章 13 订阅
26 篇文章 2 订阅

 

       

目录

C++补充

补充知识

语言对比 

C和C++

Java和C++

Python和C++

C和C++中struct

判断结构体是否相等

可变参数模板

switch中case里不能自定义变量

char和int转换

malloc的底层实现

C语言检索内存情况

异常处理try/catch

fork()

epoll

C/C++

C语言补充

printf

switch

动态内存管理

malloc函数

realloc函数

calloc函数

字符串操作

strcpy

strcmp

strlen

strcat

内存管理

memcpy

memset

memcmp

内存分配方式

从静态存储区分配

在栈上创建

在堆上分配

宏定义

判断一段程序是C编译还是C++

在main函数之前运行的函数

数组的下标可以是负数

可变参数函数

函数调用

位运算


C++补充

  1. 补充知识

    • 语言对比 

      • C和C++

        • 设计思想
          • 面向对象和面向过程
        • 语法
          • C++有继承多态封装
          • 增加许多类型安全功能,比如强制类型转换
          • C++支持范式编程,比如函数模板,类模板
          • C语言不支持重载
            • 函数指针
              • 传入void*指针,参数无类别化
            • 可变参数列表
          • 有异常处理机制
      • Java和C++

        • Java为解释性语言,程序源代码经过Java编译器编译成字节码,然后由JVM解释执行。而C/C++为编译型语言,源代码经过编译和链接后生成可执行的二进制代码
        • C++用析构函数回收垃圾,写C和C++程序时一定要注意内存的申请和释放 Java语言不使用指针,内存的分配和回收都是自动进行的,程序员无须考虑内存碎片的问题
      • Python和C++

        • Python是一种脚本语言,是解释执行的,而C++是编译语言,是需要编译后在特定平台运行的。python可以很方便的跨平台,但是效率没有C++高。
        • Python使用缩进来区分不同的代码块,C++使用花括号来区分
        • C++中需要事先定义变量的类型,而Python不需要,Python的基本数据类型只有数字,布尔值,字符串,列表,元组等等
        • Python的库函数比C++的多,调用起来很方便
    • C和C++中struct

      • C语言中:struct是用户自定义数据类型(UDT)
      • C++中struct是抽象数据类型(ADT)
      • 在C中必须在结构标记 前加上struct,才能做结构类型名
      • C++中的struct能继承,能实现多态
    • 判断结构体是否相等

      • 重载“==”操作符
      • 使用memcmp
    • 可变参数模板

    • switch中case里不能自定义变量

    • char和int转换

      • char c='5';int n = c-'0';
      • int n=5;char c=n+'0';
    • malloc的底层实现

    • C语言检索内存情况

    • 异常处理try/catch

    • fork()

    • epoll

       

C/C++

  1. C语言补充

    • printf

      • 进制
        • d
        • o
        • x
          • 大小写
          • 加#号
    • switch

      • 支持byte,char,short,int,long,bool,整数类型和枚举
      • 不支持float,double,string
      • case里为何不能定义变量
    • 动态内存管理

      • malloc函数

        • 函数原型:void *malloc(size_t size);
        • 分配成功则返回指向被分配内存的指针(内存中的值未初始化)分配失败返回NULL
        • 在 1G 内存的计算机中能否 malloc(1.2G) ?为什么?
          • 能,malloc能够申请的空间大小与物理内存的大小没有直接关系,仅与程序的虚拟地址空间相关
        • 底层原理
          • 为了减少内存碎片和系统调用的开销,malloc采用内存池的方式
            • 先申请大块内存作为堆区然后将堆区分为多个内存块,以块作为内存管理的基本单位。当用户申请内存时,直接从堆区分配一块合适的空闲块
            • malloc采用隐式链表结构将堆区分成连续的、大小不一的块,包含已分配块和未分配块
            • malloc采用显示链表结构来管理所有的空闲块:即用一个双向链表将空闲块连接起来,每个空闲块记录了一个连续、未分配的地址
            • 当进行内存分配时,malloc会通过隐式链表遍历所有的空闲块,选择满足要求的块进行分配;当进行内存合并时,malloc采用边界标记法,根据每个块的前后块是否以及分配来决定是否进行块合并
          • 申请内存时,一般会通过brk或者mmap系统调用进行申请
            • 当申请内存小于128k时,会使用系统brk在堆区中分配
            • 当申请内存大于128k时,会使用系统函数mmap在映射区分配
      • realloc函数

        • 函数原型:extern void *realloc(void* mem_address, unsigned int newsize);指针名 = (数据类型 *)realloc(要改变内存大小的指针名,新的大小)
        • 假如旧内存后面还有足够多的剩余内存:realloc的内存=旧内存+剩余内存
        • 假如旧内存后面无足够多的剩余内存:realloc将申请新的内存,把旧内存中的数据拷贝到新内存中,再将原内存释放,返回新内存的地址
        • 传递给realloc的指针必须是先通过malloc,calloc或者是realloc分配的
        • 传递给realloc的指针可以为空,等同于malloc
      • calloc函数

        • 函数原型:void *calloc(size_t num,size_t size);
        • 与malloc区别
          • calloc分配完内存后,会将该内存空间置零,而malloc不初始化,内存中的是随机数据
    • 字符串操作

      • strcpy

        • des 和 src 所指内存区域不可以重叠且 des 必须有足够的空间来容纳 src 的字符串
        • char * myStrcpy(char *des, const char*src) {   assert((des != NULL) && (src != NULL));    char * addr = des;     while ((*des++ = *src++) != '\0'); return addr;}
        •  strcpy 会拷贝’\0’
      • strcmp

        • /* *函数strcmp的原型是int strcmp(const char *s1,const char *s2)。 若s1==s2,返回零;若s1>s2,返回正数;若s1<s2,返回负数。*/int myStrcmp(const char* s1, const char* s2) {     assert((s1 != NULL) && (s2 != NULL)); while (*s1 == *s2) {         if (*s1 == '\0') return 0;         ++s1;     ++s2;     }      return *s1 - *s2;}
      • strlen

        • int myStrlen(const char* src) {     assert(src != NULL); int len = 0;   while ((*src++) != '\0') {            ++len;   }      return len;}
      • strcat

        • //des 和 src 所指内存区域不可以重叠且 des 必须有足够的空间来容纳 src 的字符串char * myStrcat(char*des, const char *src) { assert((des != NULL) && (src != NULL));      char *addr = des;      while (*des != '\0') {//移动到字符串末尾        ++des;   }      //此时des指向的是‘\0’ while (*des++ = *src++) {      }      return addr;}
    • 内存管理

      • memcpy

        • void *memcpy(void *destin, void *source, unsigned n);
        • 从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源source中拷贝n个字节到目标destin中
        • source和destin所指的内存区域可能重叠,但是如果source和destin所指的内存区域重叠,那么这个函数并不能够确保source所在重叠区域在拷贝之前不被覆盖。而使用memmove可以用来处理重叠区域。函数返回指向destin的指针
        • 底层原理
      • memset

      • memcmp

    • 内存分配方式

      • 从静态存储区分配

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

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

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

      • 文件包含#include
      • 宏定义#define
        • #define 标识符 字符串
          • #define PI 3.14
          • #define S(a,b) a*b
            • S(2,3) ==6
          • #define S(a)  a*a
            • S(2+3) == 2+3*2+3 = 11
          • 交换两个数
            • #define SWAP(a,b) (a)=(a)+(b);(b)=(a)-(b);(a)=(a)-(b);
          • 找较小数
            • #define MIN(a,b) ((a) <= (b) ? (a) : (b) )
          • 数组大小
            • #define LENOFARR(arr) sizeof(arr)/sizeof(arr[0])
          • 不使用sizeof,求类型所占的字节数
            • #define SIZEOF(value) (char *)(&value+1)-(char*)(&value)
              • (char*)(&value)返回的是value地址的第一个字节所在的地址(char*)(&value+1)返回的是value地址的下一个地址空间的第一个字节所在的地址
            • int s = 1;double d = 2.0;float f = 1.0;cout << SIZEOF(s) << endl;//4cout << SIZEOF(d) << endl;//8cout << SIZEOF(f) << endl;//4
        • 宏名一般用大写,提高可读性和通用性,如数组的大小
        • 宏定义末尾不加分号
        • 无类型,不做安全检查
        • 不分配内存
        • 可以嵌套
        • 可使用#undef命令终止宏定义的作用域
      • 条件编译#ifdef...
        • 防止头文件被重复引用
      • #error
        • 编译程序时,只要遇到#error
    • 判断一段程序是C编译还是C++

      • #ifdef __cplusplus    cout << "C++" << endl;#else  cout << "C" << endl;#endif
    • 在main函数之前运行的函数

      • C++
        • 全局类变量的构造函数、拷贝构造函数
        • 匿名函数
          • int fun1 = []() {     cout << "fun1" << endl;   return 0;}();
        • 用函数返回值给全局变量初始化
    • 数组的下标可以是负数

      • 下标只是给出了一个与当前地址的偏移量,只要根据这个偏移量能定位到目标地址即可
        • int nums[] = { 1,2,3,4,5 };int *p = nums + 4;cout << p[-4] << endl;//1
    • 可变参数函数

      • 比如printf和scanf
      • 实现原理
        • 利用四个宏(头文件stdarg.h)
          • va_list
          • va_start
          • va_arg
          • va_end
        • 内存压栈技术
          • 压栈的顺序是从最右边参数开始的,再向左逐个压入,根据栈的原理,在取参数时,就从第一个可变参数开始
    • 函数调用

      • 每一个函数调用都会分配函数栈,在栈内进行函数指向过程。调用前,先把返回地址压栈,然后把当前函数的esp指针压栈
      • 参数压栈顺序
        • 从右至左
    • 位运算

     

     

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

SOC罗三炮

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

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

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

打赏作者

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

抵扣说明:

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

余额充值