0

我正在尝试将模糊搜索添加到我使用 Maurice Aubrey http://aspell.net/metaphone/的 double_metaphone 的现有 C++ 实现构建的 iOS 应用程序中。我已将他的主类 double_metaphone.mm 重命名,将其设置为 File Type C++ Source 并构建项目。

但是,EXC_BAD_ACCESS在调用该DoubleMetaphone方法后出现错误。我的大多数应用程序都使用 ARC,我在 double_metaphone.mm 类中看到了许多内存管理的东西。也就是说,我最怀疑我是如何试图从该方法中得到答案的。这是 double_metaphone.h 的相关部分(根据从 Objective C 调用 C++ 方法,我将方法声明附在 extern "C" 中)。

void
DoubleMetaphone(const char *str,
            char **codes);

以下是 double_metaphone.mm 中方法实现的相关部分

void
DoubleMetaphone(const char *str, char **codes)
{
int        length;
metastring *original;
metastring *primary;
metastring *secondary;
int        current;
int        last;

current = 0;
/* we need the real length and last prior to padding */
length  = strlen(str); 
last    = length - 1; 
original = NewMetaString(str);
/* Pad original so we can index beyond end */
MetaphAdd(original, "     ");

primary = NewMetaString("");
secondary = NewMetaString("");
primary->free_string_on_destroy = 0;
secondary->free_string_on_destroy = 0;

MakeUpper(original);

/* skip these when at start of word */
if (StringAt(original, 0, 2, "GN", "KN", "PN", "WR", "PS", ""))
current += 1;

/* Initial 'X' is pronounced 'Z' e.g. 'Xavier' */
if (GetAt(original, 0) == 'X')
  {
  MetaphAdd(primary, "S");  /* 'Z' maps to 'S' */
  MetaphAdd(secondary, "S");
  current += 1;
  }

/* main loop */
while ((primary->length < 4) || (secondary->length < 4))  
  {
  if (current >= length)
      break;

  switch (GetAt(original, current))

.....

使用 if 语句为每个可能的字符提供一大堆案例,以挑选出不同的模糊编码,并在识别出主要和次要字母时添加字母。

.....

if (primary->length > 4)
SetAt(primary, 4, '\0');

if (secondary->length > 4)
SetAt(secondary, 4, '\0');

*codes = primary->str;
*++codes = secondary->str;

DestroyMetaString(original);
DestroyMetaString(primary);
DestroyMetaString(secondary);
}

最后,这是我调用此方法的代码片段。我导入 double_metaphone.h,然后在一个方法中执行以下操作:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Filtered Word";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
    Word *word = [self.fetchedResultsController objectAtIndexPath:indexPath];

    char *codes;
    NSString *wordForMetaphone = [NSString stringWithString:word.spelling];
    DoubleMetaphone([wordForMetaphone UTF8String], &codes);
    NSLog(@"doubleMetaphone code = %s", codes);

    cell.textLabel.text = word.spelling;

return cell;
}

日志消息似乎可以毫无问题地执行,但cell.textLable.text = word.spelling会触发EXC_BAD_ACCESS错误。当我单步执行代码时,我也不能 po word.spelling - 我认为 C++ 代码正在炸毁我的指针/内存。但我真的不知道从哪里开始修复它。

注意:最初我刚通过,[word.spelling UTF*String]但遇到了同样的内存问题。 word.spelling == @"a"第一次通过代码。当我注释掉我的 4 行代码时,应用程序运行良好。

我也不确定我正在设置 char *codes 并正确引用它,所以我认为这可能会导致问题 - 这不应该是主要和次要的数组吗?

我确实将 DoubleMetaphone 方法的定义从

 DoubleMetaphone(char *str, char **codes) 

由于“不推荐使用从字符串常量到 'char*' 的转换”警告,请参阅 C++ 不推荐使用从字符串常量到 'char*' 的转换。C++ 类中还有其他一些方法,我还必须切换到 const char* 我希望这不是问题的一部分?

请帮忙!

4

2 回答 2

0

你的问题是

    *++codes = secondary->str;

您将指向函数的指针传递给函数,无效指针也是如此 您可能正在覆盖恰好存储在调用函数旁边的关键内容)。char*++codescodes

如果你想返回两个东西,你可以传递两个char**参数——一个用于“primary”,一个用于“secondary”——或者你可以传递一个指向数组的指针,如下所示:

char* outputs[2] = {0, 0};
DoubleMetaphone([wordForMetaphone UTF8String], outputs);
NSLog(@"doubleMetaphone primary = %s, secondary = %s", outputs[0], outputs[1]);

...
// In DoubleMetaphone:
codes[0] = primary->str;
codes[1] = secondary->str;
于 2013-05-15T09:42:20.933 回答
0

你也可以使用我的标准 C++11 版本:double_metaphone。这应该#include直接进入.mm(Objective-C++)文件,无需任何更改,您可以使用回调版本转换std::stringNSString或自己编写。NSString

于 2014-08-22T00:44:10.637 回答