Supprimer un élément d'un tableau d'une stucture

a marqué ce sujet comme résolu.

Bonjour à tous.

Je dois faire un sudoku pour mon projet et j’ai un problème avec un tableau de structure. En effet, après avoir placé une valeur dans une case avec la méthode des candidats uniques ( le programme "scan" la grille en regardant quelles cases ont un seul candidat et la remplit par ce dernier ) je dois forcement enlever ce candidat des cases voisines ( donc case de la même ligne / colonne / région ). Le problème est que … je n’y arrive pas , j’ai par exmple essayé de faire un décalage vers la gauche dans le tableau ou encore de remettre tout à 0 mais ca ne marche pas … mon programme s’arrete sans me dire d’erreur. Mon code :

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define TAILLE 9
typedef struct {
    int x; // numéro de ligne
    int y; // numéro de colonne
} Case;
typedef struct {
    int nbc; // nombre de candidats
    int * tab; // table des candidats
} Cand;
 
Cand C[9][9];
Case O[81] ;
int NBO=0;
int G[TAILLE][TAILLE];
void lireGrille();
void ecrireGrille();
void estCand(int,int,int);
void initJeu();
void rechCaseUnique();
bool estCandUnique(int ,int ,int);
bool appartient(int , int ,int);
bool absentSurLigne (int, int G[9][9], int);
bool absentSurColonne (int, int G[9][9], int );
bool absentSurBloc (int, int G[9][9], int, int);
void fermerCase(int , int ,int);
void fermerGrille();
 
 
 
int main() {
    int k=0,i,j;
    lireGrille();
    printf("Voici la grille initial :\n");
    ecrireGrille();
    initJeu();
    for(i=0;i<9;i++){
        for(j=0;j<9;j++){
            for(k=1;k<=9;k++){
                C[i][j].tab = malloc(9 * sizeof(int));
                if(G[i][j]==0){
                    estCand(i,j,k);
                     
                }
 
             
            }
        }
    }
     
    fermerGrille();
    ecrireGrille();
}
  
void lireGrille() {
     int i=0,j=0,z=0; //Variables pour initialisé le tableau G
    FILE* fichier = NULL;
    fichier = fopen("sudoku.txt", "r");
  
    if (fichier != NULL) {
                while(fscanf(fichier,"%d %d %d",&i,&j,&z)==3) {
                            G[i][j]= z;
                             
                                }
                                             
                fclose(fichier);
         
    }
     
    else {
  
        printf(" Une erreur c'est produite lors du chargement du fichier Sudoku !\n");
    }
     
}
 
void ecrireGrille(){
        int i=0;
        int j=0;
        int m=0;
        printf("-------------------------------- \n");
        for(i=0; i<9;i++){
            printf("|");
            for(j=0;j<9;j++){
                printf("%3d", G[i][j]);
                m+=1;
                if (m%3==0)
                    printf("|");
 
                }
                 
            printf("\n");
            if((i+1)%3==0 && i>0 && i!=8)
                printf("|-----------------------------| \n");
            }
            printf("-------------------------------- \n");
    }  
     
         
void estCand(int i, int j, int k){
    if ((absentSurLigne(k,G,i) && absentSurColonne(k,G,j) && absentSurBloc(k,G,i,j)) && k!=0){
        C[i][j].nbc+=1;
        C[i][j].tab[C[i][j].nbc]=k;
    }
 
      
}
     
 
     
bool absentSurLigne (int k, int G[9][9], int i) //Test si une valeur k est absente sur la ligne i
{
    for (int j=0; j < 9; j++)
        if (G[i][j] == k)
            return false;
    return true;
}
 
bool absentSurColonne (int k, int G[9][9], int j)//Test si une valeur k est absente sur la colonne j
{
    for (int i=0; i < 9; i++)
        if (G[i][j] == k)
            return false;
    return true;
}
 
bool absentSurBloc (int k, int G[9][9], int i, int j)//Test si une valeur k est absente dans le bloc de la case[i][j]
{
    int x = i-(i%3), y = j-(j%3);
    for (i=x; i < x+3; i++)
        for (j=y; j < y+3; j++)
            if (G[i][j] == k)
                return false;
    return true;
}
 
void initJeu(){
    int i,j;
     
    for(i=0; i<9;i++){
        for(j=0;j<9;j++){
            if(G[i][j]!=0){
                C[i][j].nbc=0;
                C[i][j].tab=NULL;
            }
            else {
                C[i][j].nbc=0;
                C[i][j].tab=NULL;
                O[NBO].x=i;
                O[NBO].y=j;
                NBO+=1;
            }
             
        }
    }
}
 
