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

C语言递归函数引发Segmentation Fault错误排查及循环检测需求

问题描述

我有一个存储胜者(winner)和败者(loser)的pair结构体数组,败者可能在其他pair中作为胜者,且一个败者可能对应多个以其为胜者的pair。我需要检测这类胜负链是否形成循环(loop):若不存在循环,将二维数组locked的对应pair位置设为true;若存在循环则设为false。但程序运行时出现Segmentation Fault(段错误),无法定位原因。

原代码片段
#include <stdio.h>
#include <stdbool.h>
#define MAX 5

int preferences[MAX][MAX] = {0};

bool locked[MAX][MAX];

bool visited[MAX][MAX];

typedef struct
{
    int winner;
    int loser;
} pair;

pair pairs[] ={{0,2}, {0,1}, {0,3}, {1,2}, {0,4}, {3,1}, {3,2}, {3,4}, {4,1}, {4,2}};
int pair_count = MAX*(MAX - 1)/2;

void clear_workspace(void);
bool check_for_loop(int start, int end);
bool branches(int loser, int arr[]);
void lock_pairs(void);

int main(void)
{
    for (int i = 0; i < MAX; i++)
    {
        for (int j = 0; j < MAX; j++)
        {
            locked[i][j] = false;
        }
    }
    lock_pairs();
}
void lock_pairs(void)
{
    for (int i = 0;i < pair_count;i++)
    {
        int start = pairs[i].winner;
        int end = pairs[i].loser;
        clear_workspace();
        if(check_for_loop(start, end) == false)
        {
            locked[start][end] = true;
        }
    }
}
bool check_for_loop(int start, int end)
{
    visited[start][end] = true;
    int arr[MAX * MAX] = {-1};
    if (branches(end,arr) == true)
    {
        for (int i = 0;i < MAX;i++)
        {
            if (arr[i] != -1 && visited[end][arr[i]] == true)
            {
                return true;
            }
            if (arr[i] != -1 && check_for_loop(start, arr[i]) == true)
            {
                return true;
            }
        }
    }
    return false;
}
bool branches(int loser, int arr[])
{
    int arr_index;
    arr_index = 0;
    int flag = 0;
    for (int i = 0;i < pair_count;i++)
    {
        if (pairs[i].winner == loser)
        {
            arr[arr_index] = pairs[i].winner;
            arr_index++;
            flag = 1;
        }
    }
    for (int i = arr_index;i < MAX;i++)
    {
        arr[i] = -1;
    }
    if (flag == 1)
    {
        return true;
    }
    else
    {
        return false;
    }
}
void clear_workspace(void)
{
    for (int i = 0;i < MAX;i++)
    {
        for (int j = 0;j < MAX;j++)
        {
            visited[i][j] = false;
        }
    }
}
问题排查与修复

1. 核心逻辑错误:branches函数赋值错误

在branches函数中,需要收集当前loser作为胜者时击败的对象(即新的败者),但代码错误地将pairs[i].winner存入数组,导致后续递归追踪同一个节点(当前loser自己),引发逻辑混乱甚至死循环。

修复:将arr[arr_index] = pairs[i].winner;改为arr[arr_index] = pairs[i].loser;

2. 循环检测逻辑缺失:未判断是否回到起点

当前check_for_loop函数没有检测是否回到初始的start节点,这是判断循环的核心条件——从start出发最终回到start即形成循环。

修复:在check_for_loop函数开头添加判断:

if (end == start) {
    return true;
}

3. Visited数组使用错误:追踪节点而非边

原代码用二维visited数组标记边是否被访问,但实际需要追踪路径中的节点是否被访问,避免重复遍历导致栈溢出(段错误的主要原因之一)。

修复:将二维visited[MAX][MAX]改为一维visited[MAX],并修改相关函数逻辑:

  • clear_workspace改为重置一维数组:
void clear_workspace(void)
{
    for (int i = 0;i < MAX;i++)
    {
        visited[i] = false;
    }
}
  • check_for_loop中标记当前节点为已访问,并添加回溯逻辑:
bool check_for_loop(int start, int end)
{
    if (end == start) {
        return true;
    }
    if (visited[end]) {
        return false;
    }
    visited[end] = true;
    
    int arr[MAX * MAX] = {-1};
    if (branches(end, arr) == true)
    {
        for (int i = 0; arr[i] != -1; i++)
        {
            if (check_for_loop(start, arr[i]) == true)
            {
                return true;
            }
        }
    }
    visited[end] = false;
    return false;
}

4. 数组遍历边界错误

原check_for_loop中固定循环MAX次,但实际有效元素可能少于MAX,改为遍历到arr[i] != -1即可,避免访问无效元素。

修复后的完整代码
#include <stdio.h>
#include <stdbool.h>
#define MAX 5

int preferences[MAX][MAX] = {0};

bool locked[MAX][MAX];

bool visited[MAX]; // 修改为一维数组,标记节点是否被访问

typedef struct
{
    int winner;
    int loser;
} pair;

pair pairs[] ={{0,2}, {0,1}, {0,3}, {1,2}, {0,4}, {3,1}, {3,2}, {3,4}, {4,1}, {4,2}};
int pair_count = MAX*(MAX - 1)/2;

void clear_workspace(void);
bool check_for_loop(int start, int end);
bool branches(int loser, int arr[]);
void lock_pairs(void);

int main(void)
{
    for (int i = 0; i < MAX; i++)
    {
        for (int j = 0; j < MAX; j++)
        {
            locked[i][j] = false;
        }
    }
    lock_pairs();
    
    // 可选:打印locked数组验证结果
    printf("Locked array:\n");
    for (int i = 0; i < MAX; i++) {
        for (int j = 0; j < MAX; j++) {
            printf("%d ", locked[i][j]);
        }
        printf("\n");
    }
}

void lock_pairs(void)
{
    for (int i = 0;i < pair_count;i++)
    {
        int start = pairs[i].winner;
        int end = pairs[i].loser;
        clear_workspace();
        if(check_for_loop(start, end) == false)
        {
            locked[start][end] = true;
        }
    }
}

bool check_for_loop(int start, int end)
{
    // 终止条件:回到起点,形成循环
    if (end == start) {
        return true;
    }
    // 已访问过该节点,无需继续遍历
    if (visited[end]) {
        return false;
    }
    visited[end] = true;
    
    int arr[MAX * MAX] = {-1};
    if (branches(end, arr) == true)
    {
        // 遍历所有后续节点,直到遇到-1
        for (int i = 0; arr[i] != -1; i++)
        {
            if (check_for_loop(start, arr[i]) == true)
            {
                return true;
            }
        }
    }
    // 回溯,取消节点访问标记
    visited[end] = false;
    return false;
}

bool branches(int loser, int arr[])
{
    int arr_index = 0;
    int flag = 0;
    for (int i = 0;i < pair_count;i++)
    {
        if (pairs[i].winner == loser)
        {
            // 存入当前胜者击败的败者,而非胜者自己
            arr[arr_index] = pairs[i].loser;
            arr_index++;
            flag = 1;
        }
    }
    // 末尾补-1,标记数组结束
    arr[arr_index] = -1;
    return flag == 1;
}

void clear_workspace(void)
{
    for (int i = 0;i < MAX;i++)
    {
        visited[i] = false;
    }
}

内容的提问来源于stack exchange,提问作者Level-0

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 22:29:56