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
相关产品推荐
相关产品推荐

