CLion中C程序Debug模式正常,正常执行返回错误码0xC0000005求助
问题描述
我在用C语言完成Advent of Code 2022年第3题的挑战,代码在CLion的Debug模式下运行完全正常,但切换到正常执行(Release模式)时返回错误码-1073741819(0xC0000005)。查阅资料得知该错误码可能与栈溢出相关,但无法自行定位问题点,同时怀疑是否存在内存未释放的情况。
主程序代码
// // Created by gusta on 2022-12-06. // #include "aocio.h" #include <string.h> int cexists(char* cp, char c, int length); char getDuplicate(char* line); int main() { FILE* fptr = openFile("../Inputs/day3.txt"); char* line; while (readLine(fptr, &line)) { char c = getDuplicate(line); putchar(c); } return 0; } char getDuplicate(char* line) { // Returnerar STRING_END om ingen fanns unsigned int length = strlen(line); char letters[length/2]; char* cp = &letters[0]; for (int i = 0; i < length/2; i++) { letters[i] = ' '; } for (int index = 0; line[index] != STRING_END; index++) { if (index < length/2) { int i_char = cexists(letters, line[index], length/2); if (i_char == -1) { *cp = line[index]; cp++; } } else { if (cexists(letters, line[index], length/2) != -1) { return line[index]; } } } } int cexists(char* cp, char c, int length) { for (int i = 0; i < length; i++) { if (cp[i] == c) { return i; } } return -1; }
aocio.h 工具头文件代码
// // Created by gusta on 2022-12-01. // #ifndef ADVENTOFCODE_AOCIO_H #define ADVENTOFCODE_AOCIO_H #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #define SIGN_ASCII 45 #define TRUE 1 #define FALSE 0 #endif //ADVENTOFCODE_AOCIO_H #define STRING_END '\0' #define NUMBERS_ASCII 48 char* prompt(const char* question) { printf(question); char* string = malloc(1); int curChar = 0, index = 0; while (curChar != '\n') { curChar = getchar(); if (curChar == '\n'){ string[index] = STRING_END; } else{ if (index > 0) { string = (char*) realloc(string, index+1); } string[index] = curChar; } index++; } return string; } FILE* openFile(const char* fileName) { FILE *fptr; fptr = fopen(fileName, "r"); if (fptr == NULL) { printf("Big fat file error!!\n"); fclose(fptr); getchar(); exit(-1); } return fptr; } char readLine(FILE* fptr, char** line) { int index = 0, end = 0; char* string = (char *) malloc(1); char curChar; do { end = fscanf(fptr, "%c", &curChar); if (end == EOF) { string[index] = STRING_END; fclose(fptr); *line = string; return FALSE; } if (curChar == '\n') { string[index] = STRING_END; *line = string; return TRUE; } else { if (index > 0) { string = (char *) realloc(string, index + 1); } string[index] = curChar; index++; } } while (end != EOF); } int parseToInt(char* string) { int numberLength = 0, number = 0; int sign = FALSE; for (int index = 0; string[index] != STRING_END; index++) { numberLength++; } for (int index = numberLength-1; index >= 0; index--) { char curChar = string[index]; if (index == 0 && curChar - SIGN_ASCII == 0) { sign = TRUE; continue; } if (curChar - NUMBERS_ASCII >= 0 && curChar - NUMBERS_ASCII <= 9) { int num = (int) (curChar - NUMBERS_ASCII); num *= (int)(pow(10, numberLength-index-1)); number += num; } else { printf("Felaktig inmatning. parseInt kan bara ta in tal"); // Invalid input. parseInt can only take in numbers getchar(); exit(-1); } } if (sign == TRUE) { number *= -1; } return number; }
问题根源及修复方案
1. 栈溢出:变长数组(VLA)的危险用法
getDuplicate函数中使用了char letters[length/2];这种变长数组,栈的默认空间通常只有几MB,一旦输入的行长度较大,这个数组会直接耗尽栈空间导致崩溃。Debug模式下IDE可能会给栈分配更大的空间或者添加保护机制,所以不会触发问题,但Release模式下会直接报错。
修复方案:改用堆内存分配,用完后释放:
char getDuplicate(char* line) { unsigned int length = strlen(line); // 用malloc分配堆内存 char* letters = malloc(length/2); if (letters == NULL) { // 处理内存分配失败的情况 return STRING_END; } char* cp = letters; for (int i = 0; i < length/2; i++) { letters[i] = ' '; } // ... 原有逻辑不变 ... // 函数结束前释放内存 free(letters); // 必须添加默认返回值 return STRING_END; }
2. 函数缺少默认返回值
getDuplicate函数声明返回char,但如果遍历完整个字符串都没找到重复字符,函数没有任何返回语句,这会导致未定义行为。Debug模式下编译器可能会自动填充一个默认值,但Release模式下会引发不可预测的结果,甚至崩溃。
修复方案:在函数末尾添加明确的默认返回值,比如return STRING_END;。
3. 内存泄漏
readLine函数每次都会通过malloc分配新的字符串,但主程序中从未调用free(line)释放内存。虽然这不是当前崩溃的直接原因,但长期运行会耗尽堆内存,必须修复。
修复方案:在循环内读完每一行后释放内存:
while (readLine(fptr, &line)) { char c = getDuplicate(line); putchar(c); free(line); // 释放当前行的内存 }
4. openFile函数的错误处理bug
当fopen失败时,fptr为NULL,此时调用fclose(fptr)会触发崩溃,因为不能关闭空指针。
修复方案:删除错误分支中的fclose(fptr)语句:
FILE* openFile(const char* fileName) { FILE *fptr; fptr = fopen(fileName, "r"); if (fptr == NULL) { printf("Big fat file error!!\n"); // 删除这行:fclose(fptr); getchar(); exit(-1); } return fptr; }
5. readLine的realloc逻辑优化
当前readLine中,当index=0时,第一次分配1字节是没问题的,但后续的realloc逻辑可以更稳妥,确保每次分配的空间足够容纳当前字符和终止符。建议修改为每次分配index+2的空间(留一个位置给STRING_END):
else { // 不管index是否为0,都重新分配足够的空间 string = (char *) realloc(string, index + 2); string[index] = curChar; index++; }
内容的提问来源于stack exchange,提问作者BeefJoerky

