TB-C/C++

1.main函数之前之后执行的代码

  • 设置栈指针
  • 初始化静态变量和全局变量(.data段内容,已初始化且不为0)
  • 赋初值(.bss段内容,未初始化的全局变量和静态变量)
  • 传参(argc,argv)
  • atexit()   在vs2010上没有效果
#include <iostream>
#include <stdio.h>
using namespace std;int f() {printf("before\n");return 0;
}void f2()
{printf("EXIT!\n");
}int a = f();int main() {atexit(exit_1);printf("main\n");return 0;
}before
main

2.结构体内存对齐

C++11引入两个关键字:

alignof:计算类型的对齐方式

alignas:指定结构体的对齐方式

// alignas 生效的情况struct Info {uint8_t a;uint16_t b;uint8_t c;
};std::cout << sizeof(Info) << std::endl;   // 6  2 + 2 + 2
std::cout << alignof(Info) << std::endl;  // 2struct alignas(4) Info2 {uint8_t a;uint16_t b;uint8_t c;
};std::cout << sizeof(Info2) << std::endl;   // 8  4 + 4
std::cout << alignof(Info2) << std::endl;  // 4struct alignas(4) Info2 {uint8_t a;uint16_t b;
};std::cout << sizeof(Info2) << std::endl;   // 4
std::cout << alignof(Info2) << std::endl;  // 4
// alignas 失效的情况struct Info {uint8_t a;uint32_t b;uint8_t c;
};std::cout << sizeof(Info) << std::endl;   // 12  4 + 4 + 4
std::cout << alignof(Info) << std::endl;  // 4struct alignas(2) Info2 {uint8_t a;uint32_t b;uint8_t c;
};std::cout << sizeof(Info2) << std::endl;   // 12  4 + 4 + 4
std::cout << alignof(Info2) << std::endl;  // 4若alignas小于自然对齐的最小单位,则被忽略。
如果想使用单字节对齐的方式,使用alignas是无效的。应该使用#pragma pack(push,1)或者使用__attribute__((packed))。#if defined(__GNUC__) || defined(__GNUG__)#define ONEBYTE_ALIGN __attribute__((packed))
#elif defined(_MSC_VER)#define ONEBYTE_ALIGN#pragma pack(push,1)
#endifstruct Info {uint8_t a;uint32_t b;uint8_t c;
} ONEBYTE_ALIGN;#if defined(__GNUC__) || defined(__GNUG__)#undef ONEBYTE_ALIGN
#elif defined(_MSC_VER)#pragma pack(pop)#undef ONEBYTE_ALIGN
#endifstd::cout << sizeof(Info) << std::endl;   // 6 1 + 4 + 1
std::cout << alignof(Info) << std::endl;  // 1
#if defined(__GNUC__) || defined(__GNUG__)#define ONEBYTE_ALIGN __attribute__((packed))
#elif defined(_MSC_VER)#define ONEBYTE_ALIGN#pragma pack(push,1)
#endif/**
* 0 1   3     6   8 9            15
* +-+---+-----+---+-+-------------+
* | |   |     |   | |             |
* |a| b |  c  | d |e|     pad     |
* | |   |     |   | |             |
* +-+---+-----+---+-+-------------+
*/
struct Info {uint16_t a : 1;uint16_t b : 2;uint16_t c : 3;uint16_t d : 2;uint16_t e : 1;uint16_t pad : 7;
} ONEBYTE_ALIGN;#if defined(__GNUC__) || defined(__GNUG__)#undef ONEBYTE_ALIGN
#elif defined(_MSC_VER)#pragma pack(pop)#undef ONEBYTE_ALIGN
#endifstd::cout << sizeof(Info) << std::endl;   // 2
std::cout << alignof(Info) << std::endl;  // 1位段是通过结构体来实现的一种以位(bit位)为单位的数据存储结构,它可以把数据以位的形式紧凑的储存,并允许程序员对此结构的位进行操作。由此可以看出,位段是一种节省空间的用法。位段的声明与结构体类似,但有两点不同:
1.位段的成员必须是整型家族的成员(char、int、unsigned int、signed int……)
2.位段的成员后面有一个冒号和一个数字注意:位段每一个成员冒号后面的数字,代表该成员在内存中占用的二进制位大小。就如这里的成员a占用2个bit位,成员d占用30个bit位。而且要记住冒号后面数字的大小是不能超过前面成员类型大小的。

