C ++ - strcmp()无法正常工作?

时间:2009-12-24 20:00:04

标签: c++ strcmp

有一些非常奇怪的事情:虽然两个字符串完全相同,但strcmp()返回-1。以下是调试器输出(gdb)的片段:

(gdb) print s[i][0] == grammar->symbols_from_int[107][0]
$36 = true
(gdb) print s[i][1] == grammar->symbols_from_int[107][1]
$37 = true
(gdb) print s[i][2] == grammar->symbols_from_int[107][2]
$38 = true
(gdb) print s[i][3] == grammar->symbols_from_int[107][3]
$39 = true
(gdb) print s[i][4] == grammar->symbols_from_int[107][4]
$40 = true
(gdb) print s[i][5] == grammar->symbols_from_int[107][5]
$41 = false
(gdb) print grammar->symbols_from_int[107][4]
$42 = 0 '\0'
(gdb) print s[i]
$43 = (char * const&) @0x202dc50: 0x202d730 "Does"
(gdb) print grammar->symbols_from_int[107]
$44 = (char * const&) @0x1c9fb08: 0x1c9a062 "Does"
(gdb) print strcmp(s[i],grammar->symbols_from_int[107])
$45 = -1

知道发生了什么事吗?

提前致谢,

厄尼尔

编辑1: 以下是我的代码的一些片段:

# include <unordered_map>       // Used as hash table
# include <stdlib.h>
# include <string.h>
# include <stdio.h>
# include <vector>

using namespace std;
using std::unordered_map;
using std::hash;

struct eqstr
{
  bool operator()(const char* s1, const char* s2) const
  {
    return strcmp(s1, s2) == 0;
  }
};

...
<some other code>
...

class BPCFG {

  public:

        char *symbols;  // Character array holding all grammar symbols, with NULL seperating them.
        char *rules;    // Character array holding all rules, with NULL seperating them.

        unordered_map<char *, int , hash<char *> , eqstr> int_from_symbols; // Hash table holding the grammar symbols and their integer indices as key/value pairs.
...
<some other code>
...

vector<char *> symbols_from_int;        // Hash table holding the integer indices and their corresponding grammar symbols as key/value pairs.
void load_symbols_from_file(const char *symbols_file);
}

void BPCFG::load_symbols_from_file(const char *symbols_file) {
        char buffer[200];
        FILE *input = fopen(symbols_file, "r");
        int symbol_index = 0;
        while(fscanf(input, "%s", buffer) > 0) {
                if(buffer[0] == '/')
                        strcpy(symbols + symbol_index, buffer+1);
                else
                        strcpy(symbols + symbol_index, buffer);
                symbols_from_int.push_back(symbols + symbol_index);
                int_from_symbols[symbols+symbol_index] = symbols_from_int.size()-1;
                probs.push_back(vector<double>());
                hyperprobs.push_back(vector<double>());
                rules_from_IntPair.push_back(vector<char *>());
                symbol_index += strlen(symbols+symbol_index) + 1;
        }


        fclose(input);
}

这最后一个函数(BPCFG :: load_symbols_from_file)似乎是我在整个代码中修改symbols_from_int的唯一函数。如果您需要更多代码,请告诉我。我不会放一切,因为它有数百行。

编辑2: 好的,我想我应该从我的代码中添加一件事。这是BPCFG类的构造函数:

BPCFG(int symbols_length, int rules_length, int symbol_count, int rule_count):
   int_from_symbols(1.5*symbol_count),
   IntPair_from_rules(1.5*rule_count),
   symbol_after_dot(10*rule_count)
{
    symbols = (char *)malloc(symbols_length*sizeof(char));
    rules = (char *)malloc(rules_length*sizeof(char));
}

编辑3: 这是错误点路径上的代码。它不是可编译的,但是它显示了代码的步骤(我在调试器中检查了next和step命令,代码确实遵循了这条路径):

BPCFG my_grammar(2000, 5500, 194, 187);
my_grammar.load_symbols_from_file("random_50_1_words_symbols.txt");
<some irrelevant code>
my_grammar.load_rules_from_file("random_50_1_words_grammar.txt", true);
<some irrelevant code>
my_grammar.load_symbols_after_dots();

BPCFGParser my_parser(&my_grammar);
BPCFGParser::Sentence s;

// (Sentence is defined in the BPCFGParser class with
// typedef vector<char *> Sentence;)

Edge e;
try {
        my_parser.parse(s, e);
}
catch(char *e) {fprintf(stderr, "%s", e);}

void BPCFGParser::parse(const Sentence & s, Edge & goal_edge) {

        /* Initializing the chart */

        chart::active_sets.clear();
        chart::passive_sets.clear();
        chart::active_sets.resize(s.size());
        chart::passive_sets.resize(s.size());

        // initialize(sentence, goal);

        try {
                initialize(s, goal_edge);
        }
        catch (char *e) {
                if(strcmp(e, UNKNOWN_WORD) == 0)
                        throw e;
        }
<Does something more, but the execution does not come to this point>
}

