C 编写字谜解算器并获得分段故障释放堆内存

C 编写字谜解算器并获得分段故障释放堆内存,c,segmentation-fault,word,puzzle,cs50,C,Segmentation Fault,Word,Puzzle,Cs50,我在堆内存方面遇到了一些问题。我正在用C写一些代码来解决字谜(来自英国一个叫倒计时的游戏)。游戏是给你9个字母,目标是尽可能地写出最长的单词 如果我注释掉对free()的所有调用,我的代码就可以工作(尽管我还没有完全测试过),但是当我把free调用放进去时,就会出现分段错误。我运行了valgrind,得到了错误消息,如“地址0x9cbe627在一个大小为9的空闲块中有7个字节”和“无效读取大小为1”。我尝试在线查找,以了解这一点,但我仍然不明白 有人能看一下并解释一下发生了什么吗?(下面给出的代

我在堆内存方面遇到了一些问题。我正在用C写一些代码来解决字谜(来自英国一个叫倒计时的游戏)。游戏是给你9个字母,目标是尽可能地写出最长的单词

如果我注释掉对free()的所有调用,我的代码就可以工作(尽管我还没有完全测试过),但是当我把free调用放进去时,就会出现分段错误。我运行了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;

}

您的代码是一个相当大的内存分配和释放蜘蛛网。我对它进行了修改,这样内存分配就更有意义了(无论如何,对我来说)。让一个子程序释放其调用者的内存是很奇怪的——相反,让调用者释放子程序的返回结果是可以的

虽然基本情况(字典中单词的精确匹配)似乎有效,但我不能说我能够测试其他可能性,因此此代码可能需要更多调试。但它并不是在抱怨内存错误:

/**
 * 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;
}
/**
*解决电视节目倒计时中的单词难题的程序。
*要求输入9个字母,然后打印出
*最高分数和该分数的示例单词
*/
#包括
#包括
#包括
#包括
/**
使用递归迭代来自的大小“长度”的组合
大小为“lengthData”的数据[]。存储在中生成的组合
组合[]和置换[]中的置换。对于每个组合
调用checkPermutations以迭代所有置换
根据字典检查单词匹配的组合
如果找到匹配项,则返回true
*/
布尔校验字(字符数据[],整数长度数据,整数长度,字符组合[],整数长度组合,字符排列[]);
/**
*接收数组-(实际上是main()中的组合[])和
*迭代存储数组的所有排列
*使用递归在置换[]中生成置换。对于
*每个人都会对照字典检查单词匹配情况。返回true
*当找到匹配项时
*/
布尔校验置换(字符数据[],整数长度数据,字符置换[],整数长度置换);
/**
*获取具有一定长度的数组和索引,然后返回
*指向堆上相同但具有
*索引处和左侧的元素已删除,然后保留
*元素“下移”
*/
char*removereftofindex(char数据[],int长度数据,int索引);
/**
*获取具有一定长度和索引位置的数组并返回
*指向已删除元素的堆上数组的指针
*其余元素“下移”
*/
char*removeElementAtIndex(char数据[],int长度数据,int索引);
#定义字母计数(9)
内部主(空)
{
字符字母[字母计数];
//收到信件
对于(int i=0;i0;i--)
{
(作废)strncpy(数据、字母、字母计数);
//检查是否有长度为i的单词
if(校验字(数据、字母计数、i、组合、i、排列))
{
printf(“最大分数:%i\n示例单词:%s\n”,i,排列);
成功=真实;
打破
}
}
如果(!成功)
{
printf(“最大分数:0\n无法生成单词\n”);
}
免费(数据);
自由(置换);
自由(组合);
返回退出成功;
}
布尔校验字(字符数据[],整数长度数据,整数长度,字符组合[],整数长度组合,字符排列[])
{
//基本递归情况
如果(长度==0)
{ 
//检查固定组合的排列
返回校验排列(组合、长度组合、排列、长度组合);
}
//通过固定一个元素生成组合以及递归生成和检查

对于(int j=0;j当使用Valgrind时,错误消息(如
大小为1的无效读取
)应该有一个与之关联的行号-Valgrind通常会告诉您指针所在位置的行号。如果您没有看到这个行号,请尝试将
-g
添加到编译标志中(即,
gcc-g-o prog sourceFile.c
),然后以通常的方式在程序上运行Valgrind。如果segfault在malloc中发生,则堆已损坏。这意味着您可能已在分配的内存之外写入,或者仍在使用先前释放的块。我认为您正在调用
free(data)
太多了。尝试以不同的方式组织malloc和free,这样只要看一下
free
malloc
相对应的代码就可以明显看出,因此您在一个函数中创建了名为newData的堆内存,该函数反复点击。您是否释放过该内存?@BrianCross:没有释放分配的memory不会导致segfault。不过,OP在释放它们时会得到一个segfault,所以很可能会释放两次,或者覆盖分配的块。非常感谢cdlane,这对如何组织代码有很大帮助。我在参数列表中调用函数RemoveRefToFinder和removeElementAtIndex来调用其他函数并且没有将它们保存到指针变量中(就像您使用“reduced”时所做的那样),因此我别无选择,只能在子例程调用中释放调用者内存
/**
 * 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;
}