首页 > 编程语言 >C/C++基础知识点

C/C++基础知识点

时间:2023-08-10 15:15:48浏览次数:33  
标签:知识点 const 变量 基础 C++ unique ptr 指针

C和C++的区别

  1. C++是C的超集,C是面向过程化的结构性语言,而C++是面向对象的编程语言
  2. C语言更偏向于底层,使用较为灵活,可移植性强,而C++更偏向于上层,可扩展性强,对于大型项目往往使用C++
  3. C++在C语言的基础上提出了STL标准模板库,函数模板等特性

static关键字的作用

  1. 隐藏,凡事变量前添加static关键字,只对该变量所在的文件显示,对其他文件隐藏
  2. 默认初始化为0,对于变量前加static关键字,未经初始化前该变量会被自动初始化为0
  3. 保持变量的持久化
  4. 用来修饰类的成员函数和成员变量,类的成员变量前加static关键字,该成员将属于整个类,而非类的某个对象;类的静态成员函数同理。其无this指针,仅能访问static修饰的成员函数和变量。

static全局静态变量和局部静态变量的区别

  1. 默认初始化为0
  2. 作用域。
    1. static全局静态变量在声明它的文件之外是不可见的,准确来说,从定义开始到文件结尾。
    2. static局部静态变量的作用域当定义在它的函数或者语句块结束时,作用域结束。但是当局部静态变量离开作用域时并没有被销毁,而是仍然驻留在内存中,只不过无法对其进行访问,直到该函数再次被调用,并且值不变。

C++中四种cast类型转换

  1. const_cast用于将const转换为非const类型
  2. static_cast用于所有的隐式转换(类似于C语言的强转类型),同时也用于上行转换(将子类转为父类),父类转子类也可行,但是类型不安全
  3. dynamic_cast即可以用于上行转换也可以用于下行转换,下行转换不成功会返回NULL,有安全检查
  4. reprint_cast用于所有类型和指针之间的转换

C++中指针和引用的区别

  1. 指针不必初始化,引用必须初始化且只能作为同一变量的别名
  2. 指针一般指的是某块内存的地址,通过这个地址,可以访问到这块内存;而引用只是一个变量的别名
  3. 指针可以指向任何类型;而引用只能指向一个变量
  4. 指针可以为NULL;而引用不可以为空

C++中智能指针原理、用法和缺陷

原理

智能指针是一个指针类,利用了析构函数的原理,离开作用域时释放指针对象。引入智能指针的目的是为了防止程序员在创建了指针,使用完成后,未进行释放导致内存泄漏问题。

用法

auto_ptr:

C++98提出的,定义在库中,只能用来管理单个动态创建的对象,而不是管理动态创建的数组

Auto_ptr不足之处:
  1. 两个auto_ptr不能指向同一块内存,析构时会造成同一块内存多次释放,程序崩溃;
  2. 不要将auto_ptr对象作为STL容器的元素,C++标准中禁止这样使用;
  3. 不能将数组作为auto_ptr的参数;

unique_ptr:

与share_ptr不同,unique_ptr没有定义类似make_share的操作,因此只能使用new来分配内存,不可通过拷贝和赋值,初始化时必须使用直接初始化的方式。
例如:

nique_ptr <int> up1(new int()); // ok
unique_ptr <int> up2 = new int(); // error
unique_ptr <int> up3(up2); // error

与share_ptr不同,unique_ptr拥有它所指向的对象,在某一时刻,只能有一个unique_ptr指向特定的对象。当unique_ptr被销毁时,它所指向的对象也会被销毁。因此不允许多个unique_ptr指向同一个对象,所以不允许拷贝与赋值。

如何传递unique_ptr参数和返回unique_ptr呢?

A. 可以拷贝或赋值一个将要被销毁的unique_ptr

// 从函数返回一个unique_ptr
unique_ptr func1(int a){
   Return unique_ptr <int> (new int(a));
}
// 返回一个局部对象的拷贝
unique_ptr func1(int a){
  unique_ptr <int> up(new int(a));
  return up;
}

B. 传unique_ptr参数可以使用引用避免所有权的转移,或者暂时的移交所有权

void func1(unique_ptr <int> &up){
  Cout<<*up<<endl;
}

unique_ptr <int> func2(unique_ptr <int> up){
  cout<<*up<<endl;
  return up;
}
// 使用up作为参数
unique_ptr <int> up(new int(10));

// 传引用,不拷贝,不涉及所有权转移
Func1(up);

// 暂停转移所有权,函数结束时返回拷贝,重新收回所有权
up = func2(unique_ptr <int> (up.release()));

share_ptr:

通过引用计数的方式来实现多个share_ptr对象共享同一块资源。

缺陷:
  1. 不要与裸指针混用;
  2. 不要用p.get()的返回值为share_ptr赋值,因为p.get()返回值是普通指针;
  3. 两个类,每个类包含share_ptr指针互相指向对方,会造成循环引用,导致内存泄漏

weak_ptr:

为了解决循环引用问题。原理是weak_ptr并不影响shared_ptr引用计数指针的计数值,即weak_ptr不会影响指向区域内存的生命周期

数组和指针的区别

概念

数组用于存放多个相同类型的集合,而指针用来存放变量在内存中的地址

赋值

同类型指针可以相互赋值,而数组需要一个一个元素赋值或者拷贝

存储

数组的存储空间不是在静态区就是在栈上,而指针无法确定

求sizeof

数组大小 = sizeof(数组名)/ sizeof(数据类型),而指针 32位:4,64位:8

const的用法

用来修饰指针变量

  1. const位于*的左侧,表示指针所指变量是常量,不可通过解引用来修改其值
  2. const位于*的右侧,表示指针本身是常量,不可修改指针所指向的地址
  3. const位于*的左右两侧,表示都不可改变

用来修饰函数参数

  1. 对于指针类型的参数,需要加const防止指针被意外修改
  2. 对于非内部数据结构的参数,修改为const引用方式,提高效率

用来修饰函数返回值

  1. 用const修饰的函数返回值,不可修改其返回值,且必须用同类型的const变量接收

用来修饰类成员函数体

  1. 修饰类的成员函数,表明该成员变量不可修改,否则会报错

new/delete和malloc/free的区别

  1. new/delete是C++的关键字;而malloc/free是C语言中的函数
  2. new/delete在创建的时候调用C++的构造/析构函数,而malloc/free不需要
  3. new创建对象时不需要指定大小,而malloc需要指定内存分配大小
  4. new创建成功后返回创建的对象,是类型安全的,无需转换;而malloc需要强转指定类型

C++内存是如何分配

  1. 从栈上分配。函数中的临时局部变量分配在栈上,由操作系统自动分配,函数调用结束时内存也随之析构,栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
  2. 从堆上分配。在堆区使用malloc或new申请内存,这种内存分配方式非常灵活。
  3. 从静态存储区上分配。这块内存在程序编译的时候就已经分配好,用来存放常量,全局变量和static变量,内存在整个程序运行周期内都存在。
  4. 全局/静态存储区。
  5. 常量存储区。

为什么需要内存对齐及如何关闭内存对齐?

内存对齐:

为了提高程序的性能,数据结构(尤其是栈)应该尽可能在自然边界上对齐。原因是,为了访问未对齐的内存,处理器需要两次内存访问;然而,对齐的内存仅需访问一次。

如何关闭内存对齐?

一种是添加#pragma pack(1); 另一种是利用__attribute__(packed)指令。用法如下

#pragma pack(1)
struct A {
  int a;
  int b;
  char c;
};
sizeof(A); //输出9

struct B{
  int a;
  int b;
  char c;
}__attribute__((packed))B;
sizeof(B); //输出9

sizeof和strlen的区别

  1. strlen是函数,而sizeof是运算符;
  2. strlen测量的是字符的实际长度,以“\0”结束,但不包括“\0”所占大小;
  3. sizeof是用来计算字节或类型大小,一般由机器决定,而非人为控制
  4. strlen是在运行时计算长度的,而sizeof是在编译时确定长度大小的;

堆和栈的区别

  1. 申请方式:栈区内存由系统自由分配,函数结束后自动释放,而堆区则由程序员自行分配,用完后自行释放;
  2. 申请空间大小:栈默认是1M,可进行修改,最大是8M,而堆则需要看主机是32位还是64位;
  3. 申请效率:栈快于堆;
  4. 存取效率:栈快于堆;
  5. 底层不同:栈是连续的空间,而堆是不连续的空间
  6. 是否产生碎片化:对于堆来讲,频繁的new/delete势必造成内存空间的不连续,因此堆容易产生碎片化,而栈不会;
  7. 生长式向:堆是向上生长的,也就是向着内存地址增加的方向,而栈恰恰相反。

#define的用法以及与typedef的区别

  1. define是C语言定义的语法,是预处理指令,在预处理时只做简单的字符串替换不做安全检查,只有在编译被展开的源程序时才会发生可能的错误并报错;
  2. typedef是关键字,在编译处理时,有类型安全检查。是为一个已存在的类型起别名。

在C中用const能定义真正意义上的常量吗?C++中的const呢?

不能。C中的const仅仅从编译层来限定,不允许对const变量进行赋值操作,在运行期是无效的,所以并非真正的常量。但是C++中是有区别的,c++在编译时会把const常量加入符号表,以后(仍然在编译期)遇到这个变量会从符号表中查找,所以在C++中是不可能修改到const变量的。

补充:

  1. c中的局部const常量存储在栈空间,全局const常量存在只读存储区,所以全局const常量也是无法修改的,它是一个只读变量。 2. 这里需要说明的是,常量并非仅仅是不可修改,而是相对于变量,它的值在编译期已经决定,而不是在运行时决定。
  2. c++中的const 和宏定义是有区别的,宏是在预编译期直接进行文本替换,而const发生在编译期,是可以进行类型检查和作用域检查的。
  3. c语言中只有enum可以实现真正的常量。
  4. c++中只有用字面量初始化的const常量会被加入符号表,而变量初始化的const常量依然只是只读变量。
  5. c++中const成员为只读变量,可以通过指针修改const成员的值,另外const成员变量只能在初始化列表中进行初始化。

标签:知识点,const,变量,基础,C++,unique,ptr,指针
From: https://www.cnblogs.com/stlong/p/17619645.html

相关文章

  • 盘点一个列表相加的Python基础题目
    大家好,我是皮皮。一、前言前几天在明佬的Python群【dq】问了一个Python列表基础处理的问题,一起来看看吧。下图是他的原始列表,想通过左边的列表,得到右边的合并列表。二、实现过程这里【流水线】和【hclw】大佬给了一个答案,如下图所示:如此顺利地解决了粉丝的问题。后来他自......
  • # yyds干货盘点 # 盘点一个列表相加的Python基础题目
    大家好,我是皮皮。一、前言前几天在明佬的Python群【dq】问了一个Python列表基础处理的问题,一起来看看吧。下图是他的原始列表,想通过左边的列表,得到右边的合并列表。二、实现过程这里【流水线】和【hclw】大佬给了一个答案,如下图所示:如此顺利地解决了粉丝的问题。后来他自己也写了个......
  • c++枚举详细介绍以及具体用法
    C++中的枚举(Enumeration)是一种用于定义命名常量集合的数据类型。枚举可以提高代码的可读性和可维护性,让您可以使用有意义的名称来表示特定的取值,而不必使用原始的数字常量。枚举的基本语法:enumEnumName{Value1,Value2,//...};EnumName是枚举类型的名称......
  • C/C++开发者必备 如何获取系统环境变量的方法
    获取系统环境变量在C/C++中是一项简单的任务。下面展示了一个纯C语言实现的方法。```c#include<stdio.h>#include<stdlib.h>intmain(void){char*pathVar;pathVar=getenv("PATH");printf("pathVar=%s",pathVar);return0;}```需要注意的是,`getenv()`函数定义......
  • 我的第一篇博客--C++课程设计
    目录前言一、题目1.数位之和2.数字排序3.字符串匹配二、问题分析1.数位之和2.数字排序3.字符串匹配三、具体代码1.数位之和2.数字排序3.字符串匹配总结前言这是我的第一篇博客,内容便是最近所做的课程设计,之后也会每天和大家分享一下刷题笔记,以及AC后的代码,希望大家的批评指正,分享大......
  • Linux基础概念:历史、发展、发行版及命令行工具详解
    ·介绍:Linux是一种开源的、类Unix操作系统内核,它具有广泛的应用领域和强大的稳定性。本文将深入探讨Linux的历史与发展、常见的Linux发行版及其特点,以及常用的Linux命令行工具和基本操作。此外,还会提供个人见解和难点解析。一、Linux的历史与发展Linux的历史可以追溯到1991年,由芬......
  • 代码随想录算法训练营第十四天| 理论基础 递归遍历 迭代遍历
     理论基础    卡哥建议:需要了解 二叉树的种类,存储方式,遍历方式 以及二叉树的定义   文章讲解:https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html   补充的知识点:   名词的概念看卡哥文章。二叉树......
  • docker基础及安装
    一、镜像(Image):镜像是一个只读的模板或蓝图,包含着用于创建容器的操作系统、应用程序和所有依赖项。镜像是静态的,一旦创建,其内容不会发生变化,可以被多个容器同时使用。镜像可以通过Dockerfile定义创建过程,也可以从DockerHub或私有仓库中获取已构建好的镜像。docker镜像就好比是一个......
  • Python基础知识总结
     前言     本总结所观看视频如下:变量,数字,字符串,注释_哔哩哔哩_bilibili【Python】3小时不挂_哔哩哔哩_bilibili目录前言一、基本命令 二、基本计算语句 三、字符串操作 四、官方文档的使用五、列表与元组 六、字典 七、集合 八、值类型变量与引用类型变量 九、pr......
  • 【机器学习|数学基础】Mathematics for Machine Learning系列之矩阵理论(12):相似形理论
    目录前言往期文章3.3线性变换的最简矩阵表示-相似形理论3.3.1一般数域上矩阵相似最简形定义3.9定理3.3.1前言Hello!小伙伴!非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出~ 自我介绍ଘ(੭ˊᵕˋ)੭昵称:海轰标签:程序猿|C++选手|学生简介:因C语言结识编程,随后转入计算......