【问题标题】:Finding the first occurance of a specific color - weird allocation behaviour查找特定颜色的第一次出现 - 奇怪的分配行为
【发布时间】:2014-08-09 22:50:25
【问题描述】:

我正在编写一个函数,它返回具有指定颜色的第一个定位像素的地址。现在我正在测试检测。目前在 50x50 bmp。考虑到这段代码:

dword bmp_find_xy (dword xp, dword yp)                                          
{                                                                                                
    dword w = 50;
    word bpx = (3*8);
    dword offset = (2+sizeof(BMP)+sizeof(DIB));
    dword row = (((bpx * w) * 4) / 32);
    dword pixAddress = (offset) + row * yp + ((xp * bpx) / 8);

    return pixAddress;
}                                                                                                

dword bmp_dfind_c (char *FILE_NAME, BYTE R, BYTE G, BYTE B)
{
    dword w = 50;
    dword h = 50;
    dword size;

    int W, H, i;

    FILE* fp = fopen("sample.bmp", "r+b");
    BYTE* bmp;

    fseek(fp, 0L, SEEK_END);
    size = ftell(fp);
    bmp = malloc(size+48); // note this line
    rewind(fp);

    for(i=0; i<size; i++)
    bmp[i] = fgetc(fp);

    fseek(fp, 54, SEEK_SET);

    for(H = h; H >=1; H--)
    {
        for(W = 0; W < w; W++)
        {
            if(bmp[bmp_find_xy(FILE_NAME, W, H)] == 255)
            printf("There is a pix with maxed value");
        }
    }
    fclose(fp);
    return 1;
}

所以.. 因为我使用古老的编译器并且没有优化.. 如果我没有将至少 +48 的大小设置为缓冲区溢出,我会收到错误。为什么是48?如果我只输入malloc(size),为什么它会溢出,这对我来说毫无意义。

【问题讨论】:

  • size 的实际值是多少?可能是-1
  • size的实际值为7654。并且图像的大小是真正的 7654 字节。不,当然不是-1 为什么会是-1?如果这是真的.. 分配的 47 个字节就足够了。
  • dword的类型是什么。
  • @FiddlingBits dword 类型是 unsigned long
  • ftell 出错时返回 -1

标签: c memory-management allocation bmp alloc


【解决方案1】:

您的H 循环错误。如果您的图像高 100 像素,则您的循环是从 101 到 1,而不是从 99 到 0。因此,bmp_find_xy 会计算错误的索引。

尝试将循环替换为:

H = h;
while (h-- > 0) {

这种模式有时被戏称为“去操作员”。在循环中将无符号变量递减到零是一种安全的方法。

【讨论】:

  • 值得注意的是,“goes to”运算符引用来自键入不带空格的表达式时的语法:var--&gt;0。请注意将 var 指向目标值的“箭头”。 +1 提及它。 See this.
【解决方案2】:

如果我质疑你的 H 递减逻辑,请原谅我。假设您的 HW 是从零开始的(并且应该是),我相信这一点:

for(H = h; H >=1; H--)

这样会更好:

H = h;
while (H--)

如果它真的是向后枚举器H-1 的意图下降到0。 (我认为应该是)。修复我和我相当确定您可以正确分配缓冲区的问题。如所写,期望您在第 Hth 行中搜索以开始循环,而这样的行不在您的缓冲区中。

如果一个for循环是强制性的,它实际上涉及更多的工作。像这样看似无辜的事情:

for(H=(h-1); H>=0; --H)

不会作为通用机制。当h 和无符号类型以0 开头时会发生什么?表达式(h-1) 会引入下溢。哎哟。当然,您可以通过执行以下操作“解决”此问题:

if (h)
{
    for(H=(h-1); H>=0; --H)
    ....
}

但这只会让原本是个坏主意的东西变得更糟。

以下工作,但不太清楚恕我直言:

for (H=h; H--;)

这完成了与我们的while循环相同的逻辑,但以混淆为代价。它带来的一个(也是唯一一个)东西是 local-var-declaration,可能很有帮助:

for (dword var=h; var--;)

有很多方法可以做到这一点,这只是少数。我发现第一个在您的上下文中最清楚。祝你好运。

【讨论】:

  • @Edenia 很高兴为您提供帮助。它是使用后递减/递增有意义的少数几个地方之一。花一点时间在上面,它应该是清楚的。
  • 是的.. while 方法很好,因为它会递减 H 直到达到 false 即 0。使用 while 执行此操作看起来更好。
  • @Edenia 对是否继续的评估是在递减之前使用 prior 值进行的。这很重要。这意味着您可以有一个未签名的H,即0,并且循环将被跳过。当使用 for 循环(我将添加到答案中以便您稍后进行比较)时,这样的逻辑几乎没有那么干净(实际上需要不寻常的递减逻辑或特殊情况的 if-check)。
  • 为了清楚起见,我更喜欢for (H=0; H&lt;h; H++),然后索引为[h-H-1]
  • @WhozCraig 像for (dword var=h; var--;) 这样的声明在我的编译器上不起作用。它甚至不适用于 gcc .. (ANSI-C) 我认为那是众所周知的 C++ 类演员。
猜你喜欢
  • 2011-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-02
  • 2021-11-16
  • 2016-05-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多