201_C++基础

2024-05-12 09:36
文章标签 基础 c++ 201

本文主要是介绍201_C++基础,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、C++结构体相关知识

一段代码阐释所有初始化与赋值的情况:

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;//结构体初始化的几种方式
//定义一个node结构体
typedef struct node{int id;int num;string name;//1、无参数的构造函数数组初始化时调用//node():id(),num(),name(){};//有参构造//node(int a,int b,string c):id(a),num(b),name(c){}//2、对于方法3的构造函数初始化,什么都不写就是使用的结构体自带的默认构造函数。//如果自己重写了带参数的构造函数,就不能用大括号进行初始化了,即不能再使用指定初始化与顺序初始化了(初始化结构体时如果不传入参数会出现错误)。//在建立结构体数组时,如果只写了带参数的构造函数将会出现数组无法初始化的错误//3、放在最后的构造函数可以不加分号结尾//node(int id,int num,string name){//     this->id=id;//     this->num=num;//     this->name=name;// }
} node_t;typedef struct charnode{int id;int num;char name[16];
} charnode_t;struct Test {int x = 0; // <== 含有默认初始化值的元素,无法使用初始化列表进行初始化char v;
};class Hero {public:Hero() {cout << "Hero 构造函数调用了" << endl;}//如果用下面的free释放new出来的h2内存,将不会触发下面的析构函数//Hero *h2 = new Hero;//free(h2);~Hero() {cout << "Hero 析构函数调用了" << endl;}
};struct Date{int day, month, year;
};int main(){//初始化的几种方法//1、顺序初始化node node1st={1,2,"node1st"};// node node1st;cout<<node1st.name<<"---"<<"size:"<<sizeof(node1st)<<endl;//2、指定初始化(点号+赋值符号或者使用冒号)struct node node2st={.id=2,num:5,name:"node2st"};cout<<node2st.name<<endl;//3、构造函数初始化//构造函数初始化常见于 C++ 代码中,因为 C++ 中的 struct 可以看作 class,结构体也可以拥有构造函数//struct 如果定义了构造函数的话,就不能用大括号进行初始化了,即不能再使用指定初始化与顺序初始化了node_t node3st(5,6,"node3st");cout<<node3st.name<<endl;//4、使用calloc分配并置为0node_t * node4st=(node_t *)calloc(1,sizeof(struct node));std::cout << node4st->name<<"--point size:"<<sizeof(node4st)<<endl;//5、使用new动态创建结构体变量时,必须是结构体指针类型node_t * node5st=new node();//虽说delete可以释放calloc的内存,但是我编译器还是报错了,还是得用free来释放delete node5st;// free(node5st);//6、结构体变量使用结构体+()可以初始一个结构体变量的(也就创建了一个新的引用)node node6st;node6st=node();cout<<node6st.name<<"--node6st--"<<"size:"<<sizeof(node6st)<<endl;//7、以前是可以部分初始化的,但部分初始化只限于初始化开头的变量,如果某个结构成员未被初始化,则所有跟在它后面的成员都需要保留为未初始化//不过我的编辑器部分初始化也报错了,感觉可能部分初始化风险较大吧// Date birthday = {23,8};//结构体赋值的几种方法//变量的赋值和初始化是不一样的,初始化是在变量定义的时候完成的,是属于变量定义的一部分,赋值是在变量定义完成之后想改变变量值的时候所采取的操作//无法使用node1st={1,2,"node1st"};这种方式赋值//1、使用 memset 对结构体变量进行置空操作//如下,使用memset进行赋值时,结构体里不能是string类型,但可以是char或char*charnode_t node1ass;// 按照编译器默认的方式进行初始化(如果node4st是全局静态存储区的变量,默认初始化为0,如果是栈上的局部变量,默认初始化为随机值)memset(&node1ass,0,sizeof(charnode_t));cout<<node1ass.name<<endl;//2、依次给每一个结构体成员变量进行赋值node_t node2ass;node2ass.id=5;node2ass.name="node2ass";cout<<node2ass.name<<endl;//3、使用已有的结构体变量给另一个结构体变量赋值(结构体变量之间是可以相互赋值的)node_t node3ass;node3ass=node1st;cout<<node3ass.name<<endl;//ps:初始化与赋值有着本质的区别,初始化是变量定义时的第一次赋值,赋值则是定义之后的值的变更操作node3ass.name="node3ass";cout<<node3ass.name<<"--"<<node1st.name<<endl;//4、使用指针指向一个结构体变量node_t *node4ass;// node4ass=&node1st;node4ass=node4st;cout<<node4ass->name<<endl;node4ass->name="node4ass";// cout<<node4ass->name<<"--"<<node1st.name<<endl;cout<<node4ass->name<<"--"<<node4st->name<<endl;//1、delete主要用来释放new分配的内存,但delete 也可以用来释放由 malloc 和 calloc 分配的内存// delete node4ass;// delete node4st;//2、free主要用来释放由 malloc 和 calloc 分配的内存,也可以释放new 分配的内存,但不推荐使用free(node4ass);// free(node4st);// cout<<node4ass->name<<"--"<<node4st->name<<endl;//char *c1 = (char *)malloc(1, 10);//c1[0] = 'a';//delete[] c1;//经过 delete 释放过后,指针变成了野指针,此时再访问内存将是非法的,没有任何数据的,所以会显示乱码//free(c1);//不要使用 free 去释放由 new 分配的内存,因为它 不会去触发析构函数return 0;
}