bool appartient(int i, int j, int k){
    int a=0;
    for(a=1;a<TAILLE;a++){
        if(k==C[i][j].tab[a]){
            return true;
    }
}
    return false;
}
 
 
bool estCandUnique(int i, int j ,int k){
    if(C[i][j].nbc==1 && C[i][j].tab[1]==k){
        return true;
    }
    return false;
}
 
void rechCaseUnique(){
    for(int i=0;i<9;i++){
        for(int j=0;j<9;j++){
            for(int k=1;k<=9;k++){
                if(estCandUnique(i,j,k)){
                    fermerCase(i,j,k);
                }
            }
        }
    }
}
 
void fermerCase(int i, int j, int k){
    G[i][j]=k;
    C[i][j].nbc=0;
    C[i][j].tab=NULL;
    NBO-=1;        
 
}
                 
void fermerGrille(){
    int i,j,k;
    do{
         rechCaseUnique();
         for(i=0;i<9;i++){
            for(j=0;j<9;j++){
            for(k=1;k<=9;k++){
                if(G[i][j]==0){
                    estCand(i,j,k);
                }
            }
        }
    }
          
    } while(NBO==0);
}
     
     
                

La suppression doit être faite dans la fonction fermerCase.

Si besoin : le sujet https://www.mediafire.com/file/ma8k8zzl5ta088a/C_A1_sudoku_18_19.pdf/file

et le fichier sudoku.txt :https://www.mediafire.com/file/0nfdfyddn2cj59d/sudoku.txt/file

Merci d’avance

+0 -0

Salut,

Patiente un peu, tu as posté il y a même pas deux heures, et on est le 2 Janvier… :-°

Par ailleurs, merci de mettre ton fichier sudoku.txt sur un service qui ne demande pas de s’inscrire ou désactiver son bloqueur de pub pour y accéder (comme par exemple sur ce forum même dans un bloc secret) ou bien de nous expliquer comment on est censé le formater pour pouvoir en construire un nous même.

+2 -0

C’est vrai excuse moi, je suis de nature impatiente :p . je vous met le contenu du sudoku.txt ici :

0 5 1
0 7 8
1 0 2
1 2 4
1 4 7
1 7 3
1 8 5
2 1 7
2 4 5
2 5 6
2 6 2
2 7 1
3 1 6
3 3 2
3 5 5
3 8 1
4 0 3
4 8 6
5 0 1
5 3 6
5 5 7
5 7 2
6 1 3
6 2 1
6 3 8
6 4 6
6 7 7
7 0 7
7 1 2
7 4 1
7 6 8
7 8 4
8 1 5
8 3 7

En faite chaque ligne correspond à une case remplie de base : le premier chiffre sa position x, le 2eme sa position y et le dernier le chiffre dans cette dite case ( les lignes / colonnes sont numéroté de 0 à 8).

Merci !

Quand ton programme crashe comme ça sans rien te dire, une bonne habitude est déjà de compiler en mode debug puisque ton compilateur va laisser des informations qui peuvent aider au debuggage (ici, ça aide pas des masses, mais autant te le montrer).

gcc -O0 --debug main.c

Puis un outil très utile pour vérifier si ce n’est pas juste un problème de fuite de mémoire ou similaire (mauvais accès mémoire par exemple), un outil pratique est valgrind.

valgrind ./a.out 2>&1 >&- >/dev/null | xclip

Le morceau 2>&1 >&- >/dev/null | xclip sert juste à mettre la sortie standard à la poubelle et récupérer la sortie erreur (celle de valgrind) dans le presse-papier. Si tu es sous Windows, je ne sais pas comment faire ça mais la commande valgrind marche pareil. Il suffit de mettre son nom et celui de ton fichier exécutable pour laisser la magie opérer.

Avec ton code, j’obtiens un message qui devrait te mettre sur la voie :

==5044== Memcheck, a memory error detector
==5044== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5044== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==5044== Command: ./a.out
==5044== 
==5044== Invalid write of size 4
==5044==    at 0x1095F1: estCand (main.c:105)
==5044==    by 0x109B55: fermerGrille (main.c:206)
==5044==    by 0x1092AF: main (main.c:53)
==5044==  Address 0x4a55c74 is 0 bytes after a block of size 36 alloc'd
==5044==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==5044==    by 0x10920C: main (main.c:42)
==5044== 
==5044== 
==5044== HEAP SUMMARY:
==5044==     in use at exit: 26,244 bytes in 729 blocks
==5044==   total heap usage: 732 allocs, 3 frees, 34,988 bytes allocated
==5044== 
==5044== LEAK SUMMARY:
==5044==    definitely lost: 23,436 bytes in 651 blocks
==5044==    indirectly lost: 0 bytes in 0 blocks
==5044==      possibly lost: 0 bytes in 0 blocks
==5044==    still reachable: 2,808 bytes in 78 blocks
==5044==         suppressed: 0 bytes in 0 blocks
==5044== Rerun with --leak-check=full to see details of leaked memory
==5044== 
==5044== For counts of detected and suppressed errors, rerun with: -v
==5044== ERROR SUMMARY: 2 errors from 1 contexts (suppressed: 0 from 0)
+0 -0

Le morceau le plus intéressant est celui-là :

==5044== Invalid write of size 4
==5044==    at 0x1095F1: estCand (main.c:105)
==5044==    by 0x109B55: fermerGrille (main.c:206)
==5044==    by 0x1092AF: main (main.c:53)
==5044==  Address 0x4a55c74 is 0 bytes after a block of size 36 alloc'd
==5044==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==5044==    by 0x10920C: main (main.c:42)

où il te dit qu’à la ligne 105 (ie C[i][j].tab[C[i][j].nbc]=k) tu essayes de mettre un truc de 4 bytes (ton int k) à un endroit qui ne peut pas les prendre. Et pour cause, ce machin est juste après ce que tu as effectivement alloué (c’est le Address 0x4a55c74 is 0 bytes after a block of size 36 alloc'd). Soit tu n’as pas alloué assez, soit ton indice est pas bon et tu écris en dehors du tableau.

+0 -0

Il faut donc que j’augmente le nombre de byte ? Et aussi comment ça j’écris en dehors du tableau ? Le problème étant que quand j’ai print ce tableau pour voir si cela étais bon , tout s’affiché correctement

EDIT : oublie la derniere phrase, je ne l’avais pas affiché

+0 -0

Salut,

Premier conseil : essaye de rendre ton code un peu plus lisible, notamment :

  • N’hésite pas à espacer tes lignes (pas spécialement chaque ligne, mais par suites logiques par exemple, comme après un ou des blocs de conditions) et les éléments des expressions ;
  • Quand il ne s’agit pas simplement d’itérateur, évite des noms comme i, j et k qui n’ont pas un sens clair au premier coup d’oeil.

Sinon, après une première lecture, une des choses qui me saute aux yeux est ceci.

for (i = 0; i < 9; i++)
    for (j = 0; j < 9; j++)
        for (k = 1; k <= 9; k++) {
            C[i][j].tab = malloc(9 * sizeof(int));

            if(G[i][j] == 0)
                estCand(i,j,k);
        }

Tu ne vois rien de problématique ligne 4 sachant que tu effectues cette opération au sein d’une boucle ?

+0 -0

Salut , j’ai changé un peu le programme avant de lire ton message

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define TAILLE 9
typedef struct {
    int x; // numéro de ligne
    int y; // numéro de colonne
} Case;
typedef struct {
    int nbc; // nombre de candidats
    int * tab; // table des candidats
} Cand;

Cand C[9][9];
Case O[81] ;
int NBO=0;
int G[TAILLE][TAILLE];
void lireGrille();
void ecrireGrille();
void estCand(int,int,int);
void initJeu();
void rechCaseUnique();
bool estCandUnique(int ,int ,int);
bool appartient(int , int ,int);
bool absentSurLigne (int, int G[9][9], int);
bool absentSurColonne (int, int G[9][9], int );
bool absentSurBloc (int, int G[9][9], int, int);
void fermerCase(int , int ,int);
void fermerGrille();



int main() {
    lireGrille();
    printf("Voici la grille initial :\n");
    ecrireGrille();
    initJeu();
    fermerGrille();
    ecrireGrille();
}
 
void lireGrille() {
     int i=0,j=0,z=0; //Variables pour initialisé le tableau G
    FILE* fichier = NULL;
    fichier = fopen("sudoku.txt", "r");
 
    if (fichier != NULL) {
                while(fscanf(fichier,"%d %d %d",&i,&j,&z)==3) {
                            G[i][j]= z;
                            
                                }
                                            
                fclose(fichier);
        
    }
    
    else {
 
        printf(" Une erreur c'est produite lors du chargement du fichier Sudoku !\n");
    }
    
}

void ecrireGrille(){
        int i=0;
        int j=0;
        int m=0;
        printf("-------------------------------- \n");
        for(i=0; i<9;i++){

            printf("|");
            for(j=0;j<9;j++){

                printf("%3d", G[i][j]);
                m+=1;
                if (m%3==0)
                    printf("|");

                }
                
            printf("\n");
            if((i+1)%3==0 && i>0 && i!=8)

                printf("|-----------------------------| \n");
            }
            printf("-------------------------------- \n");
    }   
    
        
void estCand(int i, int j, int k){
    if ((absentSurLigne(k,G,i) && absentSurColonne(k,G,j) && absentSurBloc(k,G,i,j)) && k!=0){
        C[i][j].nbc+=1;
        C[i][j].tab[C[i][j].nbc]=k;
    }

     
}
    

    
bool absentSurLigne (int k, int G[9][9], int i) //Test si une valeur k est absente sur la ligne i
{
    for (int j=0; j < 9; j++)
        if (G[i][j] == k)
            return false;
    return true;
}

bool absentSurColonne (int k, int G[9][9], int j)//Test si une valeur k est absente sur la colonne j
{
    for (int i=0; i < 9; i++)
        if (G[i][j] == k)
            return false;
    return true;
}

bool absentSurBloc (int k, int G[9][9], int i, int j)//Test si une valeur k est absente dans le bloc de la case[i][j]
{
    int x = i-(i%3), y = j-(j%3); 
    for (i=x; i < x+3; i++)
        for (j=y; j < y+3; j++)
            if (G[i][j] == k)
                return false;
    return true;
}

void initJeu(){
    int i,j;
    for(i=0; i<9;i++){
        for(j=0;j<9;j++){
            if(G[i][j]!=0){
                C[i][j].nbc=0;
                C[i][j].tab=NULL;
            }
            else {
                C[i][j].nbc=0;
                C[i][j].tab=NULL;
                NBO+=1;
                                C[i][j].tab = malloc(9 * sizeof(int));
                O[NBO].x=i;
                O[NBO].y=j;
                for(int k=1;k<=9;k++){
                    for(k=1;k<=9;k++){
                        estCand(i,j,k);
                
            }
            
        }
    }
}
}
}

bool appartient(int i, int j, int k){
    int a=0;
    for(a=1;a<TAILLE;a++){
        if(k==C[i][j].tab[a]){
            return true;
    }
}
    return false;
}


bool estCandUnique(int i, int j ,int k){
    if(C[i][j].nbc==1 && C[i][j].tab[1]==k){
        return true;
    }
    return false;
}

void rechCaseUnique(){
    for(int i=0;i<9;i++){
        for(int j=0;j<9;j++){
            for(int k=1;k<=9;k++){
                if(estCandUnique(i,j,k)){
                    fermerCase(i,j,k);
                }
            }
        }
    }
}

void fermerCase(int i, int j, int k){
    G[i][j]=k;
    C[i][j].nbc=0;
    C[i][j].tab=NULL;
    NBO-=1; 
    for(int x=0;x<9;x++){
        for(int z=1;z<=9;z++){
            if(C[x][j].tab[z]==k){
                printf("oui");
            }
        }
    }
    
    
}
                
void fermerGrille(){
    do{
         rechCaseUnique();
    } while(NBO==0);
}
    
    
                

J’ai changé le main et la fonction initJeu. Si il se trouve dans une boucle je fais plusieurs fois une allocation c’est ça ? :/

+0 -0

Ce n’était pas le cas sur ton ancienne version. Note que maintenant, quand je l’exécute, j’ai une segfault à cause de la lecture de C[x][j].tab[z] après avoir mis C[x][j].tab à NULL dans fermerCase. Prends ton temps pour répondre, c’est dommage de perdre du temps sur des détails que tu aurais pu voir.

+0 -0

J’ai enlevé la ligne où je met NULL :

void fermerCase(int i, int j, int k){
    G[i][j]=k;
    NBO-=1; 
    for(int x=0;x<9;x++){
        for(int z=1;z<=9;z++){
            if(C[x][j].tab[z]==k){
                printf("oui");
            }
        }
    }

}

La sa me print 2 fois oui ( c’est juste pour test ^^ ) et sa replante

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte