指针、链表、new、delete、引用的理解

struct Node
{
    Time_t tm;
    char id[20];
    char op[20];
    Node* next;
}

最让我迷的地方就是:Node* next。

先理解指针:

(杀千刀的真难)

指针,看开头差不多就能理解干嘛用的了👈这讲的是真详细

简单来说,我感觉可以把指针认为是一个char,然后这个char里,记录了它所需要记录的目标的地址。然后这个char肯定是默认的,因为地址肯定是个char,所以想要去更详细地表述它的特征,就在前面加个【它所能指的类型】。

我总是不理解为什么那个*是和Node连着的。后来明白了,实际上是从后往前看的:变量名叫next,往前走,看到了*,说明这个变量是个指针,再往前,看到了Node,说明这个指针next是指向Node结构的一个指针,也就是它所保存的,是具有Node结构的变量的起始地址。

然后很特殊的一点,就是,在声明一个指向Node结构的指针data后,这个data想要访问它所指的内部数据的时候,不像原本的结构a.tm这样访问,而是需要data->tm来访问。指针就用箭头,很合理。

指针相等

*ptr = NULL;

data->next = head;
head = data;

*ptr = NULL; 是常见指针初始化的方式。

data->next是一个指向Node结构的一个指针,第一句就是让data->next指向head所指的地址(或者说是head存储的地址值赋给了data->next)。

第二句就是让head这个指针指向data这个指针指的地方,也就是data存储的地址值给了head。【注意,data->next和data指的不是一个地方。】

new的用法

new是一个动态分配内存的运算符。不需要包含其他头文件。

Node * data = new Node;

创建一个指向具有Node结构的指针data,它指向了一个被new出来的区域【这个区域是空的】。然后通过data->**来填充数据,并通过上面的相等来调整位置。

【好的,指针先告一段落】

首先,结构有这些东西,是没有问题的。在定义一个【具有这样结构的变量】的时候,使用

Node *head = NULL;
while(!fin.eof()){
    char tmp;
    Node * data = new Node;
    
    fin>>data->tm.year>>tmp        //tm是定义的一个存储有6个整数来表示时间的结构体。
       >>data->tm.month>>tmp
    ...
    fin>>data->op;
    data->next = head;
    head = data;
}

head不停更改其所指的地方,最后指向了最高的那个,链表就此成型😭😭😭

链表遍历与释放
while(head)
{
    cout << head->id << endl;
    head = head->next;
}

head不是NULL时,就输出。尾部是NULL,所以可以用这一点来设置循环条件。

for(Node * p = head;p != NULL; p = p->next)
...

👆是for循环写法。很有意思的就是最后一点循环做法p = p->next。

【【【从当前元素可以知道下一个元素!!这是单向链表的典型特征。】】】

delete的用法

基础用法:

int * p = new int;
char *q = new char[10];        //10可以是个变量,即char[m]],在使用过程中确定
delete p;        //删除p所指的内存单元
delete[] q;        //删除q所指的多个单元组成的内存块

遍历删除链表节点:

while(head)
{
    Node * tmp = head;
    head = head->next;
    delete tmp;
}

先用一个临时指针指向要删除的第一个节点,然后再让头指针指向第二个节点,【顺序不能反,因为如果head先指向第二个节点,那第一个就找不到了。】最后删除这个临时指针指的内容。

其他关于*、&和什么都没有的指针
#include<iostream>
using namespace std;
int main()
{
    int a = 1;
    int * p;
    p = &a;
    cout<<p<<" "<<*p<<" "<<a<<endl;
    return 0;
}

输出为:

什么都不加,那么p就是一个存储着a的地址的变量,【可以理解为把a的地址赋给了p】所以输出p也就是输出a的地址这个值。

加了*,就是访问p所存储的地址,也就是a的值。

加了&【取址符】,就是访问这个变量(不管是a还是p)的地址名字。

引用

&用在【左值引用】里

int & v1 = v0;
int & q = struct1.struct2.struct3.p;
void swap(int &a,int &b)
{
    temp = a;
    a = b;
    b = temp;
}

上面的代码的意思就是,v1是v0的一个别名。比如v0=5,那么v1=v0。具体作用就是,当遇到许多结构嵌套的时候,可以取个别名来代指这个变量,方便书写。或在函数里,直接引用原调用地的变量,就不再需要另外开辟内存去存储和运算了。

【右值引用】

右值:不能取地址的,没有名字、临时的、不可修改的变量。它只能出现在赋值语句的右边可以被移动和复制。左值只能被复制。它主要为了支持移动语义和完美转发【待查找】

int && sum = 3+4;
float &&res = ReturnRvalue(f1,f2);
void acceptRvalue(T &&res)        //减少临时变量拷贝开销

  • 12
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值