我正试图通过指针和2D数组访问数据,但我收到了总线错误,有人知道为什么会这样吗?

时间:2018-06-09 05:11:49

标签: c pointers

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

#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; 
}

1 个答案:

答案 0 :(得分:0)

**(matr1+(i*width)+j)毫无意义。

alloc2Df(height, width)会返回大小为m的动态数组height。每个元素m[i]都是指向大小为float的{​​{1}}数组的第一个元素的指针。 (特别考虑:所有width指向同一个大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] i(外部循环的第一次迭代),我们就只是访问0(其中**(matr1 + j)来自{{} 1}}到j):

0

2会生成指向第一个数组中某个元素的指针(如左上图所示)。用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。因此,我们从i计算的指针为1matr1 + i*width + jmatr1 + 4 + 0(因为此示例中为matr1 + 4 + 1matr1 + 4 + 2

width = 4

有两件事突出:

    永远不会计算
  1. height = 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] ,这将留下一个&#34;负差距&#34 ;;即,不是跳过元素,而是两次访问相同的元素。)
  2. matr1 + 3指向左侧数组的末尾。实际上,所有指针height > width都指向了谁知道matr1 + 4。我采用无效指针,取消引用它(matr1 + i*width + j),然后将在内存中找到的任何值作为另一个指针再次解除引用(i > 0)并不会感到惊讶,导致崩溃。
  3. 有一个简单的解决方法:

    *

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

    matr1[j][i]
    

    没有必要增加任何东西。在给定大型1D阵列的情况下,您不会尝试模拟对2D阵列的访问;你所拥有的是一个两级结构,其中第一级包含第二级数组中正确的预计算偏移。

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