从 dll 调用函数时分配大小无效

Posted

技术标签:

【中文标题】从 dll 调用函数时分配大小无效【英文标题】:Invalid allocation size when calling a function from dll 【发布时间】:2015-03-21 18:15:32 【问题描述】:

我刚开始使用dll,但之前没有遇到过这个问题,所以可能没有连接dll。我在 c++ 中实现了 KMP 字符串匹配算法,我使用 dll 从 c# 调用它。

这是我的出口:

extern "C" __declspec (dllexport) const char* naive(const char* text, const   char* str);
extern "C" __declspec (dllexport) const char* KMP(const char* text, const char* str);

我的导入:

 [DllImport(@"dll_path", CallingConvention = CallingConvention.Cdecl)]
 public static extern IntPtr KMP([MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string str);

从 c# 调用

  string output = Marshal.PtrToStringAnsi(KMP(richTextBox1.Text, richTextBox2.Text));

还有c++函数:

const char* KMP(const char* text, const char* str)

    int tL = strlen(text);
    int sL = strlen(str);
    /* Algorithm */
 

在调用函数后立即引发异常。所以我认为这不是代码实现。有线的事情是它只在第二个参数 (str) 中有一个 '\n' 新行时抛出,无论具体在哪里。如果没有新行,它会正常运行。最让我困惑的是为什么只有第二个参数,两者都被相同地声明和使用。我也实现了 Naive 算法,同样的故事。

我找到的所有答案都是只有当一个负数作为数组或未声明变量的大小给出时,但指针上没有。但我怀疑它是否相似,因为当我的搜索字符串(第二个参数(str))不包含新行时,代码会正常执行。

有什么想法吗?

谢谢你。

编辑(函数体):

const char* KMP(const char* text, const char* str)

    int tL = strlen(text);
    int sL = strlen(str);
    string match = "";

    if (sL == 0 || tL == 0)
        throw "both text and string must be larger than 0";
    else if (sL > tL)
        throw "the text must be longer than the string";

    int tI = 0;
    int col = 0, row = 0;

    while (tI <= tL - sL)
    
        int i = 0;
        int tmpCol = -1;
        int next = 1;
        for (; i <= sL && text[i + tI] != '\0'; i++)
        
            if (text[i + tI] == '\n')
            
                row++;
                tmpCol++;
            
            if (text[i + tI] == str[0] && next == 1 && i > 0)
                next = i;

            if (text[i + tI] != str[i])
                break;
        
        if (i == sL)
        
            match += to_string(row) + ',' + to_string(col) + ';';
        

        tI += next;

        col = tmpCol > -1 ? tmpCol : col + next;
    
    char* c = new char[match.length() - 1];
    c[match.length() - 1] = '\0';
    for (int i = 0; i < match.length() - 1; i++)
        c[i] = match[i];
    return c;

【问题讨论】:

IntPtr 和分配是我们教授建议的,因为我们刚开始使用dll,并被告知字符串数组会导致很多问题,最好使用这个“模板”。释放..我完全忘记了我有一段时间没有使用过 c++ 了。分配是这个char* c = new char[match.length() - 1]; 为什么是 const char*/IntPtr 返回类型?该算法不应该返回字符串中的索引(int)吗? KMP yes, mu 函数返回所有找到的匹配行和列索引。 当它真的依赖于输入中的\n 时,C++ 代码中存在某种错误。由于多余/缺少\r,您可能正在缓冲区外写入​​。 @veili_13 您是否尝试过使用完全存根方法(如... return "adfadsf";)?只是为了绝对确定这是编组问题。 【参考方案1】:

只需更改您的代码以处理不匹配的情况,因为运行时无法分配 0-1 = 0xFFFFFFFFF 字节。现在我还更改了您的复制缓冲区分配和循环代码以避免覆盖(@HenkHoltermann 指出):

...
if (match.length() == 0)
    return "No matches";

// Allocate for all chars + \0 except the last semicolon
char* c = new char[match.length()];
c[match.length() - 1] = '\0';

// Copy all chars except the last semicolon
for (int i = 0; i < match.length() - 1; i++)
    c[i] = match[i];

return c;

!它仍然不会复制最后一个分号,所以如果你需要它,那么你必须在缓冲区中再添加一个符号。


P.S.:我还发现您的代码存在一些问题:

    您使用了 C++ 异常。虽然 CLR 会将它们捕获为 SEH(因为 VC++ 使用 SEH)但总体上仍然不是一个好主意 - Throwing C++ exceptions across DLL boundaries 您使用有符号的int 作为长度int tL = strlen(text);strlen 返回无符号的size_t。这可能不是一个实际问题,但也不是正确的方法。

【讨论】:

danm...我必须监督...因为我认为我的输入匹配...似乎不匹配。非常感谢您解决了它。 在我的辩护中,我正在测试 word\n 并且它不是一个匹配项(正如我所想的那样),因为它是 word \n xD。无论如何,非常感谢! 谢谢你的提示,我会继续的。再次感谢。 @veili_13 永远不要相信输入。对不起喊了。还要尝试为您的变量使用更有意义的名称 - Intellisense 无论如何都可以节省大量输入,所以为什么不利用这样的好处来创建更容易理解的程序。空行也有帮助。祝你好运。 在@HenkHolterman 指出之后,我已经修复了覆盖。我知道我的代码有点乱,变量似乎完全出乎意料,我的时间有点短,所以它们只是首字母(tI = 文本迭代器,tL = 文本长度),但我想问一些问题否则,它一直在困扰我(双关语不是故意的),你知道为什么如果断点在string match = "" 之前的任何一行,我的调试不会继续,但是会抛出错误,不是吗?抛出char* c = new char[match.length() - 1]; IF 没有匹配并且之前没有匹配?

以上是关于从 dll 调用函数时分配大小无效的主要内容,如果未能解决你的问题,请参考以下文章

022.强化训练三

从 DLL 函数调用非 DLL 函数

从 Dll 调用具有偏移地址的成员函数

从 C++ 调用 dll 函数

从 MS 访问调用 dll 函数

从 C++ 调用 DLL 中的函数