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)
- int a[5]={0};
- memset(a, 0, sizeof a);
以上两种方法仅适用于将 a 中的值全部初始化为 0
函数
若函数返回 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++三种常见的实例化方法
- 静态实例化:在程序的全局或静态作用域中定义并初始化一个对象,该对象在程序整个生命周期内只存在一个实例。
- 堆实例化:使用 new 运算符在动态存储区域中分配内存并实例化一个对象。这样创建的对象在程序运行期间一直存在,直到使用 delete 运算符显式释放其内存。
- 栈实例化:在函数或代码块的作用域中定义并实例化一个对象,该对象的生命周期与所在的函数或代码块相同。对象在离开该作用域时自动销毁。
静态实例化的例子
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();
}