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

C语言实现ANN出现Run-Time Check Failure #2错误求助

C语言人工神经网络(ANN)栈损坏问题修复

问题描述

用C语言实现了包含神经元模型及输入层、隐藏层、输出层的人工神经网络,代码由Python版本转换而来。调试后预测输出结果正确,但程序结束时触发错误:

Run-Time Check Failure #2 - Stack around the variable 'outputLayer' was corrupted.
(中文翻译:运行时检查失败#2 - 变量'outputLayer'周围的栈已损坏)

相关代码

#include<stdio.h>
#include<math.h>
#define INPUT_SIZE 3 
#define HIDDEN_SIZE 8
#define OUTPUT_SIZE 1
#define LEARNING_RATE 0.09
#define EPOCHS 20000

struct Neuron {
    double weights[INPUT_SIZE];
    double bias;
};

double relu(double x) {
    return fmax(0, x);
}

double sigmoid(double x) {
    return 1.0 / (1.0 + exp(-x));
}

double sigmoid_derivative(double x) {
    return x * (1 - x);
}

double calculateNeuronOutput(struct Neuron *neuron, double inputs[], int use_relu, int input_count) {
    double sum = neuron->bias;
    for (int i = 0; i < input_count; i++) {
        sum += inputs[i] * neuron->weights[i];
    }
    
    if (use_relu){
        return relu(sum);
    }
    else {
        return sigmoid(sum);
    }
}

void backPropagation(struct Neuron inputLayer[], struct Neuron hiddenLayer[], 
                          struct Neuron outputLayer[], double inputVector[], double target) {
    double hiddenLayerOutput[HIDDEN_SIZE];
    for (int i = 0; i < HIDDEN_SIZE; i++) {
        hiddenLayerOutput[i] = calculateNeuronOutput(&hiddenLayer[i], inputVector, 1, INPUT_SIZE);
    }

    double output = calculateNeuronOutput(&outputLayer[0], hiddenLayerOutput, 0, HIDDEN_SIZE);

    double error = 0.5 * pow(target - output, 2);

    double output_error = target - output;
    double output_delta = output_error * sigmoid_derivative(output);

    double hiddenLayer_error[HIDDEN_SIZE];
    for (int i = 0; i < HIDDEN_SIZE; i++) {
        hiddenLayer_error[i] = output_delta * outputLayer[0].weights[i];
    }

    for (int i = 0; i < HIDDEN_SIZE; i++) {
        for (int j = 0; j < INPUT_SIZE; j++) {
            hiddenLayer[i].weights[j] += LEARNING_RATE * hiddenLayer_error[i] * inputVector[j];
        }
        hiddenLayer[i].bias += LEARNING_RATE * hiddenLayer_error[i];
    }

    for (int i = 0; i < OUTPUT_SIZE; i++) {
        for (int j = 0; j < HIDDEN_SIZE; j++) {
            outputLayer[i].weights[j] += LEARNING_RATE * output_delta * hiddenLayerOutput[j];
        }
        outputLayer[i].bias += LEARNING_RATE * output_delta;
    }
}

int main() {
    struct Neuron inputLayer[INPUT_SIZE] = {
        {{0.1, -0.2, 0.3}, 0.1},
        {{0.2, -0.1, -0.3}, 0.2},
        {{0.3, 0.4, -0.1}, 0.2},
    };

    struct Neuron hiddenLayer[HIDDEN_SIZE] = {
        {{0.1, 0.2, 0.3}, 0.1},
        {{0.2, 0.1, -0.3}, 0.2},
        {{0.3, 0.4, 0.1}, 0.3},
        {{0.2, 0.1, 0.4}, -0.4},
        {{0.5, 0.2, -0.3}, -0.1},
        {{0.1, 0.3, 0.2}, 0.4},
        {{0.3, -0.4, 0.1}, 0.2},
        {{0.4, 0.2, -0.1}, -0.3}
    };

    struct Neuron outputLayer[OUTPUT_SIZE] = {
        {{0.1, -0.2, 0.3}, 0.2}
    };
    
    double inputVector[4][INPUT_SIZE] = { { 0.0, 0.0, 1.0 },{0.0, 1.0, 0.0},{0.0, 1.0, 1.0},{1.0, 1.0, 1.0 } };
    double targetOutput[4] = {0.0, 1.0, 1.0, 0.0};

    for (int epoch = 0; epoch < EPOCHS; epoch++) {
        for(int i=0; i< 4; i++){
            backPropagation(inputLayer, hiddenLayer, outputLayer, inputVector[i], targetOutput[i]);
        }

        if (epoch % 1000 == 0) {
            double totalError = 0.0;
            for (int i = 0; i < 4; i++) {
                double hiddenLayerOutput[HIDDEN_SIZE];
                for (int j = 0; j < HIDDEN_SIZE; j++) {
                    hiddenLayerOutput[j] = calculateNeuronOutput(&hiddenLayer[j], inputVector[i], 1, INPUT_SIZE);
                }
                double output = calculateNeuronOutput(&outputLayer[0], hiddenLayerOutput, 0, HIDDEN_SIZE);
                double error = 0.5 * pow(targetOutput[i] - output, 2);
                totalError += error;
            }
            printf("Epoch: %d, Loss: %f\n", epoch, totalError);
        }
    }
    
    double predictionInput[4][INPUT_SIZE] = { { 0.0, 0.0, 1.0 },{0.0, 0.0, 1.0},{0.0, 1.0, 1.0},{0.0, 1.0, 1.0 } };
    
    for (int i = 0; i < 4; ++i) {
        double hiddenLayerOutput[HIDDEN_SIZE];
        for (int j = 0; j < HIDDEN_SIZE; ++j) {
            hiddenLayerOutput[j] = calculateNeuronOutput(&hiddenLayer[j], predictionInput[i], 1, INPUT_SIZE);
        }
        double finalOutput = calculateNeuronOutput(&outputLayer[0],hiddenLayerOutput, 0, HIDDEN_SIZE);
        printf("Input: (%f, %f, %f), Exact Output: %f, Prediction: %f\n",
            predictionInput[i][0], predictionInput[i][1], predictionInput[i][2], targetOutput[i], finalOutput);
    }

    return 0;
}

运行输出

Epoch: 0, Loss: 0.526654
Epoch: 1000, Loss: 0.003173
Epoch: 2000, Loss: 0.001147
Epoch: 3000, Loss: 0.000665
Epoch: 4000, Loss: 0.000458
Epoch: 5000, Loss: 0.000346
Epoch: 6000, Loss: 0.000275
Epoch: 7000, Loss: 0.000228
Epoch: 8000, Loss: 0.000194
Epoch: 9000, Loss: 0.000168
Epoch: 10000, Loss: 0.000148
Epoch: 11000, Loss: 0.000132
Epoch: 12000, Loss: 0.000119
Epoch: 13000, Loss: 0.000108
Epoch: 14000, Loss: 0.000099
Epoch: 15000, Loss: 0.000091
Epoch: 16000, Loss: 0.000085
Epoch: 17000, Loss: 0.000079
Epoch: 18000, Loss: 0.000074
Epoch: 19000, Loss: 0.000069
Input: (0.000000, 0.000000, 1.000000), Exact Output: 0.000000, Prediction: 0.006382
Input: (0.000000, 1.000000, 0.000000), Exact Output: 1.000000, Prediction: 0.999901
Input: (0.000000, 1.000000, 1.000000), Exact Output: 1.000000, Prediction: 0.992201
Input: (1.000000, 1.000000, 1.000000), Exact Output: 0.000000, Prediction: 0.005400

问题根源

核心问题是数组越界访问:

  • struct Neuron中定义的weights数组大小固定为INPUT_SIZE(3),但输出层神经元需要接收来自隐藏层的HIDDEN_SIZE(8)个输入,因此需要8个权重。
  • 在反向传播的backPropagation函数中,循环更新输出层权重时:
    for (int j = 0; j < HIDDEN_SIZE; j++) {
        outputLayer[i].weights[j] += LEARNING_RATE * output_delta * hiddenLayerOutput[j];
    }
    
    这里j从0到7,访问outputLayer[i].weights[j]时,超出了该数组仅有的3个元素范围,直接破坏了栈内存,导致程序结束时触发栈损坏检查错误。

修复方案

由于C语言结构体无法直接定义动态大小的数组,有两种可行修复方式:

方式1:为不同层定义专用结构体

针对输入层、隐藏层、输出层分别定义结构体,各自的weights数组匹配对应层的输入数量:

// 输入层神经元:接收INPUT_SIZE个输入
struct InputNeuron {
    double weights[INPUT_SIZE];
    double bias;
};

// 隐藏层神经元:接收INPUT_SIZE个输入
struct HiddenNeuron {
    double weights[INPUT_SIZE];
    double bias;
};

// 输出层神经元:接收HIDDEN_SIZE个输入
struct OutputNeuron {
    double weights[HIDDEN_SIZE];
    double bias;
};

这种方式简单直接,但灵活性较差,适合固定结构的网络。

方式2:使用动态内存分配(推荐)

修改Neuron结构体,将weights改为指针,在初始化时根据层的需求分配内存,使用完毕后释放:

#include<stdio.h>
#include<math.h>
#include<stdlib.h>

#define INPUT_SIZE 3 
#define HIDDEN_SIZE 8
#define OUTPUT_SIZE 1
#define LEARNING_RATE 0.09
#define EPOCHS 20000

struct Neuron {
    double *weights;
    int weight_count;
    double bias;
};

struct Neuron create_neuron(int weight_count, double *init_weights, double bias) {
    struct Neuron n;
    n.weight_count = weight_count;
    n.weights = (double*)malloc(sizeof(double) * weight_count);
    if (n.weights == NULL) {
        fprintf(stderr, "内存分配失败\n");
        exit(1);
    }
    for (int i = 0; i < weight_count; i++) {
        n.weights[i] = init_weights[i];
    }
    n.bias = bias;
    return n;
}

void free_neuron(struct Neuron *n) {
    free(n->weights);
    n.weights = NULL;
}

double relu(double x) {
    return fmax(0, x);
}

double sigmoid(double x) {
    return 1.0 / (1.0 + exp(-x));
}

double sigmoid_derivative(double x) {
    return x * (1 - x);
}

double calculateNeuronOutput(struct Neuron *neuron, double inputs[]) {
    double sum = neuron->bias;
    for (int i = 0; i < neuron->weight_count; i++) {
        sum += inputs[i] * neuron->weights[i];
    }
    if (neuron->weight_count == INPUT_SIZE) {
        return relu(sum);
    } else {
        return sigmoid(sum);
    }
}

void backPropagation(struct Neuron hiddenLayer[], struct Neuron outputLayer[], 
                     double inputVector[], double target) {
    double hiddenLayerOutput[HIDDEN_SIZE];
    for (int i = 0; i < HIDDEN_SIZE; i++) {
        hiddenLayerOutput[i] = calculateNeuronOutput(&hiddenLayer[i], inputVector);
    }

    double output = calculateNeuronOutput(&outputLayer[0], hiddenLayerOutput);

    double output_error = target - output;
    double output_delta = output_error * sigmoid_derivative(output);

    double hiddenLayer_error[HIDDEN_SIZE];
    for (int i = 0; i < HIDDEN_SIZE; i++) {
        hiddenLayer_error[i] = output_delta * outputLayer[0].weights[i];
    }

    for (int i = 0; i < HIDDEN_SIZE; i++) {
        for (int j = 0; j < hiddenLayer[i].weight_count; j++) {
            hiddenLayer[i].weights[j] += LEARNING_RATE * hiddenLayer_error[i] * inputVector[j];
        }
        hiddenLayer[i].bias += LEARNING_RATE * hiddenLayer_error[i];
    }

    for (int i = 0; i < OUTPUT_SIZE; i++) {
        for (int j = 0; j < outputLayer[i].weight_count; j++) {
            outputLayer[i].weights[j] += LEARNING_RATE * output_delta * hiddenLayerOutput[j];
        }
        outputLayer[i].bias += LEARNING_RATE * output_delta;
    }
}

int main() {
    double input_weights1[] = {0.1, -0.2, 0.3};
    double input_weights2[] = {0.2, -0.1, -0.3};
    double input_weights3[] = {0.3, 0.4, -0.1};
    struct Neuron inputLayer[INPUT_SIZE] = {
        create_neuron(INPUT_SIZE, input_weights1, 0.1),
        create_neuron(INPUT_SIZE, input_weights2, 0.2),
        create_neuron(INPUT_SIZE, input_weights3, 0.2)
    };

    double hidden_weights1[] = {0.1, 0.2, 0.3};
    double hidden_weights2[] = {0.2, 0.1, -0.3};
    double hidden_weights3[] = {0.3, 0.4, 0.1};
    double hidden_weights4[] = {0.2, 0.1, 0.4};
    double hidden_weights5[] = {0.5, 0.2, -0.3};
    double hidden_weights6[] = {0.1, 0.3, 0.2};
    double hidden_weights7[] = {0.3, -0.4, 0.1};
    double hidden_weights8[] = {0.4, 0.2, -0.1};
    struct Neuron hiddenLayer[HIDDEN_SIZE] = {
        create_neuron(INPUT_SIZE, hidden_weights1, 0.1),
        create_neuron(INPUT_SIZE, hidden_weights2, 0.2),
        create_neuron(INPUT_SIZE, hidden_weights3, 0.3),
        create_neuron(INPUT_SIZE, hidden_weights4, -0.4),
        create_neuron(INPUT_SIZE, hidden_weights5, -0.1),
        create_neuron(INPUT_SIZE, hidden_weights6, 0.4),
        create_neuron(INPUT_SIZE, hidden_weights7, 0.2),
        create_neuron(INPUT_SIZE, hidden_weights8, -0.3)
    };

    double output_weights[] = {0.1, -0.2, 0.3, 0.0, 0.0, 0.0, 0.0, 0.0};
    struct Neuron outputLayer[OUTPUT
相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 23:56:44