访问指向结构的指针会导致内存读取冲突

如何解决访问指向结构的指针会导致内存读取冲突

由于大量的空闲时间,最近我在C语言中进行了大量编程。由于C(我认为)是一种很难掌握和学习的语言,所以我会犯错,并且内存泄漏左右,偶尔会陷入一个似乎无法解决的问题,就像我现在遇到的那样。

我的代码旨在成为一个简单的Bignum实现:有一点用于对数字进行签名,一个整数列表以及一个用于实际存在多少个整数的计数器。因为两百亿还不够!

无论如何,这是我的代码:

#include <stdlib.h>

const unsigned int INTSZ = (int)sizeof(int),CHRSZ = (int)sizeof(char);

typedef struct {
    unsigned int negative : 1;
    unsigned int count;
    unsigned int* list;
} VLENNUM_I;

typedef struct {
    unsigned int negative : 1;
    unsigned int count;
    unsigned char* list;
} VLENNUM_C;

int ceiling(double x) {
    return (((int)x) == x) ? (int)x : (int)x + 1;
}

VLENNUM_I* vlnc_to_vlni(VLENNUM_C* toconv) {
    VLENNUM_I result = { 0 };
    VLENNUM_C drtc = *toconv;

    result.negative = drtc.negative;
    result.count = ceiling(drtc.count / INTSZ);
    result.list = calloc(result.count,INTSZ);

    unsigned int i = 0,temp = 0,toprl = 0;
    for (; i < drtc.count; ++i) {
        temp |= drtc.list[i] << (3 - i % 4) * 8; // Right here

        if (i > 0 && !((i + 1) % 4)) {
            result.list[toprl] = temp;
            temp = 0;
            ++toprl;
        }
    }

    if (!(i % 4)) result.list[toprl + 1] = temp;

    return &result;
}

VLENNUM_C* vlni_to_vlnc(VLENNUM_I* toconv) {
    VLENNUM_C result = { 0 };
    VLENNUM_I drtc = *toconv;

    result.negative = drtc.negative;
    result.count = drtc.count * INTSZ;
    result.list = calloc(result.count,CHRSZ);

    unsigned int i = 0,c = 0,masks[4] = { 255,65280,16711680,4278190080 };

    for (; i < drtc.count; ++i)
        for (int j = 0; j < 4; ++j)
            result.list[(i * 4) + (3 - j)] = (char)((drtc.list[i] & masks[j]) >> (j * 8));

    return &result;
}

int main(void) {
    VLENNUM_I x = { 0 };

    x.count = 1;
    x.negative = 0;
    x.list = malloc(1 * INTSZ);

    x.list[0] = 172639;

    VLENNUM_C* y = vlni_to_vlnc(&x);

    VLENNUM_I* z = vlnc_to_vlni(y);

    return 1;
}

VLENNUM_IVLENNUM_C是“可变长度数字”,其中包含int s或char s的列表。 vlnc_to_vlniVLENNUM_C转换为VLENNUM_I,反之亦然vlni_to_vlnc。输入和输出位于指针中,以防传递较大的值,因此实际上返回的是整数,而不是表示结构的大量数据。在Visual Studio 2020中运行代码会导致内存读取错误,我在注释中指出了该错误;使用VS的调试器单步执行代码会产生一些有用的信息,尽管对我而言这些信息毫无意义:toconv充满了某种垃圾数据。例如,结构中包含的count变量将替换为随机数,而不是应有的随机数。有人可以帮我找出这意味着什么以及如何解决吗?

解决方法

vlnc_to_vlnivlni_to_vlnc都有致命缺陷:

VLENNUM_I* vlnc_to_vlni(VLENNUM_C* toconv) {
    VLENNUM_I result = { 0 };
    // ...
    return &result;
}

VLENNUM_C* vlni_to_vlnc(VLENNUM_I* toconv) {
    VLENNUM_C result = { 0 };
    // ...
    return &result;
}

