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

C语言Blackjack游戏开发遇Segmentation Fault及Invalid Read问题求助

Blackjack游戏C语言实现的指针与内存问题修复

问题背景

用C语言实现Blackjack游戏核心逻辑,定义了包含数值(Chiffre)和花色(Couleur)的Carte结构体,通过calloc分配可存储52张卡牌的数组,编写了TestPaire(检测是否有对子)和CompteCarte(计算卡牌总和)两个函数,但运行时出现Invalid read of size 4错误、WSL下触发Segmentation Fault,控制台先输出10后显示0。

核心错误分析

  1. sizeof的误用:函数中sizeof(*Jeu)获取的是指针类型的大小(比如64位系统是8字节),不是数组的元素个数。主函数仅初始化了前3张牌,但函数循环次数是指针大小的数值,导致访问未初始化的内存区域,触发越界读取错误。
  2. 循环变量错误:TestPaire的内层循环中,错误地将j++写成了i++,导致外层循环变量i被无限制递增,直接越界访问内存引发段错误。
  3. 参数设计缺陷:没有传递当前手牌的实际数量,依赖sizeof获取数组长度的方式在指针参数中完全失效——当数组名作为参数传递给函数时,会退化为指针,无法通过sizeof获取原数组的长度。

修正后的代码

结构体定义

typedef struct Carte {
    int Chiffre;
    char Couleur[10];
} Carte;

修正后的CompteCarte函数

// 新增参数nb_cartes:当前手牌的实际数量
int CompteCarte(Carte *Jeu, int nb_cartes) {
    int compteur = 0;
    for (int i = 0; i < nb_cartes; i++) {
        compteur += Jeu[i].Chiffre;
    }
    return compteur;
}

修正后的TestPaire函数

// 新增参数nb_cartes:当前手牌的实际数量
int TestPaire(Carte *Jeu, int nb_cartes) {
    for (int i = 0; i < nb_cartes; i++) {
        // 内层循环从i+1开始,避免重复比较
        for (int j = i + 1; j < nb_cartes; j++) {
            if (Jeu[i].Chiffre == Jeu[j].Chiffre) {
                return 1;
            }
        }
    }
    return 0;
}

修正后的主函数

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

int main(int argc, char const *argv[]) {
    Carte* Jeu = (Carte*)calloc(52, sizeof(Carte));
    if (Jeu == NULL) { // 新增内存分配失败的检查
        fprintf(stderr, "Erreur d'allocation mémoire\n");
        return 1;
    }

    Jeu[0].Chiffre = 3;
    Jeu[1].Chiffre = 1;
    Jeu[2].Chiffre = 6;
    int nb_cartes_joueur = 3; // 明确当前手牌数量

    int a = CompteCarte(Jeu, nb_cartes_joueur);
    printf("%d\n", a); // 输出应为10
    int b = TestPaire(Jeu, nb_cartes_joueur);
    printf("%d\n", b); // 输出应为0,因为没有对子

    free(Jeu); // 释放动态分配的内存
    return 0;
}

关键建议

  • 动态数组必须传递长度参数:所有操作动态数组的函数,都需要额外传入数组的实际元素个数,不能依赖sizeof计算长度。
  • 循环变量严格检查:编写嵌套循环时,注意循环变量的递增逻辑,避免出现笔误导致的无限循环或越界。
  • 内存分配后检查:使用calloc/malloc分配内存后,必须检查返回值是否为NULL,避免空指针访问。
  • 指针使用简化:主函数中Jeu是Carte*类型,直接传递Jeu即可(无需&Jeu),函数参数用Carte*接收,更符合数组的使用逻辑,避免不必要的二级指针复杂度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 20:20:03