函数参数的三种传递方式
1、值传递,与C语言一致的一种传递方式,具有形参和实参,形参是实参的的副本,形参和实参使用不同的地址,需要额外的存储空间,在函数结束时会释放占用的存储空间。
2、地址传递,也是与C语言一致的传递方式,传入的是参数的地址,在函数中对传入参数的修改也会影响到原始参数本身,这种方式同样需要额外的存储空间,只不过该空间是用来存放参数的地址。
3、引用传递,C++特有的方式,传入的是参数的别名,其实际效用和地址传递一样,但是不需要额外的空间。
https://blog.csdn.net/mjl960108/article/details/53559098 中有这三种方式的例子
func(int number[],int length){
…
}
number是一个地址,number可以获取数组第一个元素的值
常量指针和指针常量
使用指针时涉及到两个对象:该指针本身和被它所指的对象。将一个指针的声明用const“预先固定”将使那个对象而不是使这个指针成为常量。要将指针本身而不是被指对象声明为常量,必须使用声明运算符const。
参考 http://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777416.html
变量的输入输出模板
一、不定长数组
用vector实现:
#include <vector>
using namespace std;
vector<int> numbers;
while(cin>>value) {
numbers.push_back(value);
}
有些时候长度也是作为输入变量
vector<int> numbers;
cin>>n;
numbers.assign(n,0);
for(int i=0;i<n;i++) cin>>numbers[i];
可以像给数组初始化那样给vector初始化,但是在有些编译器好像不能成功?
vector<int> numbers{1,2,3,4};
是否可以不用常量去初始化数组的长度
比如
int N=10;
int numbers[N]={0};
C99标准的编译器是支持这种做法的,之前的不支持,所以需要看环境。
非常奇怪的是,如果只是定义而不做初始化,那么依然是对的!
int N=10;
int numbers[N] //不会报错;
由于没法初始化,如果要定义一个不定长的全零数组,需要逐一赋值,非常耗时,还不如用vector方便,这是在牛客clang3.9上测试成功的安利
int *numbers = new int[length];
for(int i=0;i<length;i++)
numbers[i]=0;
新建节点
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
//错误做法
ListNode* pNode;
pNode->val=2; //此时pNode只是声明了类型,但没有初始化,pNode==nullptr,也不能对val和next赋值
//正确做法1
ListNode* pNode=p1; //p1是一个已知的确定节点
//正确做法2
ListNode* pNode=new ListNode(val); //val是任意数值
//正确做法3
ListNode* pNode;
pNode = new ListNode(val);
vector、queue、stack的push和pop
1、queue
push;pop;front;back
二维向量的坑
vector<vector> A;//错误的定义方式
vector<vector > A;//正缺的定义方式,多了一个空格
类型转换
链接:https://www.jianshu.com/p/1a2310f1b58e
static_cast
通常这个运算符用来进行数值类型间的转化,比如int到float,也可以是自定义的某些数据类型的转化。这个操作符通常也可以用于类指针之间的转化,但是这个运算符在父类到子类的转化中没有做检查并不安全。
dynamic_cast
这个操作符专门用于指针或者引用操作,也可以进行point -> void 的操作。对父类和子类之间的指针装换这个操作具有类型检查的功能,比较安全!这里要注意的是,如果父类和子类之间没有虚函数(文档称为多态类),那么dynamic_cast不能执行转换,应采用static_cast来进行转换。
附上一段qsort中compare方法的例子
int compare (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
在这句话里 a,b肯定是一个指针变量。(int *)a是表示把a强制转换成一个int型的指针。
如果以前a是char型,编译器会认为a指向的那一个字节的内存单元是a里面的东西,把a转换成int型,编译器会认为a指向的连续四个字节里的东西都是a里面的。
(int )a就是取a指向的内容的意思,跟a的那个作用一样
类中的坑
1、类中的静态常量声明只可以是整形。
class B{
const static b = 1.0;//错误
constexpr static b = 1.0;//正确
}
2、非const的静态值初始化必须在类外。non-const static data member must be initialized out of line
3、静态成员函数和非静态成员函数
在类中定义的静态成员函数和普通函数是一样的
在类中定义的非静态成员函数是稍有不同,它默认并且隐藏的首个参数是Solution* this指针
这也使得类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致了它仅能访问类的静态数据和静态成员函数。
static的作用
1、隐藏。static修饰的全局变量在其他文件中不可见。
2、把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围
3、默认初始化为0(static变量)
4、在类中的使用https://www.cnblogs.com/songdanzju/p/7422380.html
sort和qsort
qsort是对连续内存内的数据做排序
sort对STL中的数据类型都可以做排序,而且排序的方法有对应优化
在任何情况下,sort的效率都是比qsort高的
https://blog.csdn.net/qq_26341675/article/details/70199778
sort与greater\less
sort(a ,a + len, greater<int>());//内置类型的由大到小排序
sort(a, a + len, less<int>());
构造函数列表成员初始化的顺序问题
成员的初始化顺序与各个成员在类的定义中出现的顺序一致,而与构造函数初始值列表中的前后位置关系无关
class A
{
public:
A(int val):j(val),i(j){ }
//由于i比j先定义,所以i比j先初始化,因此是拿j去初始i,在用val去初始化j
private:
int i;
int j;
}
不要用全局变量,用单例模式
?
数组的初始化
1、直接用{}:a[10]={},就可以让a[10]数组中的所有元素全为0;
2、也可以{}内包含0:a[10]={},也可以让a[10]数组中的所有元素全为0;
注意:{}内写一个值只会让第一个元素为这个值,后面的依旧是0:a[3]={5},数组实际上被初始化为{5,0,0}
数组初始化为同一个数
1、使用(C++)或<string.h>©中的memset()函数
#include <stdio.h>
int main(){
int a[10];
memset(a,5,sizeof(a));
for(int i=0;i<10;i++)
printf("%d",a[i]);
return 0;
}
2、使用中的fill()函数
#include <iostream>
#include <algorithm>
using namespace std;
int main(){
int a[10];
fill(a,a+5,233);
for(int i=0;i<10;i++)
cout<<a[i]<<" ";
return 0;
}
memset只建议初始为-1或0,fill可以是任何数,但是memset更快。
原文:https://blog.csdn.net/zhanshen112/article/details/84956950
未初始化变量
全局数组默认初始化为0
局部数组随机初始化,但是加static修饰会初始化为0
无论是全局还是局部,单个整型、浮点数默认初始化为0(待商榷)
无论是全局还是局部,new一个空间都默认初始化为0
类内成员变量随机初始化
指针常量和常量指针
指针常量——指针类型的常量(int *const p),指针永远指向一个固定地址,但地址内的内容可变
常量指针——指向“常量”的指针(const int *p, int const *p),指针指向的内容不可变
{}内的变量
int a=10;
if(1){
int a=20;
cout<<a<<endl;
}
cout<<a<<endl; //输出是20,10
{}内定义的变量只在{}内有效,如果与{}外定义的变量同名,会暂时覆盖掉{}外的变量,出去后恢复成{}外原本的值
vector和list有什么区别
https://www.cnblogs.com/shijingjing07/p/5587719.html
1.vector数据结构
vector和数组类似,拥有一段连续的内存空间,并且起始地址不变。
因此能高效的进行随机存取,时间复杂度为o(1);
但因为内存空间是连续的,所以在进行插入和删除操作时,会造成内存块的拷贝,时间复杂度为o(n)。
另外,当数组中内存空间不够时,会重新申请一块内存空间并进行内存拷贝。
2.list数据结构
list是由双向链表实现的,因此内存空间是不连续的。
只能通过指针访问数据,所以list的随机存取非常没有效率,时间复杂度为o(n);
但由于链表的特点,能高效地进行插入和删除。
因此,如果需要像数组那样随时存取第i个位置的数据,还是用vector更合适,即使它插入删除复杂度为O(n)。
如果不需要进行这样的随机存取(list根本没有重载[ ]符号),用list更好,因为插入删除的效率是O(1)
注意!!!
list也没有重载+,-,+=,,-=,>, <,只重载了++,–,因此要实现+1操作只能用自加!这也是offer62中有current++后又–这种奇怪的操作的原因。
而vector对这些符号都进行了重载
类对象和类指针的区别
https://blog.csdn.net/keneyr/article/details/89364275
用一个类对象给另一个类对象赋值时,不会改变地址,只会改变成员变量的值,两个对象仍是独立的
整型变量被赋值成小数
小数部分全部舍弃
int a=1.5;
cout<<a; //输出1
堆、栈、堆区、栈区
1、堆、栈是数据结构中的概念
栈区和堆区的区别:
1)申请方式: 栈区内存由系统自动分配,函数结束时释放;堆区内存由程序员自己申请,并指明大小,用户忘释放时,会造成内存泄露,不过进程结束时会由系统回收。
2)申请后系统的响应: 只要栈的剩余空间大于所申请的空间,系统将为程序提供内存,否则将报异常提示栈溢出;堆区,空闲链表,分配与回收机制,会产生碎片问题(外部碎片)–>(固定分区存在内部碎片(分配大于实际),可变分区存在外部碎片(太碎无法分配))。
3)申请大小的限制:栈是1或者2M,可以自己改,但是最大不超过8M;堆,看主机是多少位的,如果是32位,就是4G
4)申请效率:栈由系统自动分配,速度较快,程序员无法控制;堆是由new分配的内存,一般速度较慢,而且容易导致内存碎片,但是用起来方便!
5)存储内容:栈,函数调用(返回值,各个参数,局部变量(静态变量不入栈));堆,一般在堆的头部用一个字节存放堆的大小,堆中的具体内容由程序员安排。
6)存取效率的比较:堆需要两次访问内存,一次获取地址,一次获取内容,栈只需要访问一次内存
7)管理方式不同:栈,数据结构中的栈;堆,链表
8)生长方向:栈,高到低;堆,低到高
参考:https://www.cnblogs.com/qiuly/p/8576149.html
构造函数的可访问性
构造函数可以是public(默认),也可以是private,如果是private,其他类不能直接调用该类生成新的对象,也就避免了同一个类被反复创建的情况,这种情况下,该类只有一个对象实例,也称为单例模式
new 和 malloc
new一个对象时,不仅会分配内存,还会自动调用构造函数,malloc只会分配内存,但是不会去自动调用构造函数
获取vector的最大值以及最大值的索引
用max_element和distance方法
auto pMax = max_element(nums.begin(),nums.end()); //返回的是一个iterator
cout<<*pMax;
int index = distance(nums.begin(),pMax);
greater<T> 和 less<T>
greater 相当于大于号>,less相当于小于号<,在STL中的有序数据结构,可以用它们对元素进行排序,并且是在插入时就插入到正确的位置,这些数据结构的底层通常是某种树结构,能够实现O(logn)的有序插入,比如红黑树,堆等。举个例子
multiset<int, greater<int> > //该multiset是有序的,按照从大到小排序,for遍历时自动从大到小,即降序,可以用来实现大根堆
set<int,greater<int> >
map<int, int, greater<int>> //根据键值从大到小排序,注意是键值!!
multimap<int, int, greater<int>>
//非常奇怪的是,跟堆有关的,比如priority_queue和push_heap,greater<int>实现的是升序,
//用priority_queue实现大根堆,刚好相反
priority_queue<int,vector<int>,less<int>> min;
//默认是greater<int>,即小根堆
pair怎么比较大小
greater<pair<int, int> > 默认先比较第一个的大小,如果相等,再比较第二个数的大小
本文深入探讨C++中的函数参数传递方式,包括值传递、地址传递和引用传递的细节与区别。同时,讲解了变量的输入输出模板,类型转换,以及vector、queue、stack的使用技巧。此外,还分析了类中的常见误区,如静态常量声明、构造函数初始化顺序等,提供了数组初始化、指针操作的最佳实践。
&spm=1001.2101.3001.5002&articleId=89493161&d=1&t=3&u=c233d0fc666141b9b6fa2b6898f96305)
286

被折叠的 条评论
为什么被折叠?



