本文主要是介绍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
二、容器操作备忘
- 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
- 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++基础的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!