您将返回局部变量的地址,这是结束内存错误的快速方法。操作系统使用调用堆栈跟踪程序的执行情况,该程序在程序启动时如下所示:

[  main: x,y,z ]

这部分调用栈(称为 stack frame )具有当前函数的地址(main)和该函数的局部变量。致电vlni_to_vlnc时:

[ main: x,z ][ vlni_to_vlnc: result,drtc,i,c,masks ]

该函数获取自己的堆栈框架,并为其自身的本地空间留出空间。返回&result时,您将返回以下地址:

[ main: x,masks ]
                                 ^^^^^^

但是函数结束时,堆栈框架消失了,这给您留下了这样的指针:

[ main: x,z ]                [????]
                                 ^^^^^^

调用vlnc_to_vlni时,其堆栈框架将移至vlni_to_vlnc所在的位置:

[ main: x,z ][ vlnc_to_vlni: result,masks ]
                                 ^^^^^^ whoops!

简而言之,您的VLENNUM_I *指向新分配的堆栈帧,然后将其写入-因此,您期望的数据将被更改。

在这种情况下,解决方案是执行以下操作之一:

  • 按值返回结构
  • 使用malloc动态分配它,然后在以后释放它
  • 将结果指针作为参数(例如vlnc_to_vlni(VLENNUM_C *toconv,VLENNUM_I *out))并将结果存储在其中
,

崩溃是因为代码通过返回其地址在两个函数中形成了指向本地堆栈变量的指针。这些结构要么需要在堆上分配,要么需要从其他范围引用。

#include <stdlib.h>
#include <assert.h>

const unsigned int INTSZ = (int)sizeof(int),CHRSZ = (int)sizeof(char);

typedef struct
{
    unsigned int  negative : 1;
    unsigned int  count;
    unsigned int* list;
} VLENNUM_I;

typedef struct
{
    unsigned int   negative : 1;
    unsigned int   count;
    unsigned char* list;
} VLENNUM_C;

int ceiling(double x)
{
    return (((int)x) == x) ? (int)x : (int)x + 1;
}

void vlnc_to_vlni(VLENNUM_C* toconv,VLENNUM_I* result)
{
    VLENNUM_C drtc   = *toconv;
    assert(result != NULL);

    result->negative = drtc.negative;
    result->count    = ceiling(drtc.count / INTSZ);
    result->list     = (unsigned int*)calloc(result->count,INTSZ);

    unsigned int i = 0,temp = 0,toprl = 0;
    for (; i < drtc.count; ++i)
    {
        temp |= drtc.list[i] << (3 - i % 4) * 8;  // Right here

        if (i > 0 && !((i + 1) % 4))
        {
            result->list[toprl] = temp;
            temp               = 0;
            ++toprl;
        }
    }

    if (!(i % 4))
        result->list[toprl + 1] = temp;
}

void vlni_to_vlnc(VLENNUM_I* toconv,VLENNUM_C *result)
{
    VLENNUM_I drtc   = *toconv;
    assert(result != NULL);

    result->negative = drtc.negative;
    result->count    = drtc.count * INTSZ;
    result->list     = (unsigned char*)calloc(result->count,CHRSZ);

    unsigned int i = 0,c = 0,masks[4] = {255,65280,16711680,4278190080};

    for (; i < drtc.count && result && result->list; ++i)
    {
        for (int j = 0; j < 4; ++j)
        {
            int k = (i * 4) + (3 - j);
            if (k < drtc.count)
                result->list[k] = (char)((drtc.list[i] & masks[j]) >> (j * 8));
        }
    }

}

int main(void)
{
    VLENNUM_I x = {0};

    x.count    = 1;
    x.negative = 0;
    x.list     = (unsigned int*)malloc(1 * INTSZ);

    x.list[0] = 172639;

    VLENNUM_C y = {0};
    vlni_to_vlnc(&x,&y);

    VLENNUM_I z = {0};
    vlnc_to_vlni(&y,&z);

    return 1;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-