Форум программистов, компьютерный форум, киберфорум
Наши страницы
C для начинающих
Войти
Регистрация
Восстановить пароль
 
-Fast
0 / 0 / 0
Регистрация: 05.06.2018
Сообщений: 13
1

Написать функцию, которая получала бы два двумерных динамических массива и возвращала бы указатель на двумерный динамиче

07.06.2018, 08:52. Просмотров 245. Ответов 12
Метки нет (Все метки)

Написать функцию, которая получала бы два двумерных динамических массива и возвращала бы указатель на двумерный динамический массив, каждый элемент которого равен сумме элементов двух исходных массивов.
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
07.06.2018, 08:52
Ответы с готовыми решениями:

Нужна функция, которая принимает два двумерных массива по очереди
Помогите с функцией,которая принимает двумерные массивы. Суть вопроса: В...

Написать и протестировать функцию, которая возвращает указатель на новый прямоугольник
Определить структуру, описывает прямоугольник со сторонами, параллельными осям...

Как написать функцию, которая бы получала на входе целочисленное число, а возвращала бы значение суммы цифр куба этого числа?
Сабж.

Написать функцию, которая бы возвращала максимум из одномерного массива
Написать функцию, которая бы возвращала максимум из одномерного массива.

Как написать функцию, которая бы принимала число, а возвращала его максимальную цифру
Всем доброго времени суток!!! Есть число типа long, например,...

12
dopleref
42 / 52 / 33
Регистрация: 15.12.2015
Сообщений: 197
07.06.2018, 11:46 2
Пример программы с реализацией функции сложения массивов:
Кликните здесь для просмотра всего текста

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <stdio.h>
 
const int N = 3;
const int M = 4;
 
void createArray(int*** array) {
    *array = (int**) malloc(N * sizeof(int*));
    for (int i = 0; i < N; i++) {
        (*array)[i] = (int*) malloc(M * sizeof(int));
        for (int j = 0; j < M; j++) {
            (*array)[i][j] = rand() % 10;
        }
    }
}
 
void printArray(int** array) {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            printf("%d ", array[i][j]);
        }
        printf("\n");
    }
}
 
int** sumArray(int** array1, int** array2) {
    int** sum;
    createArray(&sum);
 
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            sum[i][j] = array1[i][j] + array2[i][j];
        }
    }
 
    return sum;
}
 
int main() {
    srand(time(NULL));
    int** array1;
    int** array2;
    createArray(&array1);
    createArray(&array2);
    printf("array1:\n");
    printArray(array1);
    printf("array2:\n");
    printArray(array2);
 
    int** sum = sumArray(array1, array2);
    printf("sum array:\n");
    printArray(sum);
}
0
stake-k26
539 / 412 / 323
Регистрация: 25.04.2016
Сообщений: 1,194
07.06.2018, 12:57 3
dopleref, очень плохое решение. И уже не раз обсуждалось чем именно оно плохо. Функция malloc() может вернуть NULL, если по каким-то причинам память не была выделена, например, просто не достаточно свободной памяти. Однако в вашем коде по этому поводу тишина. Более того, даже если память была выделена корректно, может так случиться, что вы попросту не сможете записывать значения в выделенный блок памяти, т.е. по-хорошему бы стоит проверять еще и это.

Ну и самое главное, вы забыли освободить память! Т.е. ваша программа просто берет у компьютера память под массивы и все, после завершения программы память так и остается помеченной как занятая и не может использоваться другими программами вплоть до перезагрузки компьютера.

Ну и последний момент.. - плохая реализация функции void createArray(int*** array), если точнее, то вы создаете указатель на указатель:
int** sum;

а затем передаете указатель на указатель на указатель... в функцию createArray(&sum); Зачем? Вот зачем вам такие трудности? Складывается впечатление, что вы еще плохо понимаете как работают указатели и как с ними взаимодействовать. Сравните:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
 
int ** create_array2d (int, int);
void free_array2d (int **);
void gen_array2d (int **, int, int);
void print_arr2d (int **, int, int);
int ** sum_array2d(int**, int**, int, int);
 
int main (void)
{
    int rows, cols;
    // 1. Узнаем размеры массивов:
    printf("enter the dimensions of the array:\n");
    printf("n = ");     scanf("%d", &rows);     // строки
    printf("m = ");     scanf("%d", &cols);     // столбцы
    if (rows<1 || cols<1) exit(EXIT_FAILURE);
 
    // 2. Запрашиваем память под массивы:
    int ** a = NULL, ** b = NULL;
    if ((a = create_array2d(rows, cols)) == NULL)
    {
        printf("FAILURE! Memory allocation error!\n");
        exit(EXIT_FAILURE);
    }
    if ((b = create_array2d(rows, cols)) == NULL)
    {
        free_array2d(a);        // освобождаем память, что уже успели занять
        printf("FAILURE! Memory allocation error!\n");
        exit(EXIT_FAILURE);     // выходим из программы с ошибкой
    }
 
    // 3. Два массива созданы, заполняем случайными числами:
    srand((unsigned int) time(NULL)/2);
    gen_array2d(a, rows, cols);
    gen_array2d(b, rows, cols);
 
    // 4. Выводим оба массива на экран:
    printf("array #1:\n");
    print_arr2d(a, rows, cols);
    printf("\narray #2:\n");
    print_arr2d(b, rows, cols);
 
    // 5. И вот тут мы можем передать массивы в функцию, которая найдет сумму:
    int ** c = NULL;
    if ((c = sum_array2d(a, b, rows, cols)) == NULL)
    {
        free_array2d(a);        // освобождаем память, что уже успели занять
        free_array2d(b);
        printf("FAILURE! Memory allocation error!\n");
        exit(EXIT_FAILURE);     // выходим из программы с ошибкой
    }
 
    // 6. Выведем последний массив с суммами на экран:
    printf("\nresult array:\n");
    print_arr2d(c, rows, cols);
 
    // 7. Освобождаем занятую массивами память и выходим:
    free_array2d(a);
    free_array2d(b);
    free_array2d(c);
    exit(EXIT_SUCCESS);         // программа успешно завершилась
}
// ------------------------------------------------------------
// ----- запрашиваем память под двумерный массив m[a][b] ------
int ** create_array2d (int a, int b)
{
    int ** m = NULL;
    if ((m = (int **) malloc(a * sizeof(int*))) == NULL)
        return NULL;
    if ((m[0] = (int *) malloc(a * b * sizeof(int))) == NULL)
    {
        free(m);                // освобождаем уже занятую память
        return NULL;            // сообщаем об ошибке
    }
    size_t i;
    for (i=1; i<a; i++)
        m[i] = m[i-1] + b;
    return m;
}
// ------------------------------------------------------------
// ------ освобождаем память, занятую двумерным массивом ------
void free_array2d (int ** m)
{
    free(m[0]);
    free(m);
}
// ------------------------------------------------------------
// ------ заполняем двумерный массив случайными числами -------
void gen_array2d (int ** a, int n, int m)
{
    int i, k, z = n*m;
    for (i=0; i<n; i++)
        for (k=0; k<m; k++)
            a[i][k] = rand() %z;
}
// ------------------------------------------------------------
// -------- выводим двумерный массив a[n][m] на экран ---------
void print_arr2d (int ** a, int n, int m)
{
    int i, k;
    for (i=0; i<n; i++)
    {
        for (k=0; k<m; k++)
            printf("%4d", a[i][k]);
        printf("\n");
    }
}
// ------------------------------------------------------------
// ----- создаем двумерный массив и заполняем его суммами -----
int ** sum_array2d(int** a, int** b, int n, int m)
{
    int ** z = NULL;
    if ((z = create_array2d(n, m)) == NULL)
        return NULL;
    int i, k;
    for (i=0; i<n; i++)
        for (k=0; k<m; k++)
            z[i][k] = a[i][k] + b[i][k];
    return z;
}
проверим валгриндом:
==7149== HEAP SUMMARY:
==7149== in use at exit: 0 bytes in 0 blocks
==7149== total heap usage: 8 allocs, 8 frees, 2,432 bytes allocated
==7149==
==7149== All heap blocks were freed -- no leaks are possible
==7149==
==7149== For counts of detected and suppressed errors, rerun with: -v
==7149== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Нет занятых блоков памяти, нет утечек памяти, нет ошибок. Хотите посмотреть что выдаст проверка вашего кода?
1
dopleref
42 / 52 / 33
Регистрация: 15.12.2015
Сообщений: 197
07.06.2018, 13:45 4
stake-k26, я не стал добавлять проверки на выделение памяти, т.к. это учебная задача, Вы правы нужно добавить освобождение памяти в конце программы, хотя не все что Вы написали корректно, например:

Цитата Сообщение от stake-k26 Посмотреть сообщение
ваша программа просто берет у компьютера память под массивы и все, после завершения программы память так и остается помеченной как занятая и не может использоваться другими программами вплоть до перезагрузки компьютера.
- это неверно, т.к. при завершении программы вся выделенная в ней память будет
возвращена операционной системе

Цитата Сообщение от stake-k26 Посмотреть сообщение
а затем передаете указатель на указатель на указатель... в функцию createArray(&sum); Зачем? Вот зачем вам такие трудности? Складывается впечатление, что вы еще плохо понимаете как работают указатели и как с ними взаимодействовать
- где тут проявляется плохое понимание указателей? в чем оказался трудным мой код, если Вы что то не до поняли, можете задать вопрос.

Вы и в правду думаете что Ваш пример удачен и понятен для автора темы?

Добавлено через 16 минут
stake-k26, посмотрел Ваш код, спасибо за новый для меня способ выделения памяти, под динамические массивы.
0
stake-k26
539 / 412 / 323
Регистрация: 25.04.2016
Сообщений: 1,194
07.06.2018, 14:35 5
Цитата Сообщение от dopleref Посмотреть сообщение
при завершении программы вся выделенная в ней память будет
возвращена операционной системе
Верно, память занятая указателями будет возвращена операционной системе, но если во время работы программы вы запросили блок памяти, привязали его к указателю и забыли освободить, то память занятая самим указателем будет освобождена, а вот блок памяти так и останется занятым, просто он ни к чему не будет привязан. Т.е. память, выделенная под указатель будет возвращена, с этим никто не спорит.

фактически получается следующее:

C
1
2
3
4
5
int * a = NULL;
a = (int *) malloc (5* sizeof(int));
/* здесь мы что-то делаем с получившимся массивом */
// выходим из программы:
a = NULL;
А что по-вашему случилось с тем блоком, который мы запросили через malloc? Да, мы сбросили указатель, он больше никуда не указывает и выделенная для его хранения память вернулась в кучу. Но что с занятым блоком памяти, на который ссылался наш указатель? Он так и никуда и не делся и остался занят.

Конечно, вы можете мне не верить - это ваше право. Давайте в ассемблер не полезем, а просто посмотрим на вывод valgrind:
in use at exit: 0 bytes in 0 blocks
Зачем нужно сообщать сколько памяти используется при выходе из программы? Мы же уже вышли и память была освобождена... или все-таки нет?

Цитата Сообщение от dopleref Посмотреть сообщение
Вы и в правду думаете что Ваш пример удачен и понятен для автора темы?
Понятен? Я сильно сомневаюсь, что ТС вообще стоит браться за динамическую память, если он еще с указателями не разобрался.

Удачен? ... вы всегда пишете код, полагаясь на удачу? Что-то вроде, я сейчас что-нибудь напишу, а потом буду молиться, что оно будет работать, ну хоть как-то..

А если серьезно, я считаю, что в нем почти полностью исключены возможные ошибки, не уверен на счет удачен, я бы скорее сказал надежен.
0
dopleref
07.06.2018, 14:48
  #6

Не по теме:


Цитата Сообщение от stake-k26 Посмотреть сообщение
вы всегда пишете код, полагаясь на удачу?
это технический форум, ни к чему пускаться в инсинуации, фраза была вполне однозначна

Цитата Сообщение от stake-k26 Посмотреть сообщение
Понятен? Я сильно сомневаюсь, что ТС вообще стоит браться за динамическую память, если он еще с указателями не разобрался.
- я полагаю что это раздел форума предназначен чтобы помогать начинающим программистам си,
а не для поднятия собственного ЧСВ

0
stake-k26
07.06.2018, 15:17
  #7

Не по теме:

Цитата Сообщение от dopleref Посмотреть сообщение
ни к чему пускаться в инсинуации
dopleref, извините, если я вас задел.

У меня ЧСВ и без того зашкаливает, так что не вижу нужды его еще выше поднимать. :) Однако, в данном случае по числу тем, созданных ТС, которые касаются динамической памяти, я прихожу к выводу, что вопросы не на пустом месте возникают, а значит ТС чего-то не понимает. Однако он ни разу не попросил ему что-то объяснить и все его посты выглядят как: "Я вообще ничего не знаю, сделайте за меня".

Все еще считаете что моя оценка не достаточно объективна и я просто ЧСВ поднимаю? Ваше право. :)

0
COKPOWEHEU
1205 / 860 / 201
Регистрация: 09.09.2017
Сообщений: 3,686
07.06.2018, 19:29 8
Цитата Сообщение от stake-k26 Посмотреть сообщение
А что по-вашему случилось с тем блоком, который мы запросили через malloc?
Насколько мне известно, в большинстве (не утверждаю что во всех!) операционных системах есть два механизма распределения памяти: на уровне ОС память каждому приложению выделяется крупными блоками. Потом внутри приложения есть собственный менеджер памяти, в пределах которого работает malloc. Он выделяет в блоках памяти, выданных ОСью участки памяти конкретного размера плюс служебную информацию, и их-то и возвращает приложению, либо "освобождает" при вызове free. Причем освобожденная память возвращается операционке не всегда. Некоторые компиляторы считают, что память стоит придержать на будущее.
При завершении процесса ОС помечает блоки памяти, которые она выделяла приложению, как свободные. То же самое происходит с идентификаторами файлов и прочих ресурсов.
Таким образом в учебных задачах об этом можно не беспокоиться: если память не может быть выделена, приложение просто упадет. Если память не будет освобождена добровольно, ее отберут принудительно при завершении.
Однако, если не привыкать (и не приучать) всегда прибираться за собой - освобождать память, закрывать файлы - в учебных программах, то и в рабочих подобные ошибки будут время от времени возникать, а там сбои куда критичнее. К тому же не стоит забывать о багах в операционных системах. Недавно читал статью, как многократное выделение-освобождение памяти приводило к сбоям и утечкам. Также не стоит забывать, что все эти меры безопасности - добрая воля операционной системы, защита чтобы одно приложение не повредило остальным. Никто не заставляет все операционные системы вести себя так же.
Цитата Сообщение от dopleref Посмотреть сообщение
void createArray(int*** array)
Это попытка имитации двумерного динамического массива через указатель на массив массивов? Не лучшая идея.
0
dopleref
42 / 52 / 33
Регистрация: 15.12.2015
Сообщений: 197
08.06.2018, 06:47 9

Не по теме:


Цитата Сообщение от stake-k26 Посмотреть сообщение
посты выглядят как: "Я вообще ничего не знаю, сделайте за меня".
- да это к сожалению не очень приятный подход, хочется, что бы авторы тем, пытались в начале сделать что то сами, а потом показывали наработки в своем вопросе



COKPOWEHEU, Спасибо за подробное разъяснение вопроса.

Не по теме:


Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Не лучшая идея.
так себе оценка кода, я не сомневаюсь что у Вас были какие то агрументы что бы написать это, но лучше было их привести чтобы не быть голословным.

0
COKPOWEHEU
1205 / 860 / 201
Регистрация: 09.09.2017
Сообщений: 3,686
08.06.2018, 08:07 10
Цитата Сообщение от dopleref Посмотреть сообщение
так себе оценка кода, я не сомневаюсь что у Вас были какие то агрументы что бы написать это, но лучше было их привести чтобы не быть голословным.
Я надеюсь, та имитация двумерного массива не единственный способ, который вы знаете. Потому что более правильно это делается так (привожу примеры без функций, только инициализация, доступ, удаление):
C
1
2
3
4
5
6
7
8
#define elem2(arr, i, j) arr[i + j*(arr ## _w)]
int arr_w=5, arr_h=5;
int *arr = (int*)malloc(sizeof(int) * arr_w * arr_h);
if(arr == NULL)error();
 
elem2(arr, 2, 2)=1;
 
free(arr);
Другой способ - имитация двумерного массива через массив массивов (ваш способ):
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int arr_w=5, arr_h=5;
  int **arr = (int**)malloc(sizeof(int*) * arr_w);
  if(arr == NULL)error();
  for(int i=0; i<arr_w; i++){
    arr[i] = (int*)malloc(sizeof(int)*arr_h);
    if(arr[i] == NULL){
      for(int j=0; j<i; j++)free(arr[j]);
      free(arr);
      error();
    }
  }
 
  arr[2][2]=1;
 
  for(int i=0; i<arr_w; i++)free(arr[i]);
  free(arr);
И недавно увидел компромиссный вариант, предложенный stake-k26:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  int arr_w = 5, arr_h = 7;
  int **arr = (int**)malloc(arr_w * sizeof(int*));
  if(arr == NULL)error();
  arr[0] = (int*) malloc(arr_w * arr_h * sizeof(int));
  if(arr[0] == NULL){
    free(arr);
    error();
  }
  for(int i=1; i < arr_w; i++) arr[i] = arr[i-1] + arr_h;
  
  arr[2][3] = 4;
  
  free(arr[0]);
  free(arr);
(при подгонке всех вариантов под единый стиль мог допустить опечатки)
Лично мне больше всего нравится первые вариант - реализация двумерного массива как отображение на одномерный, тем более что статические двумерные массивы внутри устроены точно так же. Плюс этот вариант действительно является единым массивом, его можно безболезненно копировать через memcpy, например. Ну и у него нет накладных расходов.
Еще интересен третий вариант. Он чуть сложнее в инициализации, зато проще в использовании. Он также является единым массивом, точнее, двумя массивами, и это надо помнить при копировании. Еще одна проблема - для многомерных массивов инициализация приближается по сложности к варианту 2.
Ну а вариант 2 наименее удачный. Фактически это даже не единственный массив, а куча массивов, собранных еще одним массивом вместе. Несмотря на то что он выглядит как двумерный массив, применять к нему memcpy было бы не лучшей идеей. Ну и объем инициализации / освобождения с учетом контроля ошибок видно невооруженным глазом (сначала хотел ради демонстрации обойтись без него, но не зря же столько времени распинался про учебные цели и все такое!).
1
dopleref
42 / 52 / 33
Регистрация: 15.12.2015
Сообщений: 197
08.06.2018, 08:42 11
COKPOWEHEU, спасибо, теперь я кажется начал въезжать в тему))

Не по теме:

ТС по любому в ужасе от всего нашего обсуждения:jokingly:



Добавлено через 13 минут
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
#define elem2(arr, i, j) arr[i + j*(arr ## _w)]
сижу думаю над макросом, не могу понять почему не:
C
1
#define elem2(arr, i, j) arr[i + j*(arr_w)]
?
0
COKPOWEHEU
1205 / 860 / 201
Регистрация: 09.09.2017
Сообщений: 3,686
08.06.2018, 10:11 12
Цитата Сообщение от dopleref Посмотреть сообщение
сижу думаю над макросом, не могу понять почему не:
Чтобы не привязывать макрос к конкретному массиву:
C
1
2
3
4
5
6
7
8
9
float src_w, src_h, *src;
float matrix_w, matrix_h, *matrix;
float dst_w, dst_h, *dst;
...
memset(dst, 0, sizeof(float) * dst_w * dst_h);
for(int i=0; i<dst_w; i++)
  for(int j=0; j<dst_w; j++)
    for(int k=0; k<dst_w; k++)
      elem2(dst, i, j) += elem2(src, i, k) * elem2(matrix, k, j);
Это пример перемножения квадратных матриц (ширина считается равной высоте, и они у всех матриц одинаковые).
1
dopleref
42 / 52 / 33
Регистрация: 15.12.2015
Сообщений: 197
08.06.2018, 11:29 13
COKPOWEHEU, круто!
0
08.06.2018, 11:29
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
08.06.2018, 11:29

Два двумерных массива объединить в один двумерный
Даны два двумерных массива LL; PER; Нужно их объединить в один Mas чтобы...

Как сделать функцию, возвращающую указатель на функцию (которая в свою очередь возвращает указатель на массив)
Изучаю c++ по одной книжке.Она говорить не умеет.. Так вот понадобилось...

Как правильно описать функцию чтобы возвращала двумерный vector
Как правильно написать чтобы результат передался в vec1? #include &lt;iostream&gt;...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru