首页 > 其他分享 >vector操作过程中出现的地址错误

vector操作过程中出现的地址错误

时间:2023-09-08 10:57:49浏览次数:30  
标签:int 操作过程 RE 地址 vector read root

2023-08-25 15:09:42

start writing:2023.8.25 14:15

事情的起因又是邪恶的 yqt ...

为什么每次跟他都会遇到奇怪的事情

注——这只是一个对在劳累却有趣的 OI 生涯中遇到的插曲的记录,不是专业人士,对内容的研究也只是浅尝辄止,学个经验看个乐子就好了。

结论

省流:如果你用一个指针指向 vector 中一个元素,然后再对 vector 进行一些操作,有可能导致指针指向错误地址,因为在对 vector 进行操作时,vector 中数据的地址可能会发生改变。

起因

yqt 让我用线段树打一个 sb 题,反正就是区间修改,单点查询,只不过值域范围变成了 \(N \le 10^7\) 而已,操作数还是可做的。我就说树状数组直接秒。他非要我写线段树,我说写个离散也没事啊,他又说别人都没有离散就过了(要求真多),然后我就打了一个动态开点线段树,一开始交因为数组不够大,RE 了很多点,然后调了一下也就过了。

经过

这个时候,我想到“是不是可以写一个动态数组维护呢?懒得算数组大小了。”,然后就魔改成了这样:

\(Problem\ Code\)

#include<bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
inline int read(){
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())x=(x<<3)+(x<<1)+(c^48);
    return x*f;
}
struct tree{
    int v,l=-1,r=-1;
};
int n,m,tot=-1,rt=-1;
vector<tree>tr;
inline void pushdown(int root){
    if(tr[root].l<=0)tr.push_back({0,-1,-1}),tr[root].l=++tot;
    if(tr[root].r<=0)tr.push_back({0,-1,-1}),tr[root].r=++tot;
    tr[tr[root].l].v+=tr[root].v;
    tr[tr[root].r].v+=tr[root].v;
    tr[root].v=0;
    return;
}
void update(int &root,int l,int r,int x,int y,int v){
    if(root<0)tr.push_back({0,-1,-1}),root=++tot;
    if(x<=l&&r<=y)return tr[root].v+=v,void();
    pushdown(root);
    if(mid>=x)update(tr[root].l,l,mid,x,y,v);
    if(mid<y)update(tr[root].r,mid+1,r,x,y,v);
}
int query(int &root,int l,int r,int x){
    if(root<0)tr.push_back({0,-1,-1}),root=++tot;
    if(l==r)return tr[root].v;
    pushdown(root);
    if(mid>=x)return query(tr[root].l,l,mid,x);
    else return query(tr[root].r,mid+1,r,x);
}
int main(){
    n=read(),m=read();
    while(m--){
        int opt=read(),l=read();
        if(opt&1){
            printf("%d\n",query(rt,1,n,l));
        }else{
            int r=read();
            update(rt,1,n,l,r,1);
        }
    }
}

乍眼一看确实一点毛病没有,仔细看也没有啥问题,因为我就是把数组换成 vector 了而已。然后就莫名其妙的样例都过不去到处 RE,我把 vector<tree>tr 改成 vector<tree>tr(100000) 才勉强能过样例,交上去还是 RE 一片。

为啥呢?

在这个相对复杂的代码里面调试了很久还是找不到什么问题,只是在调试的过程中经常会出现其他变量挺正常的,但是就 root 压根没有值的现象,长这个样:

然后我想,既然是vector 的问题,那是不是就不能边 push_back 边查询刚加入的值呢?做了个实验,发现可以非常正常的运行。既然这个代码太麻烦了,那就稍微简化一下吧?于是我写了以下代码(为了观赏,删去了一些无用代码):

\(Test\ Code\)

#include<bits/stdc++.h>
using namespace std;
struct tree{int v,l,r;};
inline tree New(){
	tree p;
	p.v=0,p.l=-1,p.r=-1;
	return p;
}
int tot=-1,rt=-1;
vector<tree>f;
void update(int &root){
	if(root<0)root=++tot,f.push_back(New());
	if(f.size()<=10)update(f[root].l);
}
int main(){
	tot=-1,rt=-1;
	update(rt);
	for(int i=0;i<=10;i++){
		printf("%d\n",f[i].l);
	}
}

果不其然,就简单到这种程度了还是会 RE。

加入了几个监视变量,我把所有调试按钮打开,一个一个的看过去,只看见这个 root 非常不听话,一开始挺正常的赋值,进入第二三层就变成了一些很奇怪的值 503,-17891602,514 等,到第三层结束去第四层,直接跟之前一样压根就不显示值了。

这个时候 yqt 的一点点用处就出来了,他说肯定是你这个 & 取地址有问题啊,我刚想反驳他,突然想到,是唉,如果地址指向错了,那也不差不多就是 RE 了吗??

尾声

我立马搜索:

发现:

我的天哪,这人出现的问题居然跟我出奇的一致,那就相信他好了。

我这时又给监视加了一个 &f[0].l 看在修改过程中地址有没有改变,然后就出现了下面一幕:

然后就不出所料的 RE 了。

大概是 vector 为了新加内容,申请空间的时候,地址发生了一些不大但很关键的变化,反映到程序上就是直接访问到错误地址导致 Segmentation fault。仔细看不难发现我这里展示的 &f[0].l 是先变化了一点点,然后又变回去了,不管怎样,只要变了,出事就很正常了。

所以下次用 STL 还是不要这么想当然了吧~也给我提供了一个调试新思路。

end writing 2023.8.25 14:52

标签:int,操作过程,RE,地址,vector,read,root
From: https://www.cnblogs.com/NBest/p/17686961.html

相关文章

  • STL在遍历过程中操作地址的改变
    2023-08-2609:57:22startwriting2023.8.269:18又遇到奇怪错误了,其实在打模拟赛(wzOI2023.8.24T1)的时候就发现有这个问题了,赛后来研究一下。以下代码://check是一个返回值为bool类型的判断函数,S是一个unordered_set<int>for(inti=1;i<=n;i++){intx=i,maxx=0,ans......
  • 使用GO 程序指定IP地址访问 http/https 地址 类似curl --resolve XXXIP:PortYYY
    需求,使用GO程序指定IP地址访问http/https地址传入参数:ipAddr//ipv4地址string值serviceUrl//url地址string值hostContainPort//HostHeader是否带url的端口bool值返回值:responseCode//http状态码int类型,Host//request请求HostHeaderstring类型 ......
  • Keil定位常量、变量到指定地址
    一、常量-ROM区域constcharVersion[]__attribute__((at(0x8001000)))={  'M','V','1','0','0'}; 二、变量-RAM区域intval__attribute__((section(".ARM.__at_0x20000004")))=0x00; 三、函数-ROM区域#pra......
  • 前端请求地址含特殊字符"+"后端接收数据显示空格
    问题描述:前端测试Get请求访问,path中的参数含有加号,后端过滤器中使用request.getParameter()方法无法获取。请求地址:http://localhost:8899/bookmark/getByUser?encryData=g3DGtZnczC7SUm+vRvkaYg==后端过滤器中接收参数如图所示,其中查询字符串是request.getQuerySt......
  • 数组与地址,数组名到底是什么?
    (数组与地址,数组名到底是什么?1.问题引出案例:设计一个函数,可以将整形数组的次序调换例如:arr[5]={1,2,3,4,5},输出形式为:arr[5]={5,4,3,2,1}.案例代码://能否可以正常排序?#include<stdio.h>voidreverse(int*arr){ intlen=sizeof(arr)/sizeof(arr[0]); inttop......
  • .NET Core 在其上下文中,该请求的地址无效。
    .NETCore在其上下文中,该请求的地址无效。看了端口,发现没被占用,后来发现是IP地址变了改成正确的IP就可以了。......
  • 独享IP地址的意义和作用
    在当今数字化时代,独享IP地址正在成为越来越多企业和个人关注的话题。它是一种网络技术解决方案,为用户提供独立、专属的IP地址,与其他用户隔离开来。本文将探讨独享IP地址的意义和作用,以及它为用户带来的重要价值。首先,我们来理解独享IP的概念。传统上,许多用户在互联网上使用共享IP地......
  • Modbus协议详解2:通信方式、地址规则、主从机通信状态
    首先我们要清楚:Modbus是一种串行链路上的主从协议,在通信线路上只能有一个主机存在,不会有多主机存在的情况。虽然主机只有一个,但是从机是可以有多个的。Modbus的通信过程都是由主机发起的,从机在接收到主机的请求后再进行响应,从机不会主动进行数据的发送。并且从机之间也不会互相发送......
  • npm,nrm管理源仓库地址
    npm修改源地址,使用nrm管理源仓库地址npm源地址查看与修改#查看当前源地址npmgetregistry#设为淘宝镜像npmsetregistryhttps://registry.npm.taobao.org/使用nrm便捷管理源#全局安装npminrm-g#查看版本,注意是大写Vnrm-V#查看nrm预设配置源地址nrmls......
  • VMware vSphere 8.0 Update 2 下载地址(ESXi 8.0 U2 & vCenter Server 8.0 U2)
    ESXi8.0U2&vCenterServer8.0U2请访问原文链接:https://sysin.org/blog/vmware-vsphere-8-u2/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.org企业级工作负载平台vSphere将云计算的优势引入本地部署工作负载。vSphere可提高性能和运维效率并加速创新。vSpher......