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++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现