Я пытаюсь получить доступ к данным через указатели и двумерные массивы, но я получаю ошибку шины, кто-нибудь знает, почему это так? - PullRequest
0 голосов
/ 09 июня 2018

Код был в основном предоставлен мне моим преподавателем.Игнорируйте функцию 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 голосов
/ 09 июня 2018

**(matr1+(i*width)+j) не имеет смысла.

alloc2Df(height, width) возвращает динамический массив m размера height.Каждый элемент m[i] является указателем на первый элемент массива float размером 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) (где 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 s справа (помечено X).

Пока все в порядке.

Однаково второй итерации внешнего цикла i равно 1.Поэтому указатели, которые мы вычисляем по matr1 + i*width + j, являются matr1 + 4 + 0, matr1 + 4 + 1, matr1 + 4 + 2 (потому что width = 4, 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]

Две вещи выделяются:

  1. matr1 + 3 никогда не вычисляется.Это, вероятно, ошибка в логике.(Если бы в нашем примере было height > width, это оставило бы «отрицательный пробел»; т. Е. Вместо пропуска элементов, он получал бы доступ к одним и тем же элементам дважды.)
  2. matr1 + 4 указывает после конца массиваналево.Фактически, все указатели matr1 + i*width + j указывают, кто знает, где, если i > 0.Я не удивлен, что взятие недопустимого указателя, разыменование его (*), затем взятие любого значения, найденного в памяти, как другого указателя и разыменование этого снова (*), вызывает сбой.

    Существует простое исправление:

    matr1[j][i]
    

    Или, если вы хотите использовать * вручную:

    *(*(matr1 + j) + i)
    

    Нет необходимости умножать что-либо.Вы не пытаетесь эмулировать доступ к двумерному массиву при наличии большого одномерного массива;у вас уже есть двухуровневая структура, в которой первый уровень содержит правильные предварительно вычисленные смещения в массиве второго уровня.

    matr1[j] (или *(matr1 + j)) - указатель на правый блок во второммассив.Применение [i] (или *(... + i)) к этому дает вам правильный элемент в чанке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...