2016-09-21 10 views
1

を解放セグメンテーションフォールトを取得します。私は単語パズルを解決するためにC言語でいくつかのコードを書いています - (英国のCountdownというゲームから)ゲームはあなたに9文字の手紙が与えられ、目標はあなたができる最長の言葉を作ることです。 (私は完全にそれをテストしていないが)、私は解放するためにすべての呼び出しをコメントアウトした場合ワードパズルソルバーを書くと私はヒープメモリといくつかの問題を抱えていますヒープメモリ

私のコードは動作します()が、私はで無料通話を置くとき、私はセグメンテーションフォールトを取得します。私はvalgrindを実行し、 "アドレス0x9cbe627はサイズ9のブロックの中に7バイトあり、サイズ1の無効な読み込み"のようなエラーメッセージが表示されます。私はこれについて調べるためにオンラインで調べてみましたが、私はまだ理解していません。

誰もが見て、何が起こっているか説明できますか? (以下のコード)私は非常に感謝しています!

/** 
* Program to solve word puzzles from the TV show Countdown. Asks for 9 
* letters for input and then prints out the 
* maximum score and an example word of that score 
*/ 

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

/* 
uses recursion to iterate over combinations of size "length" from 
data[] of size "lengthData." Stores combinations generated in 
combination[] and permutations in permutation[]. For each combination 
calls checkPermutations to iterate over all permutations 
of the combination checking against a dictionary for word matches 
returning true if a match is found 
*/ 
bool checkForWords(char data[], int lengthData, int length, char 
        combination[], int lengthCombination, char permutation[]); 

/** 
    * takes in an array - (in practice combination[] from main()) and 
    * iterates through all the permutations of the array storing 
    * generated permutations in permutation[] by using recursion. For 
    * each checks against a dictionary for word match. Returns true 
    * when match is found 
    */ 
bool checkPermutations(char data[], int lengthData, char permutation[], 
         int lengthPermutation); 

/** 
* takes an array of some length and an index and then retruns a 
* pointer to an array on the heap that is the same but with the 
* elements at the index and to the left removed and then remaining 
* elements "shifted down" 
*/ 
char* removeLeftOfIndex(char data[], int lengthData, int index); 

/** 
* takes an array of some length and index position and returns a  
* pointer to an array on the heap that has the element removed 
* and remaining elements "shifted down" 
*/ 
char* removeElementAtIndex(char data[], int lengthData, int index); 

int main(void) 
{ 
char letters[9]; 

// getting letters 
for (int i = 0; i < 9; i++) 
{ 
    printf("Please enter letter %i: ", i + 1); 
    letters[i] = GetChar(); 
} 

// formatting 
printf("\n"); 


// iterating over the length of word to look for starting at 9 and 
    decrementing 
for (int i = 9; i > 0; i--) 
{ 
    char* data = malloc(9 * sizeof(char)); 
    char* permutation = malloc(10 * sizeof(char)); 
    char* combination = malloc(9 * sizeof(char)); 

    for (int j = 0; j < 9; j++) 
     data[j] = letters[j]; 

    // checks to see if there is a word of length i 
    if (checkForWords(data, 9, i, combination, i, permutation) == true) 
    { 
     printf("Max score: %i\nExample word: %s\n", i, permutation); 
     free(permutation); 
     return 0; 
    } 

    free(permutation); 
} 

// no words found 
printf("Max score: 0\nNo words can be made\n"); 
return 0; 
} 

bool checkForWords(char data[], int lengthData, int length, char 
        combination[], int lengthCombination, char permutation[]) 
{ 
// base recursive case 
if (length == 0) 
{ 
    free(data); 

    // checks for permutations for the fixed combination 
    return checkPermutations(combination, lengthCombination, permutation, lengthCombination); 
} 

else 
{ 
    // generating combination by fixing one element and the recursively generating and checking 
    for (int j = 0; j <= lengthData - length; ++j) 
    { 
     // fixes one element 
     combination[lengthCombination - length] = data[j]; 

     // recursive part 
     if (checkForWords(removeLeftOfIndex(data, lengthData, j), lengthData - j - 1, length - 1, combination, 
      lengthCombination, permutation) == true) 
      { 
       free(data); 
       return true; 
      } 
    } 

    free(data); 
    return false; 
} 
} 

bool checkPermutations(char data[], int lengthData, char permutation[], int lengthPermutation) 
{ 

// base recursive case 
if (lengthData == 0) 
{ 
    // null character for printing string later 
    permutation[lengthPermutation] = '\0'; 


    // checking against dictionary - make this much faster with binary search!!!! 
    FILE* dictionary= fopen("/usr/share/dict/words", "r"); 
    char word[15]; 
    while (fgets(word, sizeof(word), dictionary) != NULL) 
    { 
     // checks to see if match 
     if (strncmp(permutation, word, lengthPermutation) == 0) 
     { 
      fclose(dictionary); 
      free(data); 
      return true; 
     } 

    } 

    // not in dictionary 
    fclose(dictionary); 


    free(data); 
    return false; 

} 

else 
{ 
    // generating permutations and checking for words by fixing one element and then using recursion. 
    for (int j = 0; j < lengthData; j++) 
    { 
     // fixing element 
     permutation[lengthPermutation - lengthData] = data[j]; 

     // recursive part 
     if (checkPermutations(removeElementAtIndex(data, lengthData, j), lengthData - 1, permutation, lengthPermutation) == true) 
     { 
      free(data); 
      return true; 
     } 

    } 
    free(data); 
    return false; 
} 
} 

char* removeLeftOfIndex(char data[], int lengthData, int index) 
{ 
// allocating heap memory 
char* newData = malloc((lengthData - index - 1) * sizeof(char)); 

// loop to copy relevant parts 
for (int j = 0; j < lengthData - index - 1; j++) 
    newData[j] = data[j + index + 1]; 

return newData; 
} 

char* removeElementAtIndex(char data[], int lengthData, int index) 
{ 
// allocating heap memory 
char* newData = malloc((lengthData - 1) * sizeof(char)); 

// loops to copy relevant parts 
for (int i = 0; i < index; i++) 
    newData[i] = data[i]; 
for(int i = index; i < lengthData - 1; i++) 
    newData[i] = data[i + 1]; 

return newData; 

} 

また、私はセグメンテーションフォールトは、コードの最後の関数の実装にmalloc()への呼び出しで起こっているように見えているのデバッグをしようとしたときにすることを言及する価値があるかもしれません:

// allocating heap memory 
char* newData = malloc((lengthData - 1) * sizeof(char)); 
+1

Valgrindを使用しているときに、エラーメッセージ(サイズ1の無効な読み取り)に行番号が関連付けられている必要があります。多くの場合、Valgrindはポインタがmallocされた行番号を教えます。あなたは、この行番号が表示されない場合は、お使いのコンパイルフラグ(すなわち 'gccの-g -o progのsourceFile.c')に' -g'を追加してみてください、とセグメンテーション違反が発生する場合に、その後通常の方法 – Ankush

+0

であなたのプログラム上のValgrindを実行していますmallocでは、ヒープが破損しています。つまり、割り当てられたメモリの外側に書き込んだり、以前に解放したブロックを使用している可能性があります。 –

+0

あなたは 'free(data)'をあまりにも多く呼んでいると思います。あなたのmallocを整理して、別の方法で自由にして、 'free'が' malloc'に対応するコードを見てみましょう。 –

答えて

1

あなたコードはかなりのスパイダーのメモリ割り当てと解放のウェブです。メモリの割り当ては、もう少し意味をなさないので、私はそれを作り直してきた、呼び出し元のサブルーチン空きメモリを持つことが奇数である(とにかく、私には。) - 反対が呼び出し側は、サブルーチンの戻り値の結果を解放した、OKです。

基本的なケースでは(正確な辞書に単語を一致させる)動作しているようですが、私は私がこのコードはより多くのデバッグを必要とするかもしれない他の可能性をテストすることができたと言うことはできません。しかし、それはメモリエラーについて不満はありません:

/** 
* Program to solve word puzzles from the TV show Countdown. 
* Asks for 9 letters for input and then prints out the 
* maximum score and an example word of that score 
*/ 

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

/** 
uses recursion to iterate over combinations of size "length" from 
data[] of size "lengthData." Stores combinations generated in 
combination[] and permutations in permutation[]. For each combination 
calls checkPermutations to iterate over all permutations 
of the combination checking against a dictionary for word matches 
returning true if a match is found 
*/ 
bool checkForWords(char data[], int lengthData, int length, char combination[], int lengthCombination, char permutation[]); 

/** 
* takes in an array - (in practice combination[] from main()) and 
* iterates through all the permutations of the array storing 
* generated permutations in permutation[] by using recursion. For 
* each checks against a dictionary for word match. Returns true 
* when match is found 
*/ 
bool checkPermutations(char data[], int lengthData, char permutation[], int lengthPermutation); 

/** 
* takes an array of some length and an index and then returns a 
* pointer to an array on the heap that is the same but with the 
* elements at the index and to the left removed and then remaining 
* elements "shifted down" 
*/ 
char *removeLeftOfIndex(char data[], int lengthData, int index); 

/** 
* takes an array of some length and index position and returns a 
* pointer to an array on the heap that has the element removed 
* and remaining elements "shifted down" 
*/ 
char *removeElementAtIndex(char data[], int lengthData, int index); 

#define LETTER_COUNT (9) 

int main(void) 
{ 
    char letters[LETTER_COUNT]; 

    // getting letters 
    for (int i = 0; i < LETTER_COUNT; i++) 
    { 
     printf("Please enter letter %i: ", i + 1); 
     letters[i] = GetChar(); 
    } 

    // formatting 
    printf("\n"); 

    bool success = false; 

    char *data = malloc(LETTER_COUNT); 
    char *permutation = malloc(LETTER_COUNT + 1); 
    char *combination = malloc(LETTER_COUNT); 

    // iterating over the length of word to look for starting at 9 and decrementing 
    for (int i = LETTER_COUNT; i > 0; i--) 
    { 
     (void) strncpy(data, letters, LETTER_COUNT); 

     // checks to see if there is a word of length i 
     if (checkForWords(data, LETTER_COUNT, i, combination, i, permutation)) 
     { 
      printf("Max score: %i\nExample word: %s\n", i, permutation); 
      success = true; 
      break; 
     } 
    } 

    if (!success) 
    { 
     printf("Max score: 0\nNo words can be made\n"); 
    } 

    free(data); 
    free(permutation); 
    free(combination); 

    return EXIT_SUCCESS; 
} 

bool checkForWords(char data[], int lengthData, int length, char combination[], int lengthCombination, char permutation[]) 
{ 
    // base recursive case 
    if (length == 0) 
    { 
     // checks for permutations for the fixed combination 
     return checkPermutations(combination, lengthCombination, permutation, lengthCombination); 
    } 

    // generating combination by fixing one element and the recursively generating and checking 
    for (int j = 0; j <= lengthData - length; ++j) 
    { 
     // fixes one element 
     combination[lengthCombination - length] = data[j]; 

     // recursive part 
     char *reduced = removeLeftOfIndex(data, lengthData, j); 
     if (checkForWords(reduced, lengthData - j - 1, length - 1, combination, lengthCombination, permutation)) 
     { 
      free(reduced); 
      return true; 
     } 
     free(reduced); 
    } 

    return false; 
} 

bool checkPermutations(char data[], int lengthData, char permutation[], int lengthPermutation) 
{ 
    // base recursive case 
    if (lengthData == 0) 
    { 
     // null character for printing string later 
     permutation[lengthPermutation] = '\0'; 

     // checking against dictionary - make this much faster with binary search!!!! 
     FILE* dictionary= fopen("/usr/share/dict/words", "r"); 
     char word[64]; 

     while (fgets(word, sizeof(word), dictionary) != NULL) 
     { 
      // checks to see if match 
      if (strncmp(permutation, word, lengthPermutation) == 0) 
      { 
       fclose(dictionary); 
       return true; 
      } 
     } 

     // not in dictionary 
     fclose(dictionary); 
     return false; 
    } 

    // generating permutations and checking for words by fixing one element and then using recursion. 
    for (int j = 0; j < lengthData; j++) 
    { 
     // fixing element 
     permutation[lengthPermutation - lengthData] = data[j]; 

     // recursive part 
     char *reduced = removeElementAtIndex(data, lengthData, j); 
     if (checkPermutations(reduced, lengthData - 1, permutation, lengthPermutation)) 
     { 
      free(reduced); 
      return true; 
     } 
     free(reduced); 
    } 

    return false; 
} 

char *removeLeftOfIndex(char data[], int lengthData, int index) 
{ 
    // allocating heap memory 
    char *newData = malloc(lengthData - index - 1); 

    // loop to copy relevant parts 
    for (int j = 0; j < lengthData - index - 1; j++) 
    { 
     newData[j] = data[j + index + 1]; 
    } 

    return newData; 
} 

char *removeElementAtIndex(char data[], int lengthData, int index) 
{ 
    // allocating heap memory 
    char *newData = malloc(lengthData - 1); 

    // loops to copy relevant parts 
    for (int i = 0; i < index; i++) 
    { 
     newData[i] = data[i]; 
    } 

    for (int i = index; i < lengthData - 1; i++) 
    { 
     newData[i] = data[i + 1]; 
    } 

    return newData; 
} 

幸運と私はこれが助けて欲しいです!

+0

非常にありがとう、cdlane、それはコードを整理する方法について多くを助けます。私は関数removeLeftOfIndexとremoveElementAtIndexを他の関数への呼び出しのためにパラメータリストの中で呼び出し、ポインタ変数に保存しないようにしました。(あなたが "reduce"で行ったように)そうしたら、サブルーチン呼び出しで呼び出し元のメモリを解放します呼び出し元のポインタがないためです。 –

+0

また、あなたの投稿を投票しようとしましたが、十分な評判がまだありません。 –

+0

最後に、話題にならないと考えられるかどうかは分かりません私のコードはおそらくメモリ配分と解放の面だけではなく、おそらく「スパイダーのウェブ」だったかもしれないと思いました。誰かが改善する方法についての他の指針を持っているなら、私は再び非常に感謝します! –