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

如何在C语言中正确定义并使用返回自定义结构体的函数?

帮你搞定卷积函数里的矩阵输出实现

我太懂这种感觉了——搜了一堆基础教程,全是讲怎么定义个矩阵、简单遍历打印,完全碰不到卷积场景下的具体内存分配和元素计算细节对吧?咱们一步步把这个convolve函数的核心逻辑补全。

首先先明确核心前提:假设你要实现的是valid卷积(不补零,只计算filter和输入矩阵完全重叠的区域),那输出矩阵的尺寸公式是:

  • 输出高度 = 输入高度 - 滤波器高度 + 1
  • 输出宽度 = 输入宽度 - 滤波器宽度 + 1

如果之后需要支持same卷积(补零让输出和输入尺寸一致),咱们后面再提,先从最常用的valid场景入手。

第一步:给输出矩阵分配内存

首先得给out矩阵的行指针和每行的内存空间分配好,还要加内存分配失败的防护(避免内存泄漏):

// 先做输入合法性检查:滤波器不能比输入矩阵大,否则输出尺寸为负
if (filter.height > data.height || filter.width > data.width) {
    out.height = 0;
    out.width = 0;
    out.map = NULL;
    return out;
}

// 计算输出矩阵的尺寸
out.height = data.height - filter.height + 1;
out.width = data.width - filter.width + 1;

// 先分配行指针数组
out.map = malloc(out.height * sizeof(double*));
if (out.map == NULL) {
    // 分配失败就返回空矩阵
    out.height = 0;
    out.width = 0;
    return out;
}

// 给每一行分配内存,同时做失败回滚
for (int i = 0; i < out.height; i++) {
    out.map[i] = malloc(out.width * sizeof(double));
    if (out.map[i] == NULL) {
        // 某一行分配失败,要把已经分配的内存全部释放
        for (int j = 0; j < i; j++) {
            free(out.map[j]);
        }
        free(out.map);
        out.height = 0;
        out.width = 0;
        out.map = NULL;
        return out;
    }
}

第二步:计算卷积的每个元素值

卷积的本质就是滑动窗口内的元素对应相乘再求和,用四层循环就能搞定:

// 遍历输出矩阵的每个行
for (int i = 0; i < out.height; i++) {
    // 遍历输出矩阵的每个列
    for (int j = 0; j < out.width; j++) {
        double sum = 0.0;
        // 遍历滤波器的行
        for (int fi = 0; fi < filter.height; fi++) {
            // 遍历滤波器的列
            for (int fj = 0; fj < filter.width; fj++) {
                // 对应位置相乘累加:输入矩阵的(i+fi,j+fj) 乘 滤波器的(fi,fj)
                sum += data.map[i + fi][j + fj] * filter.map[fi][fj];
            }
        }
        out.map[i][j] = sum;
    }
}

完整的convolve函数

把上面的逻辑整合到你的代码里,最终版本是这样:

Matrix convolve(Matrix data, Matrix filter) //this is line 28 btw
{
    Matrix out;
    // 输入合法性校验
    if (filter.height > data.height || filter.width > data.width) {
        out.height = 0;
        out.width = 0;
        out.map = NULL;
        return out;
    }

    // 计算输出尺寸
    out.height = data.height - filter.height + 1;
    out.width = data.width - filter.width + 1;

    // 分配输出矩阵内存
    out.map = malloc(out.height * sizeof(double*));
    if (out.map == NULL) {
        out.height = 0;
        out.width = 0;
        return out;
    }

    for (int i = 0; i < out.height; i++) {
        out.map[i] = malloc(out.width * sizeof(double));
        if (out.map[i] == NULL) {
            // 内存分配失败的回滚逻辑
            for (int j = 0; j < i; j++) {
                free(out.map[j]);
            }
            free(out.map);
            out.height = 0;
            out.width = 0;
            out.map = NULL;
            return out;
        }
    }

    // 计算卷积结果
    for (int i = 0; i < out.height; i++) {
        for (int j = 0; j < out.width; j++) {
            double sum = 0.0;
            for (int fi = 0; fi < filter.height; fi++) {
                for (int fj = 0; fj < filter.width; fj++) {
                    sum += data.map[i + fi][j + fj] * filter.map[fi][fj];
                }
            }
            out.map[i][j] = sum;
        }
    }

    return out;
}

额外的重要提示

  • 内存泄漏防护:用完out矩阵后,一定要写一个释放函数来清理内存:
    void freeMatrix(Matrix mat) {
        if (mat.map != NULL) {
            for (int i = 0; i < mat.height; i++) {
                free(mat.map[i]);
            }
            free(mat.map);
        }
    }
    
  • same卷积支持:如果需要输出尺寸和输入一致,要先给输入矩阵补零,补零的行数是filter.height/2,列数是filter.width/2,之后再用上面的逻辑计算即可。

内容的提问来源于stack exchange,提问作者Sam Haese

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:54:47