You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言中基于Bitmap动态选择结构体成员写入缓冲区时的内存优化与栈溢出解决方案

嘿,我来帮你搞定这个问题!首先你遇到的栈溢出,核心问题不是用指针声明缓冲区本身,而是代码里所有memcpy调用都错误地在长度参数上加了+1,导致写入超出了内存边界,触发了系统的栈保护机制。另外,直接写char *buffer;却不给它分配内存的话,指针指向的是未定义的垃圾地址,往里面写数据必然会导致内存错误。

下面是既不浪费内存又能安全运行的解决方案,我会一步步解释并给出修正后的完整代码:

第一步:提前算出实际需要的缓冲区大小

我们不需要一开始就分配结构体总大小的内存,而是根据bitmap的位状态,精确计算要写入的所有成员的总字节数(包括bitmap本身):

// 先算出各个位的状态
uint8_t temp4 = isKthBitSet(abitmap.bitmap,4);
uint8_t temp3 = isKthBitSet(abitmap.bitmap,3);
uint8_t temp2 = isKthBitSet(abitmap.bitmap,2);
uint8_t temp1 = isKthBitSet(abitmap.bitmap,1);

// 计算总缓冲区大小:从bitmap的大小开始,加上选中成员的大小
size_t buffer_size = sizeof(abitmap.bitmap);
if (temp4) buffer_size += sizeof(abitmap.a);
if (temp3) buffer_size += sizeof(abitmap.b);
if (temp2) buffer_size += sizeof(abitmap.str);
if (temp1) buffer_size += sizeof(abitmap.d);

第二步:动态分配内存

用malloc根据计算出的大小分配内存,一定要检查分配是否成功——万一内存不足,malloc会返回NULL,直接用的话会崩溃:

char *buffer = malloc(buffer_size);
if (!buffer) {
    perror("malloc failed");
    return 1; // 分配失败就直接退出
}

第三步:修复memcpy的长度错误

你之前写的sizeof(xxx)+1是致命错误!比如abitmap.a是uint32_t,大小是4字节,加1就会复制5字节,直接越界写内存,这才是栈溢出的元凶。正确的做法是直接用成员的实际大小sizeof(xxx),不多不少。

第四步:用完记得释放内存

动态分配的内存不会自动回收,用free(buffer)释放,之后最好把指针设为NULL,避免变成悬空指针。

完整修正后的代码

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#define RAND(lower,upper) (rand()%(upper-lower+1))+lower

int power(int base, int exp) {
    int result=1;
    while (exp != 0) {
        result *= base;
        --exp;
    }
    return result;
}

int isKthBitSet(int n, int k)//from right, 1<=k<=n
{
    int new_num = n >> (k - 1);
    return (new_num & 1);
}

struct Astructure{
    uint16_t bitmap;
    uint32_t a;
    uint32_t b;
    char str[10];
    uint16_t d;
}__attribute__((packed));

int main() {
    struct Astructure abitmap;
    abitmap.bitmap = 0;
    abitmap.a = 52;
    abitmap.b = 16;
    char c[10]={"ramya"};
    strcpy(abitmap.str, c);
    abitmap.d = 59;
    
    srand(time(0));
    for(uint8_t position =1;position<5;position++)
    {
        int random10 = RAND(0,1);
        if(random10==1)
        {
            int value = power(2,position-1);
            abitmap.bitmap = abitmap.bitmap | value;
        }
    }
    
    // 先确定各个位的状态,计算缓冲区大小
    uint8_t temp4 = isKthBitSet(abitmap.bitmap,4);
    uint8_t temp3 = isKthBitSet(abitmap.bitmap,3);
    uint8_t temp2 = isKthBitSet(abitmap.bitmap,2);
    uint8_t temp1 = isKthBitSet(abitmap.bitmap,1);
    
    size_t buffer_size = sizeof(abitmap.bitmap);
    if (temp4) buffer_size += sizeof(abitmap.a);
    if (temp3) buffer_size += sizeof(abitmap.b);
    if (temp2) buffer_size += sizeof(abitmap.str);
    if (temp1) buffer_size += sizeof(abitmap.d);
    
    // 动态分配缓冲区
    char *buffer = malloc(buffer_size);
    if (!buffer) {
        perror("malloc failed");
        return 1;
    }
    
    // 复制数据到缓冲区
    size_t previousLength = 0;
    // 先复制bitmap
    memcpy(buffer + previousLength, &abitmap.bitmap, sizeof(abitmap.bitmap));
    previousLength += sizeof(abitmap.bitmap);
    
    if(temp4){
        memcpy(buffer + previousLength, &abitmap.a, sizeof(abitmap.a));
        previousLength += sizeof(abitmap.a);
    }
    if(temp3){
        memcpy(buffer + previousLength, &abitmap.b, sizeof(abitmap.b));
        previousLength += sizeof(abitmap.b);
    }
    if(temp2){
        memcpy(buffer + previousLength, abitmap.str, sizeof(abitmap.str));
        previousLength += sizeof(abitmap.str);
    }
    if(temp1){
        memcpy(buffer + previousLength, &abitmap.d, sizeof(abitmap.d));
        previousLength += sizeof(abitmap.d);
    }
    
    // 解析缓冲区数据
    previousLength = sizeof(abitmap.bitmap); // 跳过bitmap,我们已经知道状态了
    uint32_t a;
    uint32_t b;
    char str[10];
    uint16_t d;
    
    if(temp4){
        memcpy(&a, buffer + previousLength, sizeof(abitmap.a));
        printf("a = %d\t",a);
        previousLength += sizeof(a);
    }
    if(temp3){
        memcpy(&b, buffer + previousLength, sizeof(abitmap.b));
        printf("b = %d\t",b);
        previousLength += sizeof(b);
    }
    if(temp2){
        memcpy(str, buffer + previousLength, sizeof(abitmap.str));
        printf("string = %s\t",str);
        previousLength += sizeof(str);
    }
    if(temp1){
        memcpy(&d, buffer + previousLength, sizeof(abitmap.d));
        printf("d = %d\t",d);
        previousLength += sizeof(d);
    }
    printf("\n");
    
    // 释放内存,避免泄漏
    free(buffer);
    buffer = NULL;
    
    return 0;
}

额外说明

  • 我调整了previousLength的初始逻辑,复制数据时从0开始,更清晰;解析时直接跳过bitmap,因为我们已经提前知道各个位的状态了,没必要再从缓冲区读一遍。
  • 动态分配的内存是在堆上,不会像栈内存那样有大小限制,也不会浪费空间——用多少分配多少。
  • 一定要检查malloc的返回值,这是写C代码的良好习惯,避免内存不足导致的崩溃。

内容的提问来源于stack exchange,提问作者rayapati ramya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 21:12:35