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

C语言中调用free()触发Segmentation Fault段错误的问题求助

问题分析与修复

段错误的根源

你的代码在free(temp)处触发段错误,核心原因是**pop()函数未检查栈是否为空**:当栈为空(top == NULL)时,仍执行item = top->ch,这会直接访问空指针触发段错误(调试器显示free(temp)为错误位置,实际问题出在前面的空指针访问操作)。

同时代码还存在其他逻辑漏洞:

  • 若输入字符串中无c/C,第一个循环会越界访问数组,后续逻辑完全混乱
  • 若c/C后的字符数量多于前面的字符,会反复调用pop()直到栈为空,继续调用就会触发空指针访问
  • evaluate函数未处理flag != 1的情况,无返回值会导致未定义行为
  • gets()函数不安全,易造成缓冲区溢出

修复后的代码

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

struct stack
{
    char ch;
    struct stack *prev;
} *top = NULL;

typedef struct stack st;

char pop();
void push(char c);
int evaluate(char arr[100]);

int main()
{
    char arr[100];
    printf("Enter the string to check format of string in wcwR: ");
    // 用fgets替代不安全的gets,同时处理换行符
    fgets(arr, sizeof(arr), stdin);
    arr[strcspn(arr, "\n")] = '\0';
    
    if (evaluate(arr) == 1)
    {
        printf("Entered string is in correct format\n");
    }
    else
    {
        printf("Entered string is in wrong format\n");
    }
    return 0;
}

int evaluate(char arr[100])
{
    int i;
    // 先检查字符串中是否存在c/C
    int has_c = 0;
    for (i = 0; arr[i] != '\0'; i++) {
        if (arr[i] == 'c' || arr[i] == 'C') {
            has_c = 1;
            break;
        }
    }
    if (!has_c) {
        return 0; // 无分隔符c/C,直接返回错误
    }
    
    // 重新遍历到c/C,压栈前面的字符
    for (i = 0; arr[i] != 'c' && arr[i] != 'C'; i++)
    {
        push(arr[i]);
    }
    i++;
    int j = i;
    while (arr[j] != '\0')
    {
        // 调用pop前检查栈是否为空,若为空说明后面字符过多
        char popped = pop();
        if (popped == '\0' || arr[j] != popped)
        {
            return 0;
        }
        j++;
    }
    // 最后检查栈是否为空,若不为空说明前面字符过多
    return top == NULL ? 1 : 0;
}

void push(char c)
{
    st *p = (st *)malloc(sizeof(st));
    if (!p) { // 检查malloc是否成功
        perror("malloc failed");
        exit(EXIT_FAILURE);
    }
    p->ch = c;
    p->prev = top;
    top = p;
}

char pop()
{
    if (top == NULL) {
        return '\0'; // 栈为空时返回特殊标记
    }
    st *temp = top;
    char item = temp->ch;
    top = top->prev;
    free(temp);
    return item;
}

自主排查段错误的技巧

  • 检查空指针访问:段错误最常见原因是访问空指针,所有涉及指针的操作(如ptr->member)前,必须先判断ptr != NULL
  • 启用编译器警告:用gcc -Wall -Wextra编译代码,编译器会提示很多潜在问题(比如未初始化变量、无返回值的函数)
  • 使用调试工具:
    • 用gdb调试:编译时加-g参数,运行gdb ./your_program,输入run触发错误,再用backtrace查看调用栈,定位出错的具体位置
  • 边界条件测试:
    • 测试极端输入:比如空字符串、无c/C的字符串、c/C前/后字符数量不匹配的字符串
  • 检查内存操作:
    • 确保malloc成功后再使用指针,避免内存分配失败导致的空指针
    • 避免重复释放内存,虽然free(NULL)是安全的,但空指针访问是危险的
  • 检查数组越界:循环操作数组时,确保索引不超过数组长度,避免越界访问未知内存

内容的提问来源于stack exchange,提问作者Nishu Patel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 11:27:06