2015-10-30 2 views
-4

Mon programme fonctionne correctement lorsque j'utilise un tableau de 81 éléments mais quand je fais face à un tableau de 256 blocs, il se bloque et je ne sais pas pourquoi il le fait. Je vous présente tout le code source et le texte d'entrée que vous pouvez utiliser dans un fichier .txt avec un dernier retour chariot.Pourquoi mon programme plante-t-il avec un débordement de pile?

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <conio.h> 
#include <windows.h> 
#include <malloc.h> 

int grille[256]; 
int domaine[256][17];  /* indique les valeurs possib pour case donnee */ 
int domaine_taille[256];  /* nombre de valeurs possibles une case donnee */ 
int compteur_noeuds; 
void restreindre_domaines(int); 
int backtrack(int imite_limite_par_ton_nez); 

#define PERR(bSuccess, api) \ 
    {if (!(bSuccess)) perr(__FILE__, __LINE__,api, GetLastError());} 
#define INCONNU -1 

void lire_grille() 
    { 
    int k = 0; 

    while (k < 256) { 
    char c = getchar(); 
    if (c >= '0' && c <= '9') //0 a 9 
     grille[k++] = c-48; 
    if(c >= 'a' && c <= 'f') // a a f 
     grille[k++] = c-87; 
    if (c == '.' || c == ' ' || c== '+') // espace + ou . 
     grille[k++] = INCONNU; 
    if (c == EOF) 
     { 
     fprintf(stderr, "Lecture de la grille : mauvais format\n"); 
     exit(1); 
    } }} 

void afficher_grille() /* afficher la grille courante sur stdout */ 
    { 
    int c, l; 

    for (l = 0; l < 16; l++) { 
    for (c = 0; c < 16; c++) { 
     int k = l*16+c; 
     if (grille[k] == INCONNU) printf("."); 
     if (grille[k] >= 0 && grille[k] <= 9) //0 a 9 
     printf("%c", grille[k]+48); 
     if(grille[k] >= 10 && grille[k] <= 15) // a a f 
     printf("%c", grille[k]+87); 
     } 
    printf("\n"); 
    } 
    printf("\n"); 
    } 



void init_domaines() /* en fonction grille,initialiser domaines */ 
    { 
    int i, v; 

    for (i = 0; i < 256; i++) 
    { 
    domaine_taille[i] = 16; 
    for (v = 0; v <= 16; v++) 
     domaine[i][v] = 1; 
    } 
    for (i = 0; i < 256; i++) /* restreindre domaines cases remplies */ 
    if (grille[i] != INCONNU) restreindre_domaines(i); 
    } 



/*oter valeurs des domaines incompatibles avec valeur case i */ 
void restreindre_domaines(int i) 
    { 
    int l = i/16; //ligne 
    int c = i % 16; //colonne 
    int lb = l/4; // 
    int cb = c/4; // 
    int l2, c2, lr2, cr2, i2; 

    /* contraintes de la colonne contenant la case i */ 
    for (l2 = 0; l2 < 16; l2++) { 
    i2 = l2*16+c; 
    if (domaine[i2][grille[i]]!=0) { 
     domaine[i2][grille[i]] = 0; 
     domaine_taille[i2]--; 
     } 
    } 

    /* contraintes de la ligne contenant la case i */ 
    for (c2 = 0; c2 < 16; c2++) { 
    i2 = l*16+c2; 
    if (domaine[i2][grille[i]]) { 
     domaine[i2][grille[i]] = 0; 
     domaine_taille[i2]--; 
     } 
    } 

    /* verifier la region contenant la case i */ 
    for (lr2 = 0; lr2 < 4; lr2++) 
    for (cr2 = 0; cr2 < 4; cr2++) { 
     i2 = (lb*4+lr2)*16+(cb*4+cr2); 
     if (domaine[i2][grille[i]]) { 
     domaine[i2][grille[i]] = 0; 
     domaine_taille[i2]--; 
    }}} 

int main() 
    { 
    lire_grille(); 
    afficher_grille(); 
    init_domaines(); 
    backtrack(0); 
    printf("%d noeuds cherches\n", compteur_noeuds); 

    printf(" \n"); 
    _getch(); 
    return 0; 
    } 

int backtrack(int uz) 
    { 
    if (uz==-99) return(uz); 
    int i, i_min = -1,aa=0; 
    int taille_min = 17; 
    int domaine2[256][17]; 
    int domaine_taille2[256]; 
    static int toc,Toc; 
    int iz,zzz=0; 
    toc++; 
    static int xu; 
    xu=true; 

    int lnum[16]; 

    lnum[0]=0; 
    lnum[1]=15; 
    lnum[2]=14; 
    lnum[3]=13; 
    lnum[4]=12; 
    lnum[5]=11; 
    lnum[6]=4; 
    lnum[7]=3; 
    lnum[8]=2; 
    lnum[9]=1; 
    lnum[10]=5; 
    lnum[11]=10; 
    lnum[12]=9; 
    lnum[13]=8; 
    lnum[14]=7; 
    lnum[15]=6; 

    int tst=0; 
    for (iz = 0; iz < 256; iz++) 
    { 
    if (grille[iz] != INCONNU)tst++; 
    } 
    if(tst==256) 
    { /*fin:*/ 
    // printf("\n%d 2 valeur tst\n", tst); 
    afficher_grille(); 
    xu=0; 
    return xu; 
    } 

    /* chercher la case avec le domaine le plus petit */ 
    for (i = 0; i < 256; i++) 
    { 
    if (grille[i] == INCONNU && domaine_taille[i] < taille_min) 
     { 
     i_min = i; 
     taille_min = domaine_taille[i]; 
     //printf("i %d *do_tail[i] %d *tail_min %d \n",i,domaine_taille[i],taille_min); 
     } 

    if(toc >10000) 
     { 
     toc=0; 
     afficher_grille(); 
     printf("\n%d noeuds cherches\n", compteur_noeuds); 
     printf(" toc %d et Toc %d \n",toc,Toc); 
     Toc++; 
     printf("-------------------------------------------\n"); 
     } 
    } 

    compteur_noeuds++; 

    // for (grille[i_min] = lnum[aa]; grille[i_min] <= lnum[aa+15]; grille[i_min]++,aa++) 
    for (grille[i_min] = 0; grille[i_min] <= 15; grille[i_min]++,aa++) 
    { 
    if (domaine[i_min][grille[i_min]] == 0) 
     continue; 
     /* on sauvegarde l'etat courant de domaine 
    et domaine_taille pour les retablir apres l'appel recursif */ 
    memcpy (domaine2, domaine, sizeof(domaine)); 
    memcpy (domaine_taille2, domaine_taille, sizeof(domaine_taille)); 
    restreindre_domaines(i_min); 
    backtrack(uz); 
    if (xu==0)return xu; 
    memcpy (domaine, domaine2, sizeof(domaine)); 
    memcpy (domaine_taille, domaine_taille2, sizeof(domaine_taille)); 
    } 
    grille[i_min] = INCONNU; 
    return 0; 
    } 

Vademecum: prog.exe < inp.txt

ici est un texte inp.txt avec un bon format (16x16 numéro 1-F et pour le cas de la recherche.)

.ae692...0..5.8d 
5....4.12.37.bc6 
..f.....5......4 
.b.8e5f..9.d..01 
.42b.17.3....... 
.3.52....bf0...c 
.......a.1..042b 
....4.cb8...1..a 
....f.4eb...3..8 
.......5.3..acef 
.7.2d....51f...9 
.e3c.ab.0....... 
.0.a58e..7.1..63 
..1.....d......2 
4....d.26.59.eb0 
.6b7c9...4..d.15 

Donc, si vous pouvez m'aider.

+6

Recommandez de lire ceci: http://stackoverflow.com/help/how-to-ask et cela http://stackoverflow.com/help/mcve. Je recommande également d'essayer de déboguer. Pire encore, vous avez des inclusions spécifiques au système d'exploitation dans votre programme. Si vous voulez que les gens vous aident, vous devriez certainement poster un code minimal qui reproduit vos erreurs. Et les noms de variables doivent être en anglais, pas français;) – LBes

+2

[Comment déboguer de petits programmes] (http://ericlippert.com/2014/03/05/how-to-debug-small-programs/) –

+5

'backtrack' nécessite environ 20 Ko de pile * par appel récursif *. La profondeur de la récursivité n'est pas évidente, mais si vous utilisez Windows (comme le suggère votre code), vous n'obtenez que 2 Mo de pile, ce qui est suffisant pour une profondeur de récursivité de 100 ou plus. Pensez à utiliser 'unsigned short', ou peut-être même' unsigned char' si toutes les valeurs nécessaires vont correspondre, pour tous les tableaux. Si cela ne suffit pas, vous devrez vous débarrasser de la récursivité et/ou passer à des tas de scratch alloués. – zwol

Répondre

1

Récursion trop profonde et trop chère dans l'espace. @zwol

J'ai eu le même débordement de pile. Pourtant en changeant int tableaux en char, ce n'était pas trop profond. profondeur de récursion 251 a donné lieu à

cae69237104b5f8d 
590da4812f37ebc6 
72f1bcd0568e9a34 
3b48e5f6a9cd7201 
642b017d3c9a85fe 
13a52e984bf06d7c 
8c9e3f5a71d6042b 
df7046cb8e25139a 
0159f74eb2ac36d8 
bd6410259378acef 
a782d36ce51fb049 
fe3c8ab90d642157 
20da58efc7b14963 
951f6b04d8e3c7a2 
48c37d126a59feb0 
e6b7c9a3f402d815 

17310 noeuds cherches 

devrait cette réduction se révéler insuffisante, allouer de la mémoire pour les tableaux ou modifier l'algorithme.


Le code comporte diverses autres lacunes, couvertes de commentaires, qui obscurcissent le problème central. Corriger ceux-ci ne résout pas le problème, mais permet aux autres (et OP probablement) de diagnostiquer plus facilement.

+0

@zwol: Je vous remercie, j'essaie avec l'autre type intégral. – Chriistophe