3.指针和引用的区别

  • 指针是一个变量,存储的是一个地址,引用跟原来的变量实质上是同一个东西,是原变量的别名
  • 指针可以有多级,引用只有一级
  • 指针可以为空,引用不能为NULL且在定义时必须初始化
  • 指针在初始化后可以改变指向,而引用在初始化之后不可再改变
  • sizeof指针得到的是本指针的大小,sizeof引用得到的是引用所指向变量的大小
  • 当把指针作为参数进行传递时,也是将实参的一个拷贝传递给形参,两者指向的地址相同,但不是同一个变量,在函数中改变这个变量的指向不影响实参,而引用却可以。
  • 引用本质是一个指针,同样会占4字节内存;指针是具体变量,需要占用存储空间(,具体情况还要具体分析)。
  • 引用在声明时必须初始化为另一变量,一旦出现必须为typename refname &varname形式;指针声明和定义可以分开,可以先只声明指针变量而不初始化,等用到时再指向具体变量。
  • 引用一旦初始化之后就不可以再改变(变量可以被引用为多次,但引用只能作为一个变量引用);指针变量可以重新指向别的变量。
  • 不存在指向空值的引用,必须有具体实体;但是存在指向空值的指针。
void test(int *p)
{int a=1;p=&a;cout<<p<<" "<<*p<<endl;
}int main(void)
{int *p=NULL;test(p);if(p==NULL)cout<<"指针p为NULL"<<endl;return 0;
}
//运行结果为:
//0x22ff44 1
//指针p为NULLvoid testPTR(int* p) {int a = 12;p = &a;}void testREFF(int& p) {int a = 12;p = a;}
void main()
{int a = 10;int* b = &a;testPTR(b);//改变指针指向,但是没改变指针的所指的内容cout << a << endl;// 10cout << *b << endl;// 10a = 10;testREFF(a);cout << a << endl;//12
}

指针常量(int* const p):在指针常量中,指针自身的值是一个常量,不可改变,始终指向同一个地址。在定义的同时必须初始化。

常量指针(const int *p, int const *p):在常量指针中,指针指向的内容是不可改变的,指针看起来好像指向了一个常量。

int main() {int m = 10;const int n = 20; // 必须在定义的同时初始化const int *ptr1 = &m; // 指针指向的内容不可改变int * const ptr2 = &m; // 指针不可以指向其他的地方ptr1 = &n; // 正确ptr2 = &n; // 错误,ptr2不能指向其他地方*ptr1 = 3; // 错误,ptr1不能改变指针内容*ptr2 = 4; // 正确int *ptr3 = &n; // 错误,常量地址不能初始化普通指针吗,常量地址只能赋值给常量指针const int * ptr4 = &n; // 正确,常量地址初始化常量指针int * const ptr5; // 错误,指针常量定义时必须初始化ptr5 = &m; // 错误,指针常量不能在定义后赋值const int * const ptr6 = &m; // 指向“常量”的指针常量,具有常量指针和指针常量的特点,指针内容不能改变,也不能指向其他地方,定义同时要进行初始化*ptr6 = 5; // 错误,不能改变指针内容ptr6 = &n; // 错误,不能指向其他地方const int * ptr7; // 正确ptr7 = &m; // 正确int * const ptr8 = &n;*ptr8 = 8;return 0;
}
判断下面对错,并说明理由int main()
{char * const str = "apple";* str = "orange";cout << str << endl;getchar();
}错误"apple"是字符串常量放在常量区,str指向"apple",那么str指向的是字符串常量"apple"的首地址,也就是字符a的地址,因此str指向字符a,*str就等于字符a,对*str的修改就是对字符串首字符a的修改,但"apple"是一个字符串常量,常量的值不可修改。根据字符串赋值规则,可以修改整个字符串,方法是对指向字符串的指针str进行赋值,如下:str = "orange";但依旧是错误的,在该赋值语句中,系统会在常量区一块新的空间写入字符串"orange"并返回其首地址,此时str由指向字符串常量"apple"的首地址变为指向字符串常量"orange"的首地址,str指向的地址发生了变化,但str是指针常量不能被修改,所以错误。如果想要程序编译通过,就不能将str声明为指针常量,否则str在初始化之后就无法修改。因此将const修饰符去掉,并修改字符串赋值语句,修改后程序如下:int main()
{char * str = "apple";str = "orange";cout << str << endl;getchar();
}

4.传递函数参数什么时候使用指针,什么时候使用引用

  • 需要返回函数内局部变量的内存的时候用指针。使用指针传参需要开辟内存,用完要记得释放指针,不然会内存泄漏。而返回局部变量的引用是没有意义的

  • 对栈空间大小比较敏感(比如递归)的时候使用引用。使用引用传递不需要创建临时变量,开销要更小

  • 类对象作为参数传递的时候使用引用,这是C++类对象传递的标准方式

5.堆和栈的区别

  • 申请方式不同
    • 栈由系统自动分配
    • 堆是自己申请和释放的
  • 申请大小限制不同
    • 栈顶和栈底是之前预设好的,栈是向栈底扩展,大小固定,可以通过ulimit-a 查看,由ulimit -s修改
    • 堆向高地址扩展,是不连续的内存区域,大小可以灵活调整
  • 申请效率不同
    • 栈由系统分配,速度快,不会有碎片
    • 堆由程序员分配,速度慢,会有碎片
  • 栈空间默认是4M,堆区一般是1G-4G

6.堆和栈哪个快

毫无疑问是栈快一点。

因为操作系统会在底层对栈提供支持,会分配专门的寄存器存放栈的地址,栈的入栈出栈操作也十分简单,并且有专门的指令执行,所以栈的效率比较高也比较快。

而堆的操作是由C/C++函数库提供的,在分配堆内存的时候需要一定的算法寻找合适大小的内存。并且获取堆的内容需要两次访问,第一次访问指针,第二次根据指针保存的地址访问内存,因此堆比较慢。

7.区别下面指针类型

  • int *p[10]表示指针数组,强调数组概念,是一个数组变量,数组大小为10,数组内每个元素都是指向int类型的指针变量。

  • int (*p)[10]表示数组指针,强调是指针,只有一个变量,是指针类型,不过指向的是一个int类型的数组,这个数组大小是10。

  • int *p(int)是函数声明,函数名是p,参数是int类型的,返回值是int *类型的。

  • int (*p)(int)是函数指针,强调是指针,该指针指向的函数具有int类型参数,并且返回值是int类型的。

8.new/delete与malloc/free的异同

相同点:都可以用于内存的动态申请和释放

不同点:

  • 前者是C++运算符,后者是C/C++语言标准库函数
  • new自动计算要分配的空间大小,malloc需要手工计算
  • new是类型安全的,malloc不是。例如:
int *p = new float[2]; //编译错误
int *p = (int*)malloc(2 * sizeof(double));//编译无错误
  • new调用名为operator new的标准库函数分配足够空间并调用相关对象的构造函数,delete对指针所指对象运行适当的析构函数;然后通过调用名为operator delete的标准库函数释放该对象所用内存。后者均没有相关调用
  • 后者需要库文件支持,前者不用
  • new是封装了malloc,直接free不会报错,但是这只是释放内存,而不会析构对象

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/318471.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

12.Harbor构建私有镜像仓库

