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

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

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

Написать функцию, которая получала бы два двумерных динамических массива и возвращала бы указатель на двумерный динамический массив, каждый элемент которого равен сумме элементов двух исходных массивов.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
07.06.2018, 08:52
Ответы с готовыми решениями:

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

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

Поэлементно просуммировать два динамических двумерных массива
Здравствуйте, у меня такое задание: Написать программу, которая поэлементно суммирует два...

Есть два двумерных целочисленных динамических массива
Здравствуйте, хочу реализовать задачу, сравнить два двумерных целочисленных динамических массива,...

12
42 / 52 / 33
Регистрация: 15.12.2015
Сообщений: 199
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
1075 / 647 / 451
Регистрация: 25.04.2016
Сообщений: 1,794
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
42 / 52 / 33
Регистрация: 15.12.2015
Сообщений: 199
07.06.2018, 13:45 4
stake-k26, я не стал добавлять проверки на выделение памяти, т.к. это учебная задача, Вы правы нужно добавить освобождение памяти в конце программы, хотя не все что Вы написали корректно, например:

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

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

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

Добавлено через 16 минут
stake-k26, посмотрел Ваш код, спасибо за новый для меня способ выделения памяти, под динамические массивы.
0
1075 / 647 / 451
Регистрация: 25.04.2016
Сообщений: 1,794
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
2548 / 1518 / 333
Регистрация: 09.09.2017
Сообщений: 5,987
07.06.2018, 19:29 8
Цитата Сообщение от stake-k26 Посмотреть сообщение
А что по-вашему случилось с тем блоком, который мы запросили через malloc?
Насколько мне известно, в большинстве (не утверждаю что во всех!) операционных системах есть два механизма распределения памяти: на уровне ОС память каждому приложению выделяется крупными блоками. Потом внутри приложения есть собственный менеджер памяти, в пределах которого работает malloc. Он выделяет в блоках памяти, выданных ОСью участки памяти конкретного размера плюс служебную информацию, и их-то и возвращает приложению, либо "освобождает" при вызове free. Причем освобожденная память возвращается операционке не всегда. Некоторые компиляторы считают, что память стоит придержать на будущее.
При завершении процесса ОС помечает блоки памяти, которые она выделяла приложению, как свободные. То же самое происходит с идентификаторами файлов и прочих ресурсов.
Таким образом в учебных задачах об этом можно не беспокоиться: если память не может быть выделена, приложение просто упадет. Если память не будет освобождена добровольно, ее отберут принудительно при завершении.
Однако, если не привыкать (и не приучать) всегда прибираться за собой - освобождать память, закрывать файлы - в учебных программах, то и в рабочих подобные ошибки будут время от времени возникать, а там сбои куда критичнее. К тому же не стоит забывать о багах в операционных системах. Недавно читал статью, как многократное выделение-освобождение памяти приводило к сбоям и утечкам. Также не стоит забывать, что все эти меры безопасности - добрая воля операционной системы, защита чтобы одно приложение не повредило остальным. Никто не заставляет все операционные системы вести себя так же.
Цитата Сообщение от dopleref Посмотреть сообщение
void createArray(int*** array)
Это попытка имитации двумерного динамического массива через указатель на массив массивов? Не лучшая идея.
0
42 / 52 / 33
Регистрация: 15.12.2015
Сообщений: 199
08.06.2018, 06:47 9

Не по теме:


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



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

Не по теме:


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

0
2548 / 1518 / 333
Регистрация: 09.09.2017
Сообщений: 5,987
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
42 / 52 / 33
Регистрация: 15.12.2015
Сообщений: 199
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
2548 / 1518 / 333
Регистрация: 09.09.2017
Сообщений: 5,987
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
42 / 52 / 33
Регистрация: 15.12.2015
Сообщений: 199
08.06.2018, 11:29 13
COKPOWEHEU, круто!
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
08.06.2018, 11:29

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

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

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

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

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

Foreach Два двумерных массива объединить в один двумерный
У меня есть 1 массив из всеми данными array(2) { =&gt; array(7) { =&gt; string(1) &quot;3&quot; ...

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


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

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

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