【问题标题】:How do you debug C code that works in the debugger?您如何调试在调试器中工作的 C 代码?
【发布时间】:2014-06-05 12:26:32
【问题描述】:

我有以下 C 代码

double ComputeWord (String* word, List* dict, List* words, Matrix* results, String* ret) {
    int i = 0;
    signed long wordIndex = ListFind (words, (void*)word);
    double min = StringSize (word); // Largest possible cost
    int minIndex = 0;
    if (wordIndex == ListEnd (words) ) { 
        ListAppend(words, (void*) word);
        wordIndex = ListSize(words) - 1;
        MatrixExpand (results, 0, ListSize(words));
    }
    for (i = 0; i < ListSize(dict); i++) {
        if (!strcmp (CString(word), CString( (String*)ListElement(dict, i) ) ) ) { min = 0; minIndex = i; break; }
        double current = fromDatabase ((long)MatrixElement(results, i, wordIndex) );
        if (current == 0) {
            printf ("Was not processed\n");
            current = lDist (word, ListElement(dict, i) );
            MatrixSetElement (results, (void*)toDatabase(current), i, wordIndex);
        }
        if (current <= min) { min = current; minIndex = i; }
        printf ("%s to %s - %.1lf\n", word->elementArray, ((String*)ListElement (dict,     i))->elementArray, current);
    }

    String temp;
    StringInit (&temp);
    char temp2[256];

    sprintf (temp2, ",%.1lf", min);

    StringSet (&temp, temp2);

    StringConcatenate(ret, (String*) ListElement (dict, minIndex) );
    StringConcatenate(ret, &temp);

    StringDelete (&temp);
    StringAppend(ret, ' ');
    printf ("matched %s to %s - %.1lf\n", word->elementArray, ((String*)ListElement (dict, minIndex))->elementArray, min);
    return min;
}                                                                  

它的作用是接受一个字典字典和一个单词,并尝试使用 demerau-levenshtein 距离 (lDist) 匹配字典中的单词,然后将结果存储在一个矩阵中。

发生的情况是,虽然我的算法正确计算了距离,但它认为一些单词已经被存储,所以它得到一个不正确的 . 我尝试打开 GDB 试图弄清楚发生了什么,但程序在其中运行正常。

我得到的结果是:

creating dictionary
adding aspecto to dict
adding matematica to dict
adding algebra to dict
adding posicao to dict
adding profissao to dict
adding fourier to dict
adding casa to dict
adding calculo to dict
adding dificil to dict
Was not processed
aepscto to aspecto - 3.0
Was not processed
aepscto to matematica - 9.5
Was not processed
aepscto to algebra - 8.5
Was not processed
aepscto to posicao - 5.5
Was not processed
aepscto to profissao - 9.0
Was not processed
aepscto to fourier - 10.5
Was not processed
aepscto to casa - 6.5
Was not processed
aepscto to calculo - 7.0
Was not processed
aepscto to dificil - 9.0
matched aepscto to aspecto - 3.0
Was not processed
caculo to aspecto - 6.5
Was not processed
caculo to matematica - 11.0
Was not processed
caculo to algebra - 8.5
Was not processed
caculo to posicao - 7.0
Was not processed
caculo to profissao - 10.5
Was not processed
caculo to fourier - 9.0
Was not processed
caculo to casa - 5.0
Was not processed
caculo to calculo - 1.0
Was not processed
caculo to dificil - 7.5
matched caculo to calculo - 1.0
Was not processed
matmatica to aspecto - 10.0
Was not processed
matmatica to matematica - 1.0
Was not processed
matmatica to algebra - 9.5
Was not processed
matmatica to posicao - 8.5
Was not processed
matmatica to profissao - 11.5
Was not processed
matmatica to fourier - 11.0
Was not processed
matmatica to casa - 8.0
Was not processed
matmatica to calculo - 10.5
Was not processed
matmatica to dificil - 10.0
matched matmatica to matematica - 1.0
augebra to aspecto - 6.5
augebra to matematica - 11.0
augebra to algebra - 8.5
augebra to posicao - 7.0
augebra to profissao - 10.5
augebra to fourier - 9.0
augebra to casa - 5.0
augebra to calculo - 1.0
augebra to dificil - 7.5
matched augebra to calculo - 1.0

我注意到“augebra”的结果与“caculo”的结果完全相同,这意味着 ListFind 正在返回“caculo”的索引,但这应该是不可能的,因为我直接使用 strcmp .

/* Method: StringListComp
 * Parameters:
 * a - First String
 * b - Second String
 * Return value:
 * a == b
 * Description:
 * A specialization of list compare for strings. Compares the strings and returns.
 */

Bool StringListCompare (void* a, void* b) {
    return (Bool)!strcmp ( ( (String*)a)->elementArray, ( (String*)b)->elementArray);
}


/* Method: ListFind                                                                                                                                                                                         
 * Parameters:
 * list - List to search
 * element - Element to find
 * Return value:
 * Returns element if it was found and ListEnd if not.
 * Description:
 * Search list for element.
 */

uintptr_t ListFind (List* list, void* element) {
    uintptr_t i;
    for (i = 0; i < list->size; i++) {
        if ( list->ListCompare(list->elementArray[i], element) ) return i;
    }
    return ListEnd (list);
}

这怎么可能?

编辑: 我想我可能已经找到了问题所在。

当我像这样调用方法时:

    for (i = 0; i < ListSize(&workingStudent); i++) {
        score += ComputeWord (ListElement(&workingStudent, i), &dict, &words, &results, &ret);
        StringDelete ((String*)ListElement (&workingStudent, i);
    }

发生的情况是我正在删除要发送到行列表中的字符串

ListAppend(words, (void*) word);

由于 word 是一个指针,字符串被删除并且列表不知道。 这样,String 中的 char* 开始指向一个可以更改的空闲内存位置。

【问题讨论】:

  • 任何编译器警告?你试过在 valgrind 下运行吗?
  • 您是否尝试过添加一些printf 语句?检查变量的值?
  • 只需安装一个 Linux 虚拟机。访问 valgrind 是非常值得的(如果您找不到适用于 Mac 的类似工具)。
  • 还有一件事,随意添加断言。它们有双重目的,即及早捕获无效状态,并记录您的代码应该如何工作。
  • 可以使用 AddressSanatizer 和/或 MemorySanatizer 代替 Valgrind。它们是最近的 Clang 和 GCC 的一部分。

标签: c gdb initialization lldb


【解决方案1】:

发生的事情是调试器不允许更改已释放的内存,因此它使删除的单词保持新鲜。但是,对于现实世界的记忆来说,情况并非如此。 解决此问题的方法是删除删除字符串的行并将其添加到代码中:

if (wordIndex == ListEnd (words) ) { 
    ListAppend(words, (void*) word);
    wordIndex = ListSize(words) - 1;
    MatrixExpand (results, 0, ListSize(words));
//==========\/This\/==========//
} else {
    StringDelete (word);
    free (word);
    word = (String*) ListElement (words, wordIndex);
}

所以 word 在不需要时会被删除,并开始指向已经缓存的词。 当心调试器及其不必要的数据正确性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    相关资源
    最近更新 更多