void BPCFGParser::initialize(const Sentence & s, Edge & goal_edge) {
        // create a new chart and new agendas
        /* For now, we plan to do this during constructing the BPCFGParser object */

        // for each word w:[start,end] in the sentence
        //   discoverEdge(w:[start,end])

        Edge temp_edge;

        for(int i = 0;i < s.size();i++) {
                temp_edge.span.start = i;
                temp_edge.span.end = i+1;
                temp_edge.isActive = false;
                /* Checking whether the given word is ever seen in the training corpus */
                unordered_map<char *, int , hash<char *> , eqstr>::const_iterator it = grammar->int_from_symbols.find(s[i]);
                if(it == grammar->int_from_symbols.end())
                        throw UNKNOWN_WORD;
                <Does something more, but execution does not come to this point>
        }
}

我在调试器中运行打印命令是最后一次

throw UNKNOWN_WORD;

命令。我的意思是,我在GDB上接下来,在看到这一行后,我运行了所有这些打印命令。

感谢您的关注,
厄尼尔


好的,我想我应该从我的代码中添加一件事。这是BPCFG类的构造函数:

BPCFG(int symbols_length, int rules_length, int symbol_count, int rule_count):
   int_from_symbols(1.5*symbol_count),
   IntPair_from_rules(1.5*rule_count),
   symbol_after_dot(10*rule_count)
{
    symbols = (char *)malloc(symbols_length*sizeof(char));
    rules = (char *)malloc(rules_length*sizeof(char));
}

12 个答案:

答案 0 :(得分:10)

这听起来像s是指向堆栈上的数组的指针,一旦调用新函数就会覆盖该数组,即strcmp()

调试人员在strcmp()电话之后说的是什么?

答案 1 :(得分:3)

在最近的Linux发行版中,strcmp是STT_GNU_IFUNC类型的符号。 GDB的最新版本(撰写本文时为7.2)不支持此功能。 可能可能是您问题的原因,但在您的情况下,返回值看起来是正确的。

答案 2 :(得分:1)

鉴于GDB输出唯一可能的原因,我可以看到strcmp()被窃听。

你基本上在GDB中做了strcmp的工作:比较每个字符的字符,直到两者都是零(在4)。

你能试试print strcmp("Does", "Does");吗?


编辑:也可以尝试:

print stricmp(s[i], grammar->symbols_from_int[107], 1);
print stricmp(s[i], grammar->symbols_from_int[107], 2);
print stricmp(s[i], grammar->symbols_from_int[107], 3);
print stricmp(s[i], grammar->symbols_from_int[107], 4);
print stricmp(s[i], grammar->symbols_from_int[107], 5);

答案 3 :(得分:1)

你能解决这个问题的唯一方法是使用调试器进入strto strcmp。

答案 4 :(得分:1)

我强烈建议您在开始使用之前将内存归零。我意识到GDB输出没有任何意义,因为你确认它是一个空终止字符串,但我有很多string.h奇怪的问题消失了memset,bzero,calloc或你想要使用的任何东西。

具体来说,将构造函数和从文件读取时使用的缓冲区中的内存清零。

答案 5 :(得分:1)

正如其他人所指出的那样,strcmp几乎不可能出现问题。

最好将有问题的代码删除到重现问题所需的绝对最小值(还包括如何编译的说明 - 您正在使用哪个编译器,标志,运行时库?)。很可能您在此过程中发现错误。

如果没有,你会因为在一个最常用的C函数中找到错误而获得很多荣誉; - )

答案 6 :(得分:0)

strlen(s[i])strlen(grammar->symbols_from_int[107])会返回相同的内容吗?

另外,我无法想象这是问题所在,但是你可以使用一个常数而不是i来确保奇怪的东西不会出现吗?

答案 7 :(得分:0)

可能是两个字符串的大小不一样。

答案 8 :(得分:0)

我强烈建议首先尝试使用常规STL字符串解决问题 - 您将获得更清晰的代码和自动内存管理,因此您可以专注于解析器逻辑。只有在事物工作分析证明字符串操作是性能瓶颈后,我会更详细地查看所有使用的算法,然后是专门的字符串分配器,并且 - 作为最后的手段 - 在手册中字符数组操作,按此顺序。

答案 9 :(得分:0)

感谢所有人不遗余力地回答。我编写了自己的字符串比较函数,它在同一点上正常工作,所以很明显这是strcmp()的一个问题。尽管如此,我的代码仍然无法正常工作。但只有在我彻底分析之后,我才会请求帮助。感谢。

答案 10 :(得分:0)

将你自己的strcmp实现标记为内联,看看会发生什么......

GCC 4.3 Release Series Changes, New Features, and Fixes获取GCC 4.3.4:

“在反馈定向优化期间,发现了memcpy,memset和bzero函数操作的预期块大小,对于常用的小尺寸,会生成专用的内联代码。”

可能存在其他一些相关的错误...
尝试切换编译器优化或/和函数内联。

答案 11 :(得分:-1)

也许其中一个字符串中有一个不可打印的字符?