1、阿里云容器镜像服务-个人版 细心的同学可能已经发现,在前面的部署过程中,前面所有的部署步骤中需要的镜像都是从阿里云的镜像仓库中下载。 因为网络原因,有的镜像可能下载比较慢,有点可能下载不了,所以为了加速镜像下载,我都统一将镜像推送到阿里云的镜像仓库(个人…

编译器功能__attribute__介绍和官方资料来源

1、__attribute__简介 __attribute__不是C语言本身的关键字&#xff0c;而是属于编译器扩展的C语言的功能&#xff0c;C Extensions (Using the GNU Compiler Collection (GCC))中可以找到关于attribute的几个章节&#xff0c;Function Attributes【函数属性】、Variable Attr…

基于深度学习的交通标志图像分类识别系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 本文详细探讨了一基于深度学习的交通标志图像识别系统。采用TensorFlow和Keras框架&#xff0c;利用卷积神经网络&#xff08;CNN&#xff09;进行模型训练和预测&#xff0c;并引入VGG16迁移学习…

基于YOLOv7算法的高精度实时海上船只目标检测识别系统(PyTorch+Pyside6+YOLOv7)

摘要&#xff1a;基于YOLOv7算法的高精度实时海上船只目标检测系统可用于日常生活中检测与定位海上船只&#xff0c;此系统可完成对输入图片、视频、文件夹以及摄像头方式的目标检测与识别&#xff0c;同时本系统还支持检测结果可视化与导出。本系统采用YOLOv7目标检测算法来训…

基于华为ENSP模拟器-vlan划分网络

需求 不连外网的内网。需求隔离故障和隔离广播风暴&#xff0c;并要保证网络的连通。 解决方案使用三层交互机&#xff0c;设置vlan用于隔离网络&#xff0c;并在三层交互机为网关保证各个vlan之间的通讯。 实现 使用三层交互机&#xff0c;设置vlan用于隔离网络&#xff0…

全国计算机等级考试| 二级Python | 真题及解析(11)

一、选择题 1.有关循环结构的说法不正确的是( )。 A.循环结构是算法的基本结构之一 B.有的的程序设计中没有循环结构 C.循环结构在程序设计有可能会有嵌套出现 D.在PYTHON 程序设计语言中循环结构一般使用IF语句实现。 2.在Python中要交换变量a和b中的值,应使…

Nacos学习思维导图

一、服务注册 参考文档&#xff1a;http://www.bryh.cn/a/118936.html https://blog.csdn.net/Saintmm/article/details/121981184 二、服务续约 参考文档&#xff1a;http://www.bryh.cn/a/118936.html https://blog.csdn.net/Saintmm/article/details/121981184 三、服务…

CMake入门教程【核心篇】引用子模块.cmake文件(include)

&#x1f608;「CSDN主页」&#xff1a;传送门 &#x1f608;「Bilibil首页」&#xff1a;传送门 &#x1f608;「本文的内容」&#xff1a;CMake入门教程 &#x1f608;「动动你的小手」&#xff1a;点赞&#x1f44d;收藏⭐️评论&#x1f4dd; 文章目录 include子模块举个例…

多元统计分析(4):判别分析

4.1 判别分析的目标 主要目的&#xff1a;判别一个个体所属类别 4.2 距离判别 都选用用马氏距离 4.2.1 判别准则 化简的证明&#xff1a; 称为判别函数&#xff0c;为判别系数。 4.2.2 误判概率 【1】当两个正态总体的协方差相同 证明&#xff1a; 当两个正态总体重合的时…

ctfshow 元旦水友赛 月月的爱情故事(复现)

读了题目的文字&#xff0c;然后被刀了…… 但还是要向前看&#xff0c;做一个坚强又勇敢的人 好了碎碎念结束 一、原题 原题就是一段文字&#xff0c;一串字符和一个hint。 二、解题过程 1.base64解码 首先看到那行字符很像base64&#xff0c;那就先解码base64试一试嘛&a…

[C语言]比特鹏哥

主页有博主其他上万字精品笔记,都在不断完善更新! C语言 初识C语言 基本了解C语言的基础知识&#xff0c;对C语言有一个大概的认识。 每个知识点就是简单认识&#xff0c;不做详细讲解&#xff0c;后期课程都会细讲。 本章重点&#xff1a; 什么是C语言 第一个C语言程序 数据…

QT基础知识

QT基础知识 文章目录 QT基础知识1、QT是什么2、Qt的发展史3、为什么学习QT4、怎么学习QT1、工程的创建(环境的下载与安装请百度&#xff09;2、创建的工程结构说明3、怎么看帮助文档1、类使用的相关介绍2. 查看所用部件&#xff08;类&#xff09;的相应成员函数&#xff08;功…