运行结果

node1st---size:40
node2st
node3st
--point size:8
--node6st--size:40node2ass
node1st
node3ass--node1stnode4ass--node4ass

二、容器操作备忘

  1. vector容器的操作
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<vector>
#include<list>
#include<algorithm>
using namespace std;void myprint(int val){cout<<val<<endl;
}int main(){//容器初始化的几种方法://1、默认初始化,都是空std::vector<int> vec1;// cout<<vec1[0]<<endl;//2、列表初始化std::vector<int> vec2={1,2,3,5};cout<<vec2[0]<<endl;//3、拷贝初始化std::vector<int> vec3=vec2; //4、填充初始化std::vector<int> vec4(5, 10); // 创建一个包含5个值为10的元素的vector//初始化一个尺寸为6的容器数组std::vector<int> vec44(6);cout<<vec44[0]<<"-vec44 size:"<<vec44.size()<<endl;//5、使用迭代器进行初始化std::vector<int> vec5 = {8, 2, 3, 4, 5};//不是最高效的方法,因为它涉及到元素的复制std::vector<int> vec5s(vec5.begin()+1, vec5.end());cout<<"vec5s[0]:"<<vec5s[0]<<endl;std::list<int> lst1(vec5.begin(), vec5.end());//6、使用emplace方法进行初始化std::vector<std::string> vec6;vec6.emplace_back("Hello, World!");cout<<vec6[0]<<endl;std::vector<std::pair<int, std::string>> vecpair;vecpair.emplace_back(1, "one");  // 使用emplace方法初始化cout<<"vecpair[0].second:"<<vecpair[0].second<<endl;//7、使用std::move进行初始化//C++11引入了右值引用和std::move,可以将对象的资源从一个对象移动到另一个对象,而不是复制它们。//这对于那些拥有大量资源的对象(如std::vector或std::string)来说是非常有用的std::vector<int> vec7 = std::move(vec5);cout<<"vec7:"<<vec7[0]<<endl;//移动后vec5数组再也无法使用// cout<<"vec5:"<<vec5[0]<<endl;//容器的相关操作://rbegin() 返回Vector尾部的逆迭代器//1、末尾添加新元素vec2.push_back(8);//2、判空,非空为0cout<<"empty:"<<vec2.empty()<<endl;//3、输出尺寸cout<<"size:"<<vec2.size()<<endl;//4、遍历for(vector<int>::iterator it=vec2.begin();it!=vec2.end();it++){cout<<*it<<endl;}for(auto val: vec2)cout<<"auto:"<<val<<endl;//5、指定位置插入vec2.insert(vec2.begin()+2,88);//6、删除最后一个元素vec2.pop_back();//7、删除指定位置的元素vec2.erase(vec2.begin());//再次遍历,需要包含algorithm的头文件for_each(vec2.begin(), vec2.end(), [](int val)->void { cout << val << endl;});//8、返回特定元素:cout<<"vec2[1]:"<<vec2[1]<<endl;cout<<"vec2.at(1):"<<vec2.at(1)<<endl;cout<<"vec2.front():"<<vec2.front()<<endl;cout<<"vec2.back():"<<vec2.back()<<endl;//9、assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身vector<int>vec8;vec8.assign(5,10);//10、清空vec2.clear();cout<<"size:"<<vec2.size()<<"capacity:"<<vec2.capacity()<<endl;//11、重新配置容器长度vec2.resize(5);cout<<"size:"<<vec2.size()<<"capacity:"<<vec2.capacity()<<endl;//12、互换容器vec2.swap(vec7);for(auto val: vec2)cout<<"vec2:"<<val<<endl;//13、拷贝容器vec5.resize(5);copy(vec2.begin()+2,vec2.end(),vec5.begin());for(auto val: vec5)cout<<"vec5:"<<val<<endl;//14、排序-正向排序sort(vec5.begin(), vec5.end());for(auto val: vec5)cout<<"sort vec5:"<<val<<endl;//反向排序// sort(vec5.rbegin(), vec5.rend(), greater<int>());sort(vec5.rbegin(), vec5.rend(), less<int>());for(auto val: vec5)cout<<"anti sort vec5:"<<val<<endl;//15、反转容器内容reverse(vec5.begin(),vec5.end());cout<<"afer reverse:"<<endl;for_each(vec5.begin(),vec5.end(),myprint);//链表//合并两个list,按照指定的顺序排序//void merge( list &lst, Comp compfunction ); reurn 0;
}

