【考研】C++查缺补漏

C语言详解:结构体
模板类/模板函数 template 的用法(超详细)
template:模板

数据类型强制转换:
(int)2.5 = 2 (向下取整)
int m = (a+b)/2 :此时m强行向下取整

C语言中数组长度的计算方法总结(sizeof与strlen)

循环

while (cin >> x){}
cin函数,输入NULL时返回0,输入其他值返回它的地址

字符串

C++ 字符串
C++ string详解,C++字符串详解
C++字符串指针(指向字符串的指针)

数组

初始化数组的常用方法(常见的初始化为 0)

  1. int a[5]={0};
  2. memset(a, 0, sizeof a);

以上两种方法仅适用于将 a 中的值全部初始化为 0

memset()函数的用法详解

函数

若函数返回 void,但又想通过 return 来跳出函数,则直接写 return;

void function(){
    return;
}

结构体

typedef struct xxx {} yyy;yyy为结构体xxx的别名,是一种数据类型,需要实例化。
定义结构体 typedef struct 的用法总结

在结构体别名中定义结构体指针

typedef struct DNode{
	ElemType data;
	DNode* prior, * next;
}DNode, * DLinkList;  // * DLinkList 就是指向DNode类型的指针,声明时用DNode和DLinkList都可以

指针

C++指针详解
&:取地址
*:取地址里面的值
向函数传递数组的写法
用“->”的情况:
A是一个类 class / struct
p是一个指向A类型的指针,那么用p访问A中的成员变量和函数时,使用p->x,p->f(x)来访问。

向函数传入变量的指针和引用的区别
传入指针时,函数参数中是对指针的定义 int* a,传入函数的是变量的地址,&a;
传入引用时,函数参数中是对原变量的引用 int &a,传入函数的是原变量,a。
总之,传入指针是 通过指针,对指针指向的内存地址进行操作;传入变量的引用是直接对原变量进行修改。二者效果一样,但是原理不一样。
只传入 int a 时, 传入的是 a 的拷贝,对 a 本身没有影响。
指针

typedef struct SqList{
	int data[MaxSize];
	int length;
};

void InitList(SqList *list){
	cout<<"type in the length of list:"<<endl;
	cin>>list->length;
	cout<<"type in the data:"<<endl; 
	for(int i = 0; i<list->length; i++)
		cin>>list->data[i];
}
int main(){
	SqList sqlist;
	InitList(&sqlist);
}

引用

typedef struct SqList{
	int data[MaxSize];
	int length;
};

void InitList(SqList &list){
	cout<<"type in the length of list:"<<endl;
	cin>>list.length;
	cout<<"type in the data:"<<endl; 
	for(int i = 0; i<list.length; i++)
		cin>>list.data[i];
}
int main(){
	SqList sqlist;
	InitList(sqlist);
}

上面两段代码,如果用指针访问结构体,则需要用->访问结构体成员;如果用原结构体,则用 . 由此可见,指针和引用的差别。

向函数中传入指针类型的数据
和上面的不同,上面传入的是变量的地址,在函数列表中被定义,成为指针。而本问题描述的是直接将指针类型的数据传入函数。

#include<bits/stdc++.h>

typedef struct DNode{
	ElemType data;
	DNode* prior, * next;
}DNode, * DLinkList;  //DLinkList为指向结构体的指针类型
 
//初始化双链表
bool InitDLinkList(DLinkList L) {  //此处和变量的指针一样,也可该写作 DNode* L
	L = (DLinkList)malloc(sizeof(DLinkList));
	if (L == NULL) {
		return false;          
	}
	L->prior = NULL;
	L->next = NULL;
	return true;
}

int main() {
	DLinkList L;  //定义指针类型数据L
	InitDLinkList(L);  //由于指针的值即为变量的地址,所以和&+变量名一样,都是将地址传入函数。
	return 0;
}

swap的例子
指针

# include<iostream>
using namespace std;

void MySwap(int* a, int* b){  //在列表中定义两个指针a,b,分别指向传入变量a,b的地址 
	int t = 0;  
	t = *a;  //交换值 
	*a = *b;
	*b = t;
	
	//错误的思路:用指针交换来交换 
	int *t = NULL;  //定义中间指针t,用于指针之间的赋值 
	t = a;
	a = b;
	b = t;
	//以上操作只是让函数内的指针ab分别指向了ba,但没有对对应地址内的值进行任何改变 
}

int main(){
	int a = 1,b = 2;
	MySwap(&a, &b);  //传入变量ab的地址 
	cout<<a<<" "<<b;
}
//向函数传入变量的地址。把函数声明和传入函数的形式整体来看,就是 int* a = &a; 
//也就是指针定义操作 

引用

# include<iostream>
using namespace std;

void MySwap(int &a, int &b){  //在列表中定义两个地址引用
	int t = 0;  
	t = a; //直接修改原变量
	a = b;
	b = t;
}

int main(){
	int a = 1,b = 2;
	MySwap(a, b);  //直接传入原始变量ab
	cout<<a<<" "<<b;
}

类和对象

类中不带返回类型的函数为构造函数。造函数可用于为某些成员变量设置初始值。
c语言malloc函数的用法和意义

C++三种常见的实例化方法

  1. 静态实例化:在程序的全局或静态作用域中定义并初始化一个对象,该对象在程序整个生命周期内只存在一个实例。
  2. 堆实例化:使用 new 运算符在动态存储区域中分配内存并实例化一个对象。这样创建的对象在程序运行期间一直存在,直到使用 delete 运算符显式释放其内存。
  3. 栈实例化:在函数或代码块的作用域中定义并实例化一个对象,该对象的生命周期与所在的函数或代码块相同。对象在离开该作用域时自动销毁。

静态实例化的例子

class MyClass {
public:
    MyClass() : m_x(0) {}
    void setX(int x) { m_x = x; }
    int getX() const { return m_x; }
private:
    int m_x;
};

MyClass globalObject;  // 全局实例

int main() {
    static MyClass staticObject;  // 静态实例
    globalObject.setX(5);
    staticObject.setX(10);
    int globalX = globalObject.getX(); // globalX = 5
    int staticX = staticObject.getX(); // staticX = 10
    // ...
    return 0;
}

上面的例子中,通过调用 setX 和 getX 来对全局对象 globalObject 和静态对象 staticObject 的成员变量进行访问。

堆实例化的例子

class MyClass {
public:
    MyClass() : m_x(0) {}
    void setX(int x) { m_x = x; }
    int getX() const { return m_x; }
private:
    int m_x;
};

int main() {
    MyClass* heapObject = new MyClass;  // 堆实例
    heapObject->setX(5);
    int heapX = heapObject->getX(); // heapX = 5
    // ...
    delete heapObject;
    return 0;
}

上面的例子中,通过调用 setX 和 getX 来对堆对象 heapObject 的成员变量进行访问。

栈实例化的例子

class MyClass {
public:
    MyClass() : m_x(0) {}
    void setX(int x) { m_x = x; }
    int getX() const { return m_x; }
private:
    int m_x;
};

void someFunction() {
    MyClass stackObject;  // 栈实例
    stackObject.setX(5);
    int stackX = stackObject.getX(); // stackX = 5
    // ...
}

int main() {
    someFunction();
    return 0;
}

上面的例子中,通过调用 setX 和 getX 来对栈对象 stackObject 的成员变量进行访问。

函数模板
若想向函数传入不同类型的数据,则还需要另外定义不同的函数。为解决该问题,引入函数模板template。

#include <iostream>
using namespace std;

template<typename T>  //定义模板数据类型 T
T add(T& a, T& b){  //把T当作一种数据类型来用
	return a+b;
}

int main()
{
	float a = 10.3, b = 20.5;  //如果是int,则直接传入函数即可
	cout<<add(a, b);
	return 0;
}

上例中,可以直接传入int/float等类型,而不用重新定义函数。

类模板
参考如下构建栈的写法,照着写就行,功能也是可以随便定义函数的数据类型

# include<iostream>
using namespace std;

const int StackSize = 1024;			//定义栈的最大长度
template<class T>
class SeqStack {					//定义顺序栈的模板类
	public:
		SeqStack() { top = -1; }	//构造函数,初始化空栈
		void Push(T x);				//入栈操作
		T Pop();					//出栈操作
		T GetTop();					//查找栈顶元素
		bool Empty();				//判别栈是否为空
	private:
		T data[StackSize];			//定义数组
		int top;					//栈顶指针
};


template<class T>
void SeqStack<T>::Push(T x) {
	if (top >= StackSize - 1) throw "上溢";
	data[++top] = x;
}

template<class T>
T SeqStack<T>::Pop() {
	if (Empty()) throw "下溢";
	return data[top--];
}

template<class T>
T SeqStack<T>::GetTop() {
	if (Empty()) throw "下溢";
	return data[top];
}

template<class T>
bool SeqStack<T>::Empty() {
	if(top == -1) return true;
	else return false;
}

int main() {
	SeqStack<int> stack;  //声明的时候要加上数据类型
	stack.Push(1);
	stack.Push(2);
	stack.Push(3);
	cout << stack.GetTop();
	cout<<endl;
	
	cout << stack.Pop();
}