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

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

16.05.2017, 18:47. Показов 3607. Ответов 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
11553 / 4348 / 452
Регистрация: 12.06.2008
Сообщений: 12,453
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
11553 / 4348 / 452
Регистрация: 12.06.2008
Сообщений: 12,453
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
11553 / 4348 / 452
Регистрация: 12.06.2008
Сообщений: 12,453
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
364 / 220 / 53
Регистрация: 18.10.2017
Сообщений: 2,353
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
Ответ Создать тему
Новые блоги и статьи
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru