Форум программистов, компьютерный форум, киберфорум
C/С++ под Linux
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.72/18: Рейтинг темы: голосов - 18, средняя оценка - 4.72
0 / 0 / 0
Регистрация: 17.12.2015
Сообщений: 14

Передача трёхмерного массива в pthread_create

16.05.2017, 18:47. Показов 3631. Ответов 17
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Решить задачу с помощью нескольких потоков. Каждый поток должен вывести свой
идентификатор и отработать заданное время. Массивы заполняются с помощью функции
random().
Имеется 10 массивов данных (размера >100). Требуется посчитать количество
четных и нечётных элементов в каждой строке массива. Каждая строчка в отдельном
потоке.
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
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
 
void generate (int ***array){ /*функция для заполнения и вывода массива*/
        for (int i=0; i<10; i++){
                for(int j=0; j<3; j++){
                        for(int k=0; k<11; k++){
                                array[i][j][k]=rand()%100;
                        }
                }
        }
        for (int i=0; i<10; i++){
                for(int j=0; j<3; j++){
                        for(int k=0; k<11; k++){
                                printf("%d ", array[i][j][k]);
                        }
                        printf("\n");
                }
                printf("\n\n\n");
        }
 
}
 
void programm(int ***array){ /*считаем чётные и нечётные элементы в каждой строке*/
    int chet=0, nechet=0;
    for (int i=0; i<10; i++){
        for (int j=0; j<3; j++){
            for (int k=0; k<11; k++){
                if (array[i][j][k]%2==0)
                            chet++;
                        else if(array[i][j][k]%2==1)
                                nechet++;
                }
                printf("chet:%d         nechet:%d\n\n", chet, nechet);
                chet=0;
                nechet=0;
        }
    }
}
 
void* pthread(void ***varray){ /*потоковая функция*/
    int ***array= (int***) varray;
    generate(array);
    programm(array);
}
 
int main (){
    int max=10;
    pthread_t pt[max];
    int arr[max][10][11]; /*10 массивов по 10 строк по 11 символов*/
    for (int i=0; i<max; i++){
        pthread_create(pt, NULL, pthread, (void*) arr[i]);
        pthread_join(pt[i], NULL);
    }
}
Проблема с передачей в pthread_create 4 аргумента, выводит варнинг "passing argument 3 of 'pthread_create' from incompatible pointer type"
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
16.05.2017, 18:47
Ответы с готовыми решениями:

Передача нескольких параметров в pthread_create (передача структуры)
Здравствуйте. Мне нужно передать последним параметром в функцию pthread_create следующую структуру struct data { float a; ...

Передача трёхмерного массива в функцию
Необходимо передать СТАТИЧЕСКИЙ трёхмерный массива в функцию Почему-то на funct (int*** iArray) компилятор ругается. Может быть потому...

Передача трехмерного динамического массива в функцию
У меня почему то ошибка : Использована неинициализированная локальная переменная &quot;array&quot; .Можете исправить проблему ? ...

17
Почетный модератор
 Аватар для Humanoid
11555 / 4350 / 452
Регистрация: 12.06.2008
Сообщений: 12,454
21.05.2017, 21:22
Цитата Сообщение от oksparad Посмотреть сообщение
void* pthread(void ***varray){ /*потоковая функция*/
int ***array= (int***) varray;
Попробуйте заменить на
C
1
2
void* pthread(void *varray){ /*потоковая функция*/
    int ***array= (int***) varray;
Добавлено через 20 минут
Кстати, при создании потока вы всегда перетираете один и тот же дескриптор, т.к. в вызове pthread_create() указываете pt без индекса.
0
0 / 0 / 0
Регистрация: 17.12.2015
Сообщений: 14
22.05.2017, 20:11  [ТС]
Humanoid, проблему с указателями в потоковой функции я уже решила, но всё равно спасибо) А при указании pt с индексом выводит варнинг "passing argument 1 of 'pthread_create' makes pointer from integer without a cast".
0
Почетный модератор
 Аватар для Humanoid
11555 / 4350 / 452
Регистрация: 12.06.2008
Сообщений: 12,454
22.05.2017, 23:15
C
1
pthread_create(&pt[i], ....
0
0 / 0 / 0
Регистрация: 17.12.2015
Сообщений: 14
23.05.2017, 20:44  [ТС]
Humanoid, не сочти за наглость, но можешь ещё хотя бы на мысль натолкнуть, от чего может быть здесь ошибка сегментирования)
0
Почетный модератор
 Аватар для Humanoid
11555 / 4350 / 452
Регистрация: 12.06.2008
Сообщений: 12,454
24.05.2017, 20:57
Так вы же при создании передаёте потоку указатель на arr[i]... т.е. в поток уже передаётся двумерный массив. Но в самом потоке вы работаете с ним как с трёхмерным.
1
0 / 0 / 0
Регистрация: 17.12.2015
Сообщений: 14
07.06.2017, 18:37  [ТС]
Humanoid, спасибо большое, очень помогли
0
1 / 1 / 0
Регистрация: 25.02.2021
Сообщений: 5
25.02.2021, 19:40
Здравствуйте. Вы бы не могли пожалуйста написать как вы решили проблему с ошибкой сегментации?
0
13 / 13 / 0
Регистрация: 21.10.2011
Сообщений: 58
26.02.2021, 18:10
Боюсь девушка решает уже совсем другие задачи и она вам уже не ответит

Ошибка сегментации возникает, если разименовать пустой или не проинициализированный указатель. Возможно произошло обращение за пределы массива. Понять что случилось можно с помощью отладчика gdb. Если интересно как это сделать, скажите.

Что касается данной конкретной реализации, то она плохая. Во-первых в коде полно неименованных констант. Во-вторых, очень сомнительно использование pthread_join после создания потока. Это все-равно что запускать код последовательно
1
1 / 1 / 0
Регистрация: 25.02.2021
Сообщений: 5
26.02.2021, 20:55
Огромное спасибо за ответ. Я совсем нуб в си. У меня похожее задание по контрольной и я искал рабочий пример применения библиотеки pthread для обработки трехмерного массива, чтобы попытаться выполнить свою задачу по примеру. Поэтому я был бы крайне признателен просто за рабочий код, который выполняет данную задачу, чтобы на его примере я смог разобраться со своей задачей. Если вам не сложно внести необходимые корректировки в представленный в теме код, чтобы снять ошибку сегментирования и заставить его работать, то это было бы для меня очень полезно, так как я сам не обладаю для этого достаточными знаниями.
0
13 / 13 / 0
Регистрация: 21.10.2011
Сообщений: 58
26.02.2021, 22:48
Я тут набросал небольшой пример, дальше попробуй сам.

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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h> /* for bool type */
#include <getopt.h> /* for options support */
#include <pthread.h> /* for pthreads support */
#include <unistd.h> /* for sleep */
 
/* название программы */
#define PROGNAME "threads2"
/* версия программы */
#define VERSION "0.1"
 
int debug;
int errcode = 0; /* код ошибки */
pthread_t tid[100]; /* максимальное количество потоков */
int tcount;
 
int done; /* эта переменная отвечает за то, чтобы главный поток завершился, когда все дочерние потоки отработают */
 
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; /* если потребуется синхронизировать потоки, потребуется это */
 
void *thr_fn(void *arg) {
    int (*aaa)[3][3] = (int (*)[3][3])arg; /* это локализация переменной, чтобы можно было пользоваться как трехмерным массивом */
 
    int i, j, k;
 
    //pthread_mutex_lock(&lock); /* раскомментируй это, если нужно, чтобы потоки друг другу не мешали */
 
        /* тут будут твои вычисления */
        /* это пример */
 
    for (i = 0; i < 3; i++) {
        for (j = 0; j < 3; j++) {
            for (k = 0; k < 3; k++) {
                printf("%d ", aaa[i][j][k]);
            }
            printf("\n");
        }
        printf("\n");
    }
 
    done--;
 
    //pthread_mutex_unlock(&lock);  /* раскомментируй это, если нужно, чтобы потоки друг другу не мешали */
 
        /* поток обязательно должен вернуть указатель. Возвращаем 0 */
    return (void *)0;
}
 
/* функция для распечатки трехмерного массива, для отладки */
void print_aaa(int aaa[3][3][3]) {
    int i, j, k;
 
    i = j = k = 3;
 
    for (i = 0; i < 3; i++) {
        for (j = 0; j < 3; j++) {
            for (k = 0; k < 3; k++) {
                printf("%d ", aaa[i][j][k]);
            }
            printf("\n");
        }
        printf("\n");
    }
}
 
/* вызываем эту функцию, если пользователь ввел некорректные параметры */
void usage(const char * const name)
{
        printf("usage:\n%s [options]\n", name);
        printf("options:\n");
    printf("  --help\t\t\tThis help.\n");
        printf("  -d, --debug\t\t\tPrint lots of debugging information.\n");
        printf("  -V, --version \t\tPrint program version.\n");
}
 
/* наша любимая главная функция, она же точка входа */
int main(int argc, char *argv[])
{
        /* опции, которые принимает программа */
        static struct option long_options[] = {
                {"help", 0, 0, '?'},  /* показать помощь */
                {"debug", 0, 0, 'd'}, /* инициализировать отладку */
                {"version", 0, 0, 'V'}, /* показать версию и выйти */
                {0, 0, 0, 0} /* последняя опция должна быть с нулями */
        };
 
        /* ниже идет штука, которая считывает опции */
        int c, index = 0;
        while((c = getopt_long(argc, argv, "hdV", long_options, &index)) != -1) {
                switch(c) {
        case 'd':
                        debug = true;
                        break;
 
                case ':':
                        printf("Option -%c requires an operand\n", optopt);
                        usage(argv[0]);
                        errcode = -1;
                        goto exit;
 
                case 'V':
                        printf("%s %s\n", PROGNAME, VERSION);
                        printf("Copyright (C) 2010 fish9370");
                        printf("This is free software; see the source for copying conditions.  There is NO\n");
                        printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
                        goto exit;
 
                case '?':
                        /*printf("Unrecognized option: -%c\n", optopt);*/
                        usage(argv[0]);
                        goto exit;
                }
 
    }
 
        /* итак, опции получены, можно запускать полезный код */
 
        /* объявим трехмерный массив и статически инициализируем его */
    int aaa[3][3][3] = {
        {{1,2,3}, {1,2,3}, {1,2,3}},
        {{1,2,3}, {1,2,3}, {1,2,3}},
        {{1,2,3}, {1,2,3}, {1,2,3}},
    };
 
        /* если пользователь ввел опцию -d, распечатаем наш массив */
        if (debug)
            print_aaa(aaa);
 
        /* по умолчанию счетчик done равен нулю, что говорит, не один поток не запущен, можно выходить */
    done = 0;
 
        /* поехали, создаем 10 потоков */
    for (tcount = 0; tcount < 10; tcount++) {
                /* увеличиваем счетчик done, чтобы этот поток нужно было подождать */
        done++;
 
                /* создаем новый поток, он тут же запустит функцию thr_fn и передаст ей наш массив aaa */
        pthread_create(&tid[tcount], NULL, thr_fn, (void *)&aaa);
    }
 
        /* ожидаем пока счетчик done не уменьшится до нуля. Это случится, когда все потоки отработают */
    while(done > 0) {
                /* вставим небольшую задержку, чтобы не грузить процессор в холостую */
                usleep(100);
        }
 
exit:
    return errcode;
}
Откомпилировать это можно примерно так:
C
1
gcc -O0 -g3 -p -ggdb -Wall -pthread threads2.c -o threads2
где: -O0 выключает оптимизацию, -p, -g3 и -ggdb добавляет отладочную информацию, -Wall предупреждать о чем-то нехорошем, -pthread слинковать с библиотекой pthread, -o имя файла после компиляции
1
1 / 1 / 0
Регистрация: 25.02.2021
Сообщений: 5
27.02.2021, 02:45
Огромное спасибо. Очень красиво написан код. Просто приятно даже посмотреть как составлен. Буду разбираться теперь в нём.

Добавлено через 1 час 14 минут
Ваш код работает идеально со статическим массивом. Но у меня, насколько я понимаю, возникла та же проблема, что и у изначального автора топика. Я пытаюсь передать в поточную функцию динамический трехмерный массив и получаю ошибку сегментирования. Вы бы не могли пожалуйста показать как нужно работать с динамическими трехмерными массивами в потоковой функции? И хотел бы ещё добавить, что ваш пример со статическим массивом это лучшее, что я видел по теме многопоточности в си и он способен заменить начинающим с десяток лекций.

Я создаю массив таким образом.

Code
1
2
3
4
5
6
7
8
9
10
11
    int zindex = 3;
    int yindex = 3;
    int xindex = 3;
 
    int ***array3d = (int ***) malloc(zindex*sizeof(int**));
    for (int i = 0; i < zindex; i++) {
        array3d[i] = (int **) malloc(yindex*sizeof(int*));
        for(int j = 0; j < yindex; j++) {
            array3d[i][j] = (int *) malloc(xindex*sizeof(int));
        }
    }
Но не знаю как передать его в потоковую функцию.
0
13 / 13 / 0
Регистрация: 21.10.2011
Сообщений: 58
27.02.2021, 10:13
Ну что ж, давай еще немного поиграемся. Прежде чем начнем работать с памятью, давай подумаем, а как она устроена.
- Память это пространство, у которого есть начальный адрес, размерность одной ячейки и длина.
- Память можно выделить статически. Она будет выделяться при загрузке программы и если там будут не нулевые значения, она будет автоматически проинициализированна и будет занимать место в исполнимом файле
- Память может быть выделена динамически, во время исполнения программы. Тогда по окончании работы, такую память нужно возвращать

Теперь нюансы.
Несмотря на то, что я сказал, что Память характеризуется 'размерностью одной ячейки' - это понятие условно. Размерность это подсказка компилятору, как он должен работать с памятью, как он должен применять свою компиляторскую математику. Ничто нам не мешает в процессе исполнения, изменять эту условность и подходить к памяти с другой линейкой.
Есть специальный универсальный тип, который называется void. Он говорит компилятору: - "Смотри на это как на нечто, что ты не понимаешь, но не задавай вопросов". Его мы можем использовать, чтобы передавать любой тип в функцию, а затем мы будем его приводить к нужному. Компилятор даже не пикнет (это не относится к C++, там несколько другие правила)

Как мы можем выделять Память для нашего трехмерного массива. 1) Выделить один большой блок, затем сказать компилятору, как его интерпретировать (типа приложить трафарет с рисунком нашего массива). 2) Выделить массив указателей на int*, для каждого указателя выделить свой блок (то как ты попытался сделать)

Думаю понятно, что эффективнее выделить один блок?

Теперь программа, я внес изменения

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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h> /* for bool type */
#include <getopt.h> /* for options support */
#include <pthread.h> /* for pthreads support */
#include <unistd.h> /* for sleep */
 
#define PROGNAME "threads2"
#define VERSION "0.1"
 
/* зададим константы с размерностями */
#define D1 3
#define D2 3
#define D3 7
 
int debug;
int errcode = 0;
pthread_t tid[100];
int tcount;
 
int done;
 
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
 
/* эту структуру мы будем использовать для передачи в функцию. Во-первых, это удобно. Во-вторых, в функцию thr_fn мы можем передать лишь один параметр, а нам нужно много. Это типа лайвхак */
struct a3 {
    void *aaa; /* указатель типа void на наш массив, перед использованием, мы его должны привести к нужному типу*/
    int d1; /* наша размерность */
    int d2;
    int d3;
};
 
void *thr_fn(void *arg) {
    /* мы знаем, что arg это указатель на struct a3. Делаем приведение */
    struct a3 *a3 = (struct a3*)arg; /* "a3" и "struct a3" это не одно и то же */
 
    /* тут нюанс. Так как a3 это указатель, разыменовывать его нужно через '->' */
    int (*aaa)[a3->d2][a3->d3] = (int (*)[a3->d2][a3->d3])a3->aaa; /* создаем локальную переменную aaa и копируем туда адрес нашего массива */
 
    //pthread_mutex_lock(&lock);
 
    int i, j, k;
    for (i = 0; i < D1; i++) {
        for (j = 0; j < D2; j++) {
            for (k = 0; k < D3; k++) {
                printf("%d ", aaa[i][j][k]);
            }
            printf("\n");
        }
        printf("\n");
    }
 
    done--;
 
    //pthread_mutex_unlock(&lock);
 
    return (void *)0;
}
 
void print_aaa(struct a3 a3) {
    /* здесь структура передается статически, для разыменования используем точку */
    int (*aaa)[a3.d2][a3.d3] = a3.aaa; /* создаем локальный указатель и копируем в него адрес нашего массива */
 
    int i, j, k;
    for (i = 0; i < a3.d1; i++) {
        for (j = 0; j < a3.d2; j++) {
            for (k = 0; k < a3.d3; k++) {
                printf("%d ", aaa[i][j][k]);
            }
            printf("\n");
        }
        printf("\n");
    }
}
 
/* функция создания трехмерного массива */
void *make_aaa(int d1, int d2, int d3) {
    /* выделяем Память одним блоком, размерностью d1 x d2 x d2, с размером ячейки int */
    int (*res)[d2][d3] = malloc(sizeof(int) * d1 * d2 * d3);
 
    /* инициализируем Память значением k+1 (порядковый номер ячейки) */
    int i, j, k;
    for (i = 0; i < d1; i++) {
        for (j = 0; j < d2; j++) {
            for (k = 0; k < d3; k++) {
                res[i][j][k] = k + 1;
            }
        }
    }
 
    /* функция возвращает указатель типа void, что позволяет компилятору автоматически приводить к нужному типу */
    return (void*)res;
}
 
void usage(const char * const name)
{
        printf("usage:\n%s [options]\n", name);
        printf("options:\n");
    printf("  --help\t\t\tThis help.\n");
        printf("  -d, --debug\t\t\tPrint lots of debugging information.\n");
        printf("  -V, --version \t\tPrint program version.\n");
 
        printf("\nreport bugs to <fish9370@mail.ru>\n");
}
 
int main(int argc, char *argv[])
{
 
        static struct option long_options[] = {
                {"help", 0, 0, '?'},
                {"debug", 0, 0, 'd'},
                {"version", 0, 0, 'V'},
                {0, 0, 0, 0}
        };
 
        int c, index = 0;
        while((c = getopt_long(argc, argv, "hdV", long_options, &index)) != -1) {
                switch(c) {
        case 'd':
                        debug = true;
                        break;
 
                case ':':
                        printf("Option -%c requires an operand\n", optopt);
                        usage(argv[0]);
                        errcode = -1;
                        goto exit;
 
                case 'V':
                        printf("%s %s\n", PROGNAME, VERSION);
                        printf("Copyright (C) 2010 fish9370");
                        printf("This is free software; see the source for copying conditions.  There is NO\n");
                        printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
                        goto exit;
 
                case '?':
                        /*printf("Unrecognized option: -%c\n", optopt);*/
                        usage(argv[0]);
                        goto exit;
                }
 
    }
 
    /* создаем экземпляр нашей структуры и тут же создаем массив, размерностью D1 x D2 x D3 */
    struct a3 a3 = {
        .aaa = make_aaa(D1, D2, D3),
        .d1 = D1,
        .d2 = D2,
        .d3 = D3
    };
 
    if (debug) {
    /* при отладке (ключ -d) печатаем наш массив и выходим. Не забываем освободить память */
        print_aaa(a3);
        free(a3.aaa);
        goto exit;
    }
 
    done = 0;
 
    for (tcount = 0; tcount < 10; tcount++) {
        done++;
        pthread_create(&tid[tcount], NULL, thr_fn, (void *)&a3);
    }
 
    while (done > 0)
        usleep(100);
 
    /* Не забываем освободить Память */
    free(a3.aaa);
 
exit:
    return errcode;
}
1
1 / 1 / 0
Регистрация: 25.02.2021
Сообщений: 5
27.02.2021, 12:46
Огромное спасибо! Вам нужно преподавать в университете, если вы уже это не делаете. Очень доступно и главное понятно написано. Повторюсь, что это лучшее по теме, что я где-либо видел.
1
13 / 13 / 0
Регистрация: 21.10.2011
Сообщений: 58
27.02.2021, 16:40
И все же, ответ будет не полным, если мы не рассмотрим работу с указателем типа (int ***aaa). Особенность этого подхода в способе выделения памяти, а так же в ее освобождении

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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h> /* for bool type */
#include <getopt.h> /* for options support */
#include <pthread.h> /* for pthreads support */
#include <unistd.h> /* for sleep */
 
#define PROGNAME "threads2"
#define VERSION "0.4"
 
int debug;
int errcode = 0;
pthread_t tid[100];
int tcount;
 
int done;
 
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
 
struct a3 {
    void *aaa;
    int d1;
    int d2;
    int d3;
};
 
void *thr_fn(void *arg) {
    struct a3 *a3 = (struct a3*)arg;
 
    /* теперь локализуем переменную aaa так. Это говорит компилятору: мы имеем трехмерный массив указателей. И значение находится по адресу aaa[адрес1][адрес2][адрес3]-> вон там */
    int ***aaa = a3->aaa;
 
    //pthread_mutex_lock(&lock);
 
    int i, j, k;
    for (i = 0; i < a3->d1; i++) {
        for (j = 0; j < a3->d2; j++) {
            for (k = 0; k < a3->d3; k++) {
             /* хотя эта запись осталась прежней aaa[i][j][k], механика получения значения изменилась */
                printf("%d ", aaa[i][j][k]);
            }
            printf("\n");
        }
        printf("\n");
    }
 
    done--;
 
    //pthread_mutex_unlock(&lock);
 
    return (void *)0;
}
 
void print_aaa(struct a3 *a3) {
    /*  мы имеем трехмерный массив указателей */
    int ***aaa = a3->aaa;
 
    int i, j, k;
    for (i = 0; i < a3->d1; i++) {
        for (j = 0; j < a3->d2; j++) {
            for (k = 0; k < a3->d3; k++) {
                printf("%d ", aaa[i][j][k]);
            }
            printf("\n");
        }
        printf("\n");
    }
}
 
void make_aaa(struct a3 *a3) {
    /* инициализируем генератор случайных чисел, используем текущее время в секундах (функция time(NULL)). Это позволяет получать числа более случайно (не стоит на это полагаться в криптографических алгоритмах) */
    srand(time(NULL));
 
    /* выберем случайные значения для нашего массива, от 3 до 12 */
    a3->d1 = rand() % 10 + 3;
    a3->d2 = rand() % 10 + 3;
    a3->d3 = rand() % 10 + 3;
 
    /* выделяем память под первую размерность нашего массива */
    int (***res) = malloc(sizeof(int*) * a3->d1);
 
    /* адрес полученного блока будет точкой входа в наш массив, сохраним ее в структуре a3 */
    a3->aaa = res;
 
    int i, j, k;
    for (i = 0; i < a3->d1; i++) {
        /* выделяем память для d2 */
        res[i] = malloc(sizeof(int*) * a3->d2);
        for (j = 0; j < a3->d2; j++) {
            /* выделяем память для d3 */
            res[i][j] = malloc(sizeof(int*) * a3->d3);
            for (k = 0; k < a3->d3; k++) {
                res[i][j][k] = k + 1;
            }
        }
    }
 
     /* struct a3 передается по ссылке, т.е. данные будут записаны туда напрямую. Мы ничего не возвращаем */
 
    return;
}
 
/* функция освобождения памяти. Теперь нужно в цикле пробегать и удалять каждый выделеный блок. Делаем это в обратном порядке, тому как выделяли */
void free_aaa(struct a3 *a3) {
    int ***aaa = a3->aaa;
 
    int i, j;
    for (i = 0; i < a3->d1; i++) {
        for (j = 0; j < a3->d2; j++) {
            free(aaa[i][j]);
        }
        free(aaa[i]);
    }
    free(aaa);
}
 
void usage(const char * const name) {
        printf("usage:\n%s [options]\n", name);
        printf("options:\n");
    printf("  --help\t\t\tThis help.\n");
    printf("  -d, --debug\t\t\tPrint lots of debugging information.\n");
        printf("  -V, --version \t\tPrint program version.\n");
 
        printf("\nreport bugs to <fish9370@mail.ru>\n");
}
 
int main(int argc, char *argv[]) {
        static struct option long_options[] = {
                {"help", 0, 0, '?'},
                {"debug", 0, 0, 'd'},
                {"version", 0, 0, 'V'},
                {0, 0, 0, 0}
        };
 
        int c, index = 0;
        while((c = getopt_long(argc, argv, "hdV", long_options, &index)) != -1) {
                switch(c) {
        case 'd':
                        debug = true;
                        break;
 
                case ':':
                        printf("Option -%c requires an operand\n", optopt);
                        usage(argv[0]);
                        errcode = -1;
                        goto exit;
 
                case 'V':
                        printf("%s %s\n", PROGNAME, VERSION);
                        printf("Copyright (C) 2010 fish9370");
                        printf("This is free software; see the source for copying conditions.  There is NO\n");
                        printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
                        goto exit;
 
                case '?':
                        /*printf("Unrecognized option: -%c\n", optopt);*/
                        usage(argv[0]);
                        goto exit;
                }
 
    }
 
    /* создадим структуру a3 и заполним все ее значения нулями */
    struct a3 a3 = {0};
 
    /* создадим трехмерный массив, и запишем его размерности в a3 */
    make_aaa(&a3);
 
    if (debug) {
        printf("init array: %d x %d x %d\n", a3.d1, a3.d2, a3.d3);
 
        print_aaa(&a3);
        free_aaa(&a3);
        goto exit;
    }
 
    done = 0;
 
    for (tcount = 0; tcount < 10; tcount++) {
        done++;
        pthread_create(&tid[tcount], NULL, thr_fn, (void *)&a3);
    }
 
    while (done > 0)
        usleep(100);
 
    /* не забываем освободить память */
    free_aaa(&a3);
 
exit:
    return errcode;
}
1
1 / 1 / 0
Регистрация: 25.02.2021
Сообщений: 5
27.02.2021, 17:48
fish9370, ваш код и комментарии объяснили мне огромное количество белых пятен. Это действительно лучше десятка двухчасовых лекций. Спасибо.
0
13 / 13 / 0
Регистрация: 21.10.2011
Сообщений: 58
27.02.2021, 18:59
Ну и конечно, хорошо бы сделать такой массив, в котором каждая строчка была бы случайной длины

Вот например с такими характеристиками

Code
1
2
3
4
5
6
7
8
9
10
11
1 2 3
1 2 3 4 5 6
1 2 3 4
 
1 2
1 2 3 4 5
1 2 3
 
1 2 3
1 2 3 4 5 6 7
1
1
 Аватар для peter_irich
366 / 222 / 53
Регистрация: 18.10.2017
Сообщений: 2,358
27.02.2021, 20:13
Если есть какие-то трудности с трёхмерным массивом, то просто делайте его одномерным
и сами обеспечивайте правильное вычисления индекса. Он же физически именно одномерный.
Я иногда так делал. Это нетрудно, ведь количество элементов по каждому измерению известно,
простая формула пересчитает три индекса в один.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
27.02.2021, 20:13
Помогаю со студенческими работами здесь

Передача функции-члена класса в pthread_create
Здравствуйте, товарищи! Существует ли корректный способ передать указатель на функцию-член класса в качестве параметра в функцию...

Выделить память для трехмерного массива и изменить индексы начального элемента массива
Выделить память для трехмерного массива а. Изменить индексы начального элемента массива на . Протестировать программу

Заполнение трехмерного массива
Нужно заполнить трехмерный массив размерами 4*5*7 случайными числами от 0 до 1 с шагом 0,1 и вывести.

Сортировка трехмерного массива
Не могу понять, как (за приемлемое время - не более 300мс) отсортировать трехмерный массив на 500^3 элементов (куб). Сортировка должна...

Сортировка трехмерного массива
Выполнить сортировку трехмерного массива методом вставки, пызырька!


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

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Новые блоги и статьи
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
Первый деплой
lagorue 16.01.2026
Не спеша развернул своё 1ое приложение в kubernetes. А дальше мне интересно создать 1фронтэнд приложения и 2 бэкэнд приложения развернуть 2 деплоя в кубере получится 2 сервиса и что-бы они. . .
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ * Дана цепь постоянного тока с R, L, C, k(ключ), U, E, J. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа, решает её и находит: токи, напряжения и их 1 и 2 производные при t = 0;. . .
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым. Но восстановить их можно так. Для этого понадобится консольная утилита. . .
Изучаю kubernetes
lagorue 13.01.2026
А пригодятся-ли мне знания kubernetes в России?
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru