2

根据我之前的问题(非常感谢 Jonathan Leffler),我编辑了我的代码(后两个代码块),但我遇到了一个相当奇怪的问题。

以下是不可预知的中断...

void free_array(array_info *A)
{
    int i;
    for(i = 0; i < (A->height); ++i)
    {
        printf("About to free: %x\n", A->dat_ptr[i]);//for debugging purposes
        free(A->dat_ptr[i]);
        printf("Freed row %i\n", i);//for debugging purposes
    }
    free(A->dat_ptr);
}

我最初create_array直接测试free_array,它与相当大的数组(10 ^ 8)完美配合。但是,当我在两者之间进行计算然后尝试free()使用数组时,我得到了访问冲突异常 (c00000005)。当我调试它时,我注意到如果我在“free_array”循环中有一个断点并单独执行每一行,程序每次都会完美执行。但是,编译后的代码永远不会自己运行超过我的第二个数组的第 6 行。我关闭了编译器中的所有优化,执行时仍然出现错误。

附加信息

typedef struct {
    int    height;
    int    width;
    int    bottom;//position of the bottom tube/slice boundary
    unsigned int**  dat_ptr;//a pointer to a 2d array
    } array_info;

dat_ptr现在是一个适当的 2D 指针。创建要放入结构中的数组的create_array函数是(我已经剥离了 NULL 检查的可读性):

int create_array(array_info *A)
{
int i;
unsigned int **array = malloc(sizeof(*array) * A->height);

for (i = 0; i < A->height; ++i)
{
    array[i] = malloc(sizeof(**array) * A->width);
}

A->dat_ptr = array;
return 0;
}

此功能完全按预期工作。

更多附加信息

在 Jonathan、Chris 和 rharrison33 的回复之后添加

非常感谢乔纳森,在你的每一篇文章中,我都发现了很多关于编程的知识:)我终于找到了罪魁祸首。导致异常的代码如下:

void fill_number(array_info* array,  int value,  int x1,  int y1,  int x2,  int y2)//fills a rectangular part of the array with `value`
    {
    int i, j;
    for(i=y1 ; ((i<=y2)&&(i<array->height)) ; i++)//start seeding the values by row (as in vertically)
    {
        for(j=x1 ; ((i<=x2)&&(i<array->width)) ; j++)//seed the values by columns (as in horizontally)
        {
        array->dat_ptr[i][j]=value;
        }
    }
}

并且((i<=x2)&&(i<=array->width))没有像我预期的那样被评估(克里斯多德,你是对的)。我认为它会按该顺序评估这两个条件,或者如果其中一个为“FALSE”则停止,而与它们的顺序无关。然而,事实证明它不是那样工作的,它只是拒绝(i<array->width)正确评估零件。另外,我认为它会在尝试访问数组范围之外的内存时触发异常,但事实并非如此。反正,

我将代码更改为:

void fill_number(array_info* array,  int value,  int x1,  int y1,
                                                    int x2,  int y2)
{
    int i, j;
    if(y1>=array->height){ y1=array->height-1;}
    if(y2>=array->height){ y1=array->height-1;}
    if(x1>=array->width) { x2=array->width-1;}
    if(x2>=array->width) { x2=array->width-1;}
    for(i=y1 ; i<=y2 ; i++)//start seeding the values by row
    {
        for(j=x1 ; j<=x2 ; j++)//seed the values by column
        {
        array->dat_ptr[i][j]=value;
        }
    }
}

现在它可以工作了。s块在if()那里,因为与其他代码相比,我不会经常调用该函数,并且我需要一种视觉方式来提醒我检查在那里。

再次感谢 Jonathan Leffler、Chris Dodd 和 rharrison33 :)

4

2 回答 2

2

这段代码,密切基于你从我这里得到的和你上面写的,似乎按预期工作。注意 and 的使用<inttypes.h>PRIXPTR以及转换为(uintptr_t))。它避免了对指针大小的假设,并且在 32 位和 64 位系统上同样有效(尽管这%.8意味着您在 32 位编译中获得完整的 8 位十六进制值,以及 12 个(最多 16 个)在这个特定的 64 位平台上)。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>

typedef struct
{
    int    height;
    int    width;
    int    bottom;
    unsigned int **dat_ptr;  // Double pointer, not triple pointer
} array_info;

static void create_array(array_info *A)
{
    unsigned int **array = malloc(sizeof(*array) * A->height);
    printf("array (%zu) = 0x%.8" PRIXPTR "\n",
           sizeof(*array) * A->height, (uintptr_t)array);
    for (int i = 0; i < A->height; ++i)
    {
        array[i] = malloc(sizeof(**array) * A->width);
        printf("array[%d] (%zu) = 0x%.8" PRIXPTR "\n",
               i, sizeof(**array) * A->width, (uintptr_t)array[i]);
    }
    A->dat_ptr = array;
}

static void free_array(array_info *A)
{
    int i;
    for(i = 0; i < (A->height); ++i)
    {
        printf("About to free %d: 0x%.8" PRIXPTR "\n",
               i, (uintptr_t)A->dat_ptr[i]);
        free(A->dat_ptr[i]);
    }
    printf("About to free: 0x%.8" PRIXPTR "\n", (uintptr_t)A->dat_ptr);
    free(A->dat_ptr);
}

int main(void)
{
    array_info array = { .height = 5, .width = 10, .dat_ptr = 0 };
    create_array(&array);
    if (array.dat_ptr == 0)
    {
        fprintf(stderr, "Out of memory\n");
        exit(1);
    }
    free_array(&array);
    puts("OK");
    return(0);
}

样本输出

array (40) = 0x7FAFB3C03980
array[0] (40) = 0x7FAFB3C039B0
array[1] (40) = 0x7FAFB3C039E0
array[2] (40) = 0x7FAFB3C03A10
array[3] (40) = 0x7FAFB3C03A40
array[4] (40) = 0x7FAFB3C03A70
About to free 0: 0x7FAFB3C039B0
About to free 1: 0x7FAFB3C039E0
About to free 2: 0x7FAFB3C03A10
About to free 3: 0x7FAFB3C03A40
About to free 4: 0x7FAFB3C03A70
About to free: 0x7FAFB3C03980
OK

我没有valgrind上这台机器,但是可以目测分配和释放的地址,表明那里没有明显的问题。巧合的是,我调整了数组的大小,使它们都是 40 字节(在 64 位机器上)。

后续问题

  • 你还在用你的数据做什么?
  • 您分配的数组有多大?
  • 你确定你没有遇到算术溢出吗?

在 Mac OS X 10.8.2 和 GCC/Clang 的 XCode 版本上进行测试:

i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1(基于 Apple Inc. build 5658)(LLVM build 2336.11.00)


阵列设置和打印功能

static void init_array(array_info *A)
{
    unsigned int ctr = 0;
    printf("D       = 0x%.8" PRIXPTR "\n", (uintptr_t)A->dat_ptr);
    for (int i = 0; i < A->height; i++)
    {
        printf("D[%d]    = 0x%.8" PRIXPTR "\n",i, (uintptr_t)A->dat_ptr[i]);
        for (int j = 0; j < A->width; j++)
        {
            printf("D[%d][%d] = 0x%.8" PRIXPTR " (%u)\n",
                   i, j, (uintptr_t)&A->dat_ptr[i][j], ctr);
            A->dat_ptr[i][j] = ctr;
            ctr += 7;
        }
    }
}

static void print_array(array_info *A)
{
    printf("D       = 0x%.8" PRIXPTR "\n", (uintptr_t)A->dat_ptr);
    for (int i = 0; i < A->height; i++)
    {
        printf("D[%d]    = 0x%.8" PRIXPTR "\n",i, (uintptr_t)A->dat_ptr[i]);
        for (int j = 0; j < A->width; j++)
        {
            printf("D[%d][%d] = 0x%.8" PRIXPTR " (%u)\n",
                   i, j, (uintptr_t)&A->dat_ptr[i][j], A->dat_ptr[i][j]);
        }
    }
}

成功后调用init_array(&array);,然后调用,我得到了预期的输出。在这里展示太无聊了。main()create_array()print_array(&array);

于 2012-11-05T04:05:33.610 回答
2

我相信你 malloc'ing 不正确。尝试将您的 create_array 函数修改为:

int create_array(array_info *A)
{
  int i;
  unsigned int **array = malloc(sizeof(unsigned int*) * A->height);

  for (i = 0; i < A->height; ++i)
  {
    array[i] = malloc(sizeof(unsigned int) * A->width);
  }

  A->dat_ptr = array;
  return 0;
}
于 2012-11-05T03:29:22.963 回答