输出:

1
0-vec44 size:6
vec5s[0]:2
Hello, World!
vecpair[0].second:one
vec7:8
empty:0
size:5
1
2
3
5
8
auto:1
auto:2
auto:3
auto:5
auto:8
2
88
3
5
vec2[1]:88
vec2.at(1):88
vec2.front():2
vec2.back():5
size:0capacity:8
size:5capacity:8
vec2:8
vec2:2
vec2:3
vec2:4
vec2:5
vec5:3
vec5:4
vec5:5
vec5:0
vec5:0
sort vec5:0
sort vec5:0
sort vec5:3
sort vec5:4
sort vec5:5
anti sort vec5:5
anti sort vec5:4
anti sort vec5:3
anti sort vec5:0
anti sort vec5:0
afer reverse:
0
0
3
4
5
  1. map操作
    unordered_map 是关联容器,含有带唯一键的键(key;it->first)-值(value;it->second) pair 。搜索、插入和元素移除拥有平均常数时间复杂度。

元素在内部不以任何特定顺序排序,而是组织进桶中。元素放进哪个桶完全依赖于其键的哈希。这允许对单独元素的快速访问,因为一旦计算哈希,则它准确指代元素所放进的桶。

由于unordered_map内部采用的hashtable的数据结构存储,所以,每个特定的key会通过一些特定的哈希运算映射到一个特定的位置,我们知道,hashtable是可能存在冲突的(多个key通过计算映射到同一个位置),在同一个位置的元素会按顺序链在后面。所以把这个位置称为一个bucket是十分形象的(像桶子一样,可以装多个元素)。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<vector>
#include<list>
#include<unordered_map>
#include<algorithm>
using namespace std;void myprint(int val){cout<<val<<endl;
}int main(){unordered_map<int,string> mtable1={ {1,"This"},{2,"is"} };// 1、移动构造函数unordered_map<int, string> mtable2 = move(mtable1);//返回根据系统或库实现限制的容器可保有的元素最大数量,即对于最大容器的 std::distance(begin(), end())cout<<"mtable1.size():"<<mtable1.size()<<"-max_size:"<<mtable1.max_size()<<endl;for(auto it=mtable1.begin();it!=mtable1.end();it++){cout<<"mtable1:"<<it->first<<it->second<<endl;}// 2、范围构造函数unordered_map<int, string> mtable3(mtable2.begin(), mtable2.end());//map的操作//1、插入mtable3.insert({5,"an"});//再次插入插不进去了mtable3.insert({5,"qq"});//如果insert_or_assign的值为5则会覆盖上面的key的值mtable3.insert_or_assign(3,"apple");mtable3.emplace(7,"U pan");mtable3.try_emplace(8,"V pan");//2、遍历for(auto it=mtable3.begin();it!=mtable3.end();it++){cout<<"mtable3:"<<it->first<<it->second<<endl;}//3、擦除mtable3.erase(mtable3.begin());for(auto it=mtable3.begin();it!=mtable3.end();it++){cout<<"erase mtable3:"<<it->first<<it->second<<endl;}//4、交换两个表mtable3.swap(mtable2);mtable3[1]="hellow";for(auto it=mtable3.begin();it!=mtable3.end();it++){cout<<"mtable3:"<<it->first<<it->second<<endl;}//5、查找auto item=mtable3.find(2);cout<<"mtable3 find:"<<item->first<<"->"<<item->second<<endl;//通过equal_range进行遍历auto range=mtable3.equal_range(2);for(item=range.first;item!=range.second;item++){cout<<"mtable3 equal_range:"<<item->first<<"->"<<item->second<<endl;}//使用find判断map中是否有某个键if(mtable2.find(5)!=mtable2.end()){cout<<"find(5) in mtable2!"<<endl;}//下面的语句有问题,不能直接通过-1移动指针位置。// auto at=mtable2.end()-1;//因为end()返回的是最后一个元素边界,属于数组上沿,下面的输出就越界了,map最后一个元素应该是mtable2.end()-1// cout<<"mtable2.end():"<<mtable2.end()->second<<endl;//6、返回桶数int num=mtable2.bucket_count();cout<<"bucket_count:"<<num<<endl;for(int i=0;i<num;i++){cout << "buckst's load_factor:(每个桶的平均元素数量) " << mtable2.load_factor() <<"  ";cout<<"bucket_size:"<<mtable2.bucket_size(i)<<endl;for(auto mid=mtable2.begin(i);mid!=mtable2.end(i);mid++){cout<<"["<<mid->first<<"->"<<mid->second<<"]";}cout<<endl;}cout << "2 in the bucket" << mtable2.bucket(2) << endl;//7、设置桶数为 count 并重哈希容器,即考虑桶总数已改变,再把元素放到适当的桶中mtable2.rehash(2);for (int i = 0; i < num; i++){cout << "buckst's load_factor:(每个桶的平均元素数量) " << mtable2.load_factor() << "  ";cout << "bucket[" << i << "]" << ".size():" << mtable2.bucket_size(i) ;cout << endl;}//8、reserve 设置桶数为适应至少 count 个元素,而不超出最大加载因子所需的数,并重哈希容器,即考虑桶数已更改后将元素放进适合的桶。return 0;
}

对应输出

mtable1.size():0-max_size:384307168202282325
mtable3:8V pan
mtable3:7U pan
mtable3:3apple
mtable3:5an
mtable3:1This
mtable3:2is
erase mtable3:7U pan
erase mtable3:3apple
erase mtable3:5an
erase mtable3:1This
erase mtable3:2is
mtable3:2is
mtable3:1hellow
mtable3 find:2->is
mtable3 equal_range:2->is
find(5) in mtable2!
bucket_count:13
buckst's load_factor:(每个桶的平均元素数量) 0.384615  bucket_size:0buckst's load_factor:(每个桶的平均元素数量) 0.384615  bucket_size:1
[1->This]
buckst's load_factor:(每个桶的平均元素数量) 0.384615  bucket_size:1
[2->is]
buckst's load_factor:(每个桶的平均元素数量) 0.384615  bucket_size:1
[3->apple]
buckst's load_factor:(每个桶的平均元素数量) 0.384615  bucket_size:0buckst's load_factor:(每个桶的平均元素数量) 0.384615  bucket_size:1
[5->an]
buckst's load_factor:(每个桶的平均元素数量) 0.384615  bucket_size:0buckst's load_factor:(每个桶的平均元素数量) 0.384615  bucket_size:1
[7->U pan]
buckst's load_factor:(每个桶的平均元素数量) 0.384615  bucket_size:0buckst's load_factor:(每个桶的平均元素数量) 0.384615  bucket_size:0buckst's load_factor:(每个桶的平均元素数量) 0.384615  bucket_size:0buckst's load_factor:(每个桶的平均元素数量) 0.384615  bucket_size:0buckst's load_factor:(每个桶的平均元素数量) 0.384615  bucket_size:02 in the bucket2
buckst's load_factor:(每个桶的平均元素数量) 0.714286  bucket[0].size()1
buckst's load_factor:(每个桶的平均元素数量) 0.714286  bucket[1].size()1
buckst's load_factor:(每个桶的平均元素数量) 0.714286  bucket[2].size()1
buckst's load_factor:(每个桶的平均元素数量) 0.714286  bucket[3].size()1
buckst's load_factor:(每个桶的平均元素数量) 0.714286  bucket[4].size()0
buckst's load_factor:(每个桶的平均元素数量) 0.714286  bucket[5].size()1
buckst's load_factor:(每个桶的平均元素数量) 0.714286  bucket[6].size()0

其他备忘
  • 默认构造函数:仅当类中不包含用户声明的构造函数时才生成。
  • 析构函数:默认生成,当基类的析构函数为虚时,派生类的默认析构函数为虚函数。
  • 拷贝构造函数:仅当类中不包含用户声明的拷贝构造函数时才生成。如果该类声明了移动操作,那么拷贝构造函数将被定义为删除的。
  • 拷贝赋值运算符:仅当类中不包含用户声明的拷贝赋值运算符时才生成。如果该类声明了移动操作,那么拷贝赋值运算符将被定义为删除的。
  • 移动构造函数和移动赋值运算符:仅当类中不包含用户声明的拷贝操作、移动操作和析构函数时才生成。

这篇关于201_C++基础的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/982253

相关文章

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

从基础到高级详解Go语言中错误处理的实践指南

《从基础到高级详解Go语言中错误处理的实践指南》Go语言采用了一种独特而明确的错误处理哲学,与其他主流编程语言形成鲜明对比,本文将为大家详细介绍Go语言中错误处理详细方法,希望对大家有所帮助... 目录1 Go 错误处理哲学与核心机制1.1 错误接口设计1.2 错误与异常的区别2 错误创建与检查2.1 基础

Spring的基础事务注解@Transactional作用解读

《Spring的基础事务注解@Transactional作用解读》文章介绍了Spring框架中的事务管理,核心注解@Transactional用于声明事务,支持传播机制、隔离级别等配置,结合@Tran... 目录一、事务管理基础1.1 Spring事务的核心注解1.2 注解属性详解1.3 实现原理二、事务事

C++读写word文档(.docx)DuckX库的使用详解

《C++读写word文档(.docx)DuckX库的使用详解》DuckX是C++库,用于创建/编辑.docx文件,支持读取文档、添加段落/片段、编辑表格,解决中文乱码需更改编码方案,进阶功能含文本替换... 目录一、基本用法1. 读取文档3. 添加段落4. 添加片段3. 编辑表格二、进阶用法1. 文本替换2

C++中处理文本数据char与string的终极对比指南

《C++中处理文本数据char与string的终极对比指南》在C++编程中char和string是两种用于处理字符数据的类型,但它们在使用方式和功能上有显著的不同,:本文主要介绍C++中处理文本数... 目录1. 基本定义与本质2. 内存管理3. 操作与功能4. 性能特点5. 使用场景6. 相互转换核心区别

Java中最全最基础的IO流概述和简介案例分析

《Java中最全最基础的IO流概述和简介案例分析》JavaIO流用于程序与外部设备的数据交互,分为字节流(InputStream/OutputStream)和字符流(Reader/Writer),处理... 目录IO流简介IO是什么应用场景IO流的分类流的超类类型字节文件流应用简介核心API文件输出流应用文

C++右移运算符的一个小坑及解决

《C++右移运算符的一个小坑及解决》文章指出右移运算符处理负数时左侧补1导致死循环,与除法行为不同,强调需注意补码机制以正确统计二进制1的个数... 目录我遇到了这么一个www.chinasem.cn函数由此可以看到也很好理解总结我遇到了这么一个函数template<typename T>unsigned

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

从基础到高级详解Python数值格式化输出的完全指南

《从基础到高级详解Python数值格式化输出的完全指南》在数据分析、金融计算和科学报告领域,数值格式化是提升可读性和专业性的关键技术,本文将深入解析Python中数值格式化输出的相关方法,感兴趣的小伙... 目录引言:数值格式化的核心价值一、基础格式化方法1.1 三种核心格式化方式对比1.2 基础格式化示例