代码大部分是由我的讲师给我的。忽略free2DF函数。问题是,在外循环的第二次迭代中,发生总线错误,程序终止,但我不确定为什么。我试图将值赋给前两个矩阵,然后将它们按索引添加到第三个索引中。任何解释或帮助将不胜感激。

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

float **alloc2Df(int height, int width);
void free2DF(float **matr);

int main(void)
{
   int height = 4, width = 4, i, j;
   float **matr1, **matr2, **matr3;

   matr1 = alloc2Df(height, width);
   matr2 = alloc2Df(height, width);
   matr3 = alloc2Df(height, width);

   for(i = 0; i < width; i++)
   {
       printf("%d\n", i*width);
      for(j = 0; j < height; j++)
      {
         **(matr1+(i*width)+j) = 1;
     **(matr2+(i*width)+j) = 2;
     **(matr3+(i*width)+j) = **(matr1+(i*width)+j) + **(matr2+(i*width)+j);

     printf("%-5.1f", **(matr3+(i*width)+j));
      }

      printf("\n");
   }

   return 0;
}

float **alloc2Df( int height, int width )
{
   int i;
   int nelem;
   float *p, **pp;

   nelem = height * width;
   p = (float*)calloc( nelem, sizeof(float) );
   if( p == NULL )
      return NULL;

   pp = (float**)calloc( height, sizeof(float*) );
   if( pp == NULL )
   {
      free(p);
      return NULL;
   }

   for ( i=0; i<height; i++ )
      pp[i] = p + i*width;

   return pp;
   }

void free2Df( float **matr )
{
   if( matr != NULL ) free( (float*) *matr );
      free((float**) matr);

   return;
}

最佳答案

**(matr1+(i*width)+j)没有任何意义。

alloc2Df(height, width)返回大小为m的动态数组height。每个元素m[i]是一个指向大小为floatwidth数组的第一个元素的指针。 (特殊考虑:所有m[i]都指向同一大float数组的不同块,但这对元素访问无关紧要。)

这是显示matr1 = alloc2Df(3, 4)的图:

matr1
 |
 v
[ ]----------------------->[0.0]
[ ]--------                [0.0]
[ ]--      \               [0.0]
     \      \              [0.0]
      \      ------------->[0.0]
       \                   [0.0]
        \                  [0.0]
         \                 [0.0]
          ---------------->[0.0]
                           [0.0]
                           [0.0]
                           [0.0]


只要i0(外循环的第一个迭代),我们就在访问**(matr1 + j)(其中j02):

matr1 --------v
matr1 + 0 -->[ ]----------------------->[1.0] X
matr1 + 1 -->[ ]--------                [0.0]
matr1 + 2 -->[ ]--      \               [0.0]
                  \      \              [0.0]
                   \      ------------->[1.0] X
                    \                   [0.0]
                     \                  [0.0]
                      \                 [0.0]
                       ---------------->[1.0] X
                                        [0.0]
                                        [0.0]
                                        [0.0]


matr1 + j导致指向第一个数组中一个元素的指针(如左上方所示)。用*取消引用会给我们数组元素本身,这是另一个指针。取消引用(再次使用*)会将我们发送到右侧的float之一(标记为X)。

到目前为止一切都很好。

但是,在外循环的第二次迭代中,i1。因此,我们从matr1 + i*width + j计算的指针是matr1 + 4 + 0matr1 + 4 + 1matr1 + 4 + 2(因为在此示例中为width = 4height = 3)。

matr1 --------v
matr1 + 0 -->[ ]----------------------->[1.0]
matr1 + 1 -->[ ]--------                [0.0]
matr1 + 2 -->[ ]--      \               [0.0]
                  \      \              [0.0]
matr1 + 4 --> ?    \      ------------->[1.0]
matr1 + 5 --> ?     \                   [0.0]
matr1 + 6 --> ?      \                  [0.0]
                      \                 [0.0]
                       ---------------->[1.0]
                                        [0.0]
                                        [0.0]
                                        [0.0]


两件事脱颖而出:


matr1 + 3永远不会被计算。这可能是逻辑上的错误。 (如果我们的示例具有height > width,则将留下“负间隙”;即,不是跳过元素,而是将两次访问相同的元素。)
matr1 + 4指向左侧数组的末尾。实际上,所有指针matr1 + i*width + j都在i > 0指向who-knows-where。我对使用无效的指针,对其进行反引用(*),然后将在内存中找到的任何值用作另一个指针并再次对其进行解引用(*)导致崩溃并不感到惊讶。




有一个简单的解决方法:

matr1[j][i]


或者,如果您想手动使用*

*(*(matr1 + j) + i)


不需要乘任何东西。给定一个较大的1D数组,您并不是要模拟对2D数组的访问;您已经有了一个两层结构,其中第一层包含第二层数组中正确的预计算偏移量。

matr1[j](或*(matr1 + j))是指向第二个数组中右侧块的指针。将[i](或*(... + i))应用到该块中,将为您提供正确的元素。

07-24 20:19