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

Запись адреса переменной как массив char (или повторное обращение за выделением памяти)

01.10.2019, 13:18. Показов 1287. Ответов 17
Метки нет (Все метки)

Здравствуйте формучане, встала такая задача, есть структура определяющая "мой тип", для нее был создан свой конструктор, который выделяет память под объекты "моего типа" и дает некоторые значения им.
Встала задача отслеживать повторное обращение в конструктор, что бы не выделялась память повторно, для уже обратившегося ранее объекта (старая потеряется вроде, как я понял может быть утечка). Что же я придумал ->
Идея следующая:
Запоминать адрес объектов в массив char после выделения памяти, и потом сравнивать их при каждом обращении, если вдруг будет повторное обращение, при сравнение указателей (те что в массиве char), функция выкинет с сообщение или просто выйдет из процесса (пока не придумал)

C
1
2
3
4
5
6
7
8
9
10
11
12
13
static void memory_control (size_t flag, char* s1, char* s2) //flag это кол-во адресов в s1, s2 это новый адрес для сравнения
{
    for (int i = 0; i < flag; i++)
        if (strncmp(&s1[flag * size_of_adress], s2, size_of_adress))   //size_of_adress это кол-во символов в адресе
                continue;
            else 
            {
                // ПРИДУМАТЬ что делать с массивом который передали второй раз
                puts("_memcontrol: constructor recall");
                exit(1);
            }
    concat(s1, s2, flag);       
}
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static void concat(char* s1, const char* s2, size_t flag)  // здесь происходит склеивание строк s1 и s2, если memory_control 
                                                                                //  сказал что массивы не имеют одинаковых адресов(8ми подряд идущих 
                                                                               //   символов)
 
{
    size_t size = 2 * flag * size_of_adress + 1;
    
       // реаллоцирую память для строки s1 и s2 (-1 т.к учитываю терминирующий ноль для s1 и s2, а надо один раз)
    s1 = (char*)realloc(s1, size + strlen(s2) - 1);
    if (s1 == NULL)
    {
        puts("_concat: failed to allocate memory ");
        exit(1);
    }
    strcat_s(s1, size, s2);
}

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

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
01.10.2019, 13:18
Ответы с готовыми решениями:

Обращение к структуре в классе с выделением памяти
Добрый день уважаемые форумчане. Столкнулся с такой проблемой. Есть класс: class Components {...

Запись и чтение файла с выделением памяти на чистом C.
Помогите разобраться. Записываю вроде правильно. А прочитать не может. Выдает ошибку. Подскажите...

Как правильно делать запись переменной при подмене адреса
Подскажите пожалуйста как вставить PHP переменную в ссылку на JS, не могу понять как в такой...

Вывод адреса переменной типа char
Всем привет! Хочу задать вопрос... есть код: #include &lt;iostream&gt; int main() { char ch =...

17
Мозгоправ
1713 / 1014 / 461
Регистрация: 01.10.2018
Сообщений: 2,124
Записей в блоге: 2
02.10.2019, 23:23 2
Не лучшая идея хранить адреса в массиве char.

Чем вас не устраивает такой вариант:
C
1
2
3
4
5
struct MyType {
...
};
 
MyType *check[ARRSIZE];  /* массив указателей на экземпляры структуры MyType */
или такой:
C
1
2
3
MyType **check;  /* массив указателей на экземпляры структуры MyType */
size_t arrsize = ...;
check = (MyType *)malloc(sizeof(MyType *) * arrsize); /* с возможностью реаллоцирования памяти под массив */
Добавлено через 17 минут
А вообще для решения таких проблем C++ придумали
0
1 / 1 / 0
Регистрация: 15.12.2015
Сообщений: 24
04.10.2019, 00:41  [ТС] 3
Спасибо большое.
К сожалению юзать cpp нельзя
А решил проблему по другому, макросом, может кому пригодится
C
1
2
3
#define Matrix(m,n,C) static bool flag=1; \
                      static Matr *addr; Matr &C=*newMatr(m,n); \ //ну вместо newMatr ваш конструктор 
                      if(flag){addr=&C; flag=0;}else{free((void*)addr); addr=&C;}
0
Мозгоправ
1713 / 1014 / 461
Регистрация: 01.10.2018
Сообщений: 2,124
Записей в блоге: 2
04.10.2019, 19:35 4
Хреновый макрос у вас получился.
C
1
2
Matrix(2, 3, ma);
Matrix(4, 5, mb);
и... ваша фамилия Мухин...

И вообще, макросы - зло. Иногда необходимое. Но не в этом случае.

Если вам уж так нужен контроль за выделением/освобождением памяти при создании/удалении объектов определённого типа, то
  1. Прячьте тип, реализующий функционал, в отдельную библиотеку (lib, dll и тому подобное).
  2. Наружу показывайте только указатель на этот тип.
  3. Всё взаимодействие с объектами делайте через публично-доступные функции, принимающие или возвращающие указатель на объект. В том числе создание - через функцию-"конструктор", возвращающую указатель на полностью инициализированный объект, и удаление - через функцию-"деструктор".
  4. В закрытой части сделайте статический объект-контейнер (примерно как второй вариант из #2), который будет хранить адреса всех объектов, которые были созданы "конструктором". Все функции, взаимодействующие с объектами этого типа, в том числе и "деструктор", должны проверять наличие адреса конкретного объекта в контейнере. "Конструктор" добавляет адрес в контейнер, "деструктор" - удаляет, остальные функции - проверяют наличие.
Примерно так.
0
1 / 1 / 0
Регистрация: 15.12.2015
Сообщений: 24
06.10.2019, 10:55  [ТС] 5
L0M,
Цитата Сообщение от L0M Посмотреть сообщение
Хреновый макрос у вас получился.
какой придумал)

Цитата Сообщение от L0M Посмотреть сообщение
И вообще, макросы - зло. Иногда необходимое. Но не в этом случае.
Я думал что си и макросы неразлучны.
Цитата Сообщение от L0M Посмотреть сообщение
В закрытой части сделайте статический объект-контейнер (примерно как второй вариант из #2), который будет хранить адреса всех объектов, которые были созданы "конструктором". Все функции, взаимодействующие с объектами этого типа, в том числе и "деструктор", должны проверять наличие адреса конкретного объекта в контейнере. "Конструктор" добавляет адрес в контейнер, "деструктор" - удаляет, остальные функции - проверяют наличие.
Все до 3го пункта реализовано, но как сделать 4-й не пойму. Можно пожалуйста кусок кода, как это вообще должно выглядеть? И функции проверяющей наличие. Самую примитивную реализацию, буду признателен.

Это мой конструктор
C
1
2
3
4
5
6
7
8
9
Vector* create_Vec(size_t size)
{
    Vector* vec;
    vec = (Vector*)malloc(sizeof(Vector));
    vec->vect = create_vec(size);
    vec->size = size;
    vec->Vfree = Vfree;
    return vec;
}
А это деструктор
C
1
2
3
4
5
inline static void Vfree(Vector* vec)
{
    free(vec->vect);
    free(vec);
}
0
Мозгоправ
1713 / 1014 / 461
Регистрация: 01.10.2018
Сообщений: 2,124
Записей в блоге: 2
06.10.2019, 22:26 6
Лучший ответ Сообщение было отмечено executor как решение

Решение

Цитата Сообщение от executor Посмотреть сообщение
Все до 3го пункта реализовано, но как сделать 4-й не пойму. Можно пожалуйста кусок кода, как это вообще должно выглядеть? И функции проверяющей наличие. Самую примитивную реализацию, буду признателен.
Например так:
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
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
 
struct Vector;
void check_in(Vector *vec);
void check_out(Vector *vec);
int check_test(Vector *vec);
 
struct Vector {
    int *vect;
    size_t size;
    void(*Vfree)(Vector*);
};
 
int * create_vec(size_t size) {
    int *arr = (int *)malloc(size * sizeof(int));
    return arr;
}
 
static void Vfree(Vector* vec)
{
    check_out(vec);
 
    free(vec->vect);
    free(vec);
}
 
Vector* create_Vec(size_t size)
{
    Vector* vec;
    vec = (Vector*)malloc(sizeof(Vector));
    vec->vect = create_vec(size);
    vec->size = size;
    vec->Vfree = Vfree;
 
    check_in(vec);
 
    return vec;
}
 
/* Функция что-то делает с объектом */
int do_smth(Vector *vec) {
    if (!check_test(vec))  /* проверить объект перед использованием */
        return -1;  /* передан невалидный vec */
 
    /* do something  */
    return 0;
}
 
/*---------------------------------------------------------------------------------*/
 
struct CheckItem {
    Vector *data;
};
 
static CheckItem *check;  /* массив указателей на экземпляры структуры Vector */
static size_t check_size = 10;
static size_t check_grow = 5;
static size_t cur_size = 0;
 
void init_lib() {
    check = (CheckItem *)malloc(sizeof(CheckItem) * check_size); /* с возможностью реаллоцирования памяти под массив */
    memset(check, 0, sizeof(CheckItem) * check_size);
#ifdef _DEBUG
    printf("init_lib(): allocated memory for %zd items\n", check_size);
#endif
}
 
void uninit_lib() {
    if (cur_size > 0) {
#ifdef _DEBUG
        printf("uninit_lib(): %zd items left into container\n", cur_size);
#endif
        for (size_t i = 0; i < check_size; ++i)
            if (check[i].data != NULL)
                Vfree(check[i].data);
    }
    free(check);
}
 
void check_in(Vector *vec) {
    if (cur_size >= check_size) {
        size_t new_check_size = check_size + check_grow;
        check = (CheckItem *)realloc(check, sizeof(CheckItem) * new_check_size);
        memset(check + check_size, 0, check_grow * sizeof(CheckItem));
        check_size = new_check_size;
#ifdef _DEBUG
        printf("check_in(): reallocated memory for %zd items\n", check_size);
#endif
    }
    for (size_t i = 0; i < check_size; ++i)
        if (check[i].data == NULL) {
            check[i].data = vec;
            ++cur_size;
#ifdef _DEBUG
            printf("check_in(): item appended; container has %zd items\n", cur_size);
#endif
            break;
        }
}
 
void check_out(Vector *vec) {
    for (size_t i = 0; i < check_size; ++i)
        if (check[i].data == vec) {
            check[i].data = NULL;
            --cur_size;
#ifdef _DEBUG
            printf("check_out(): item removed; container has %zd items\n", cur_size);
#endif
            break;
        }
}
 
int check_test(Vector *vec) {
    for (size_t i = 0; i < check_size; ++i)
        if (check[i].data == vec)
            return 1;
    return 0;
}
 
/*---------------------------------------------------------------------------------*/
 
int main() {
    init_lib();
 
    Vector *v = create_Vec(11);
    Vfree(v);
 
    for (int i = 0; i < 12; ++i) {
        Vector *vv = create_Vec(7);
        if (do_smth(vv) == -1)
            printf("error\n");
    }
 
    Vector *ill_vec = (Vector *)malloc(sizeof(Vector));
    if (do_smth(ill_vec) == -1)
        printf("error with ill_vec\n");
    free(ill_vec);
 
    uninit_lib();
    return 0;
}
2
1 / 1 / 0
Регистрация: 15.12.2015
Сообщений: 24
06.10.2019, 23:00  [ТС] 7
L0M, спасибо большое
0
196 / 230 / 33
Регистрация: 29.03.2019
Сообщений: 657
07.10.2019, 00:52 8
Цитата Сообщение от executor Посмотреть сообщение
К сожалению юзать cpp нельзя
а это что?
Цитата Сообщение от executor Посмотреть сообщение
Matr &C=*newMatr(m,n)
сишный компиль отрыгнет
Цитата Сообщение от executor Посмотреть сообщение
Встала задача отслеживать повторное обращение в конструктор
если такая задача появилась, то что-то в проекте пошло не так. Насколько я понимаю здесь не идет речь о написании сборщика мусора, а банально работа со структурами данных. Ну если уж сосвем приперло, до добавьте в деструктор
C
1
2
3
4
5
6
7
inline static void Vfree(Vector* vec)
{
  free(vec->vect);
  vec->vect = NULL;
  free(vec);
  vec = NULL;
}
а в конструкторе добавьте проверку на NULL. Везде где объявляете объект инициализируйте его NULL'ем. И вообще возьмите себе как дважды два что любое объявление должно быть неразрывно с инициализацией. Где объявление, там инициализация значением по умолчанию.
C
1
2
3
4
5
6
7
8
9
10
Vector* create_Vec(size_t size)
{
    Vector* vec = NULL; // здесь изменение
    vec = (Vector*)malloc(sizeof(Vector)); // нет проверки на возврат malloc. В случае неудачи malloc возвращает NULL
    vec->vect = NULL; // добавлено выражение
    vec->vect = create_vec(size);
    vec->size = size;
    vec->Vfree = Vfree;
    return vec;
}
Вообще идея мне понятна. В хотите использовать ООП в си. Это вполне возможно, правда в более ручном режиме, но возможно. В качестве деструктора вы присваиваете полю объекта Vfree адрес функции Vfree. Что мешает вам таким же образом добавить в объект и конструктор? Итак в сухом остатке это будет выглядеть как-то так:
Кликните здесь для просмотра всего текста
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
#include <stdio.h>
#include <stdlib.h>
 
 
typedef struct vector * vector_ptr;
typedef struct vector {
  int * data;
  size_t len;
  void (*constructor)(vector_ptr, size_t);
  void (*destructor)(vector_ptr);
} vector_t;
 
void
create_data (vector_ptr self, size_t len) {
 
  if ((self->data != NULL) || ((self->data = malloc(len)) == NULL)) {
    //throw_exception(); or try again
  }
  self->len = len;
}
 
void
delete_data(vector_ptr self) {
  if (self->data != NULL) {
    free(self->data);
    self->len = 0;
  }
}
 
void
init_vector (vector_ptr vec) {
  vec->len = 0;
  vec->data = NULL;
  vec->constructor = create_data;
  vec->destructor = delete_data;
}
 
int
main (int argc, char ** argv)
{
  vector_t vec; // создали объект
  init_vector(&vec); // проинициализировали
  vec.constructor(&vec, 10); // создали массив данных, добавили служебную информацию
  /* отработали с объектом */
  vec.destructor(&vec); // освободили память под объект
  exit(EXIT_SUCCESS);
}
0
Мозгоправ
1713 / 1014 / 461
Регистрация: 01.10.2018
Сообщений: 2,124
Записей в блоге: 2
07.10.2019, 01:22 9
Цитата Сообщение от zeroalef Посмотреть сообщение
сишный компиль отрыгнет
Не отрыгнёт. Смотрите внимательнее.
Цитата Сообщение от zeroalef Посмотреть сообщение
В качестве деструктора вы присваиваете полю объекта Vfree адрес функции Vfree.
Я, кстати, не понял зачем вы, executor, сделали это поле. Я его не использовал. Но и не убрал: может у вас на него свои планы.

Добавлено через 8 минут
zeroalef, ваше решение легко сломать, если попользовать его кривыми руками. Моё решение сломать сильно сложнее. И с потенциальными утечками памяти вроде получше. По крайней мере, если не забыть вызвать uninit_lib(), все явно неприбитые объекты будут корректно разрушены.

Вопрос в том, какую цель преследует ТС.
0
196 / 230 / 33
Регистрация: 29.03.2019
Сообщений: 657
07.10.2019, 14:17 10
Цитата Сообщение от L0M Посмотреть сообщение
Не отрыгнёт. Смотрите внимательнее.
Да, так. В любом случае там написана белиберда. Возможно из-за этой игры с адресами и указателями у ТС и возникли проблемы.
Цитата Сообщение от L0M Посмотреть сообщение
Я, кстати, не понял зачем вы, executor, сделали это поле.
Просто копипаст. Из приведенного примера следует что вектор хранит в себе деструктор (Vfree). Обычная практика.
Цитата Сообщение от L0M Посмотреть сообщение
...И с потенциальными утечками памяти вроде получше. ... Вопрос в том, какую цель преследует ТС.
Контроль памяти не моя проблема. Мне показалось что ТС желает ООП в Си, я показал как это делается.

Добавлено через 29 минут
executor, возможно, описав свою задачу вы получили бы более конкретный ответ. Возможно вы выбрали не тот путь для решения вашей задачи. Опишите саму задачу.
0
1 / 1 / 0
Регистрация: 15.12.2015
Сообщений: 24
07.10.2019, 18:49  [ТС] 11
Цитата Сообщение от L0M Посмотреть сообщение
Я, кстати, не понял зачем вы, executor, сделали это поле. Я его не использовал. Но и не убрал: может у вас на него свои планы.
Засунул в него деструктор), что бы быстро вызывать.
Этим кодом будут пользоваться не только я, иначе не морочился с безопасностью.

zeroalef, задача такова, что для удобной работы с векторами, матрицами, кватернионами, создал структуры, объекты которых могу создавать. Для каждого типа создал свой коструктор/деструктор. Но потом подумал, а что если кривые руки моих друзей, возьмут и второй раз кинут в конструктор вектор, то будет утечка памяти, и хотелось бы этого избежать.


Цитата Сообщение от zeroalef Посмотреть сообщение
а в конструкторе добавьте проверку на NULL. Везде где объявляете объект инициализируйте его NULL'ем. И вообще возьмите себе как дважды два что любое объявление должно быть неразрывно с инициализацией. Где объявление, там инициализация значением по умолчанию.
NULL ptr нельзя разыменовывать.А при подаче "вектора" в коснтруктор (не NULL, первый рисунок), компилятор ругнется, мол неинициализированный указатель в функцию кидаешь, а если дать ему NULL (второй рисунок), то разыменовывать нельзя и проверить на NULL вектор не выйдет (третий рисунок) (
0
Миниатюры
Запись адреса переменной как массив char (или повторное обращение за выделением памяти)   Запись адреса переменной как массив char (или повторное обращение за выделением памяти)   Запись адреса переменной как массив char (или повторное обращение за выделением памяти)  

196 / 230 / 33
Регистрация: 29.03.2019
Сообщений: 657
07.10.2019, 20:20 12
executor, VS не умеет си. Там плюсовый компилятор.
Цитата Сообщение от executor Посмотреть сообщение
то разыменовывать нельзя и проверить на NULL вектор не выйдет (третий рисунок)
Потому что надо сначала проверить на NULL, а уже потом пытаться разыменовать если указатель не NULL. У вас на скрине нет проверки и конечно же вызвано исключение.
0
1 / 1 / 0
Регистрация: 15.12.2015
Сообщений: 24
07.10.2019, 22:46  [ТС] 13
Цитата Сообщение от zeroalef Посмотреть сообщение
Потому что надо сначала проверить на NULL, а уже потом пытаться разыменовать если указатель не NULL. У вас на скрине нет проверки и конечно же вызвано исключение.
Не понял вас.
Я показал, что пустой указатель нельзя в конструктор кинуть. И потом показал, что NULL pointer вызовет исключение.

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void
init_vector (vector_ptr vec) {
  vec->len = 0;
  vec->data = NULL;
  vec->constructor = create_data;
  vec->destructor = delete_data;
}
 
int
main (int argc, char ** argv)
{
  vector_t vec; // создали объект
  init_vector(&vec); // проинициализировали
  vec.constructor(&vec, 10); // создали массив данных, добавили служебную информацию
  /* отработали с объектом */
  vec.destructor(&vec); // освободили память под объект
  exit(EXIT_SUCCESS);
}
Если представить такой код:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void
init_vector (vector_ptr vec) {
  vec->len = 0;
  vec->data = NULL;
  vec->constructor = create_data;
  vec->destructor = delete_data;
}
 
int
main (int argc, char ** argv)
{
  vector_t vec; 
  init_vector(&vec); 
  vec.constructor(&vec, 10);
  init_vector(&vec);
  exit(EXIT_SUCCESS);
}
как мне показалось, функция init_vector, при передаче в нее структуры данных обнулит поля и потом проверку проведет.
Я не ас программирования, надеюсь выше я ошибаюсь.
0
196 / 230 / 33
Регистрация: 29.03.2019
Сообщений: 657
07.10.2019, 23:30 14
Цитата Сообщение от executor Посмотреть сообщение
Я не ас программирования, надеюсь выше я ошибаюсь.
Так и есть. Выше я писал:
Цитата Сообщение от zeroalef Посмотреть сообщение
И вообще возьмите себе как дважды два что любое объявление должно быть неразрывно с инициализацией. Где объявление, там инициализация значением по умолчанию.
В моем случае функция init_vector есть инициализация. Не больше и не меньше. Она вызывается только однажды для одного объекта сразу после его создания. Ее цель -- инициализировать поля структуры значениями. Сам же конструктор хранится в объекте и вызывается из него же явно (как и деструктор). Если объект инициализировать повторно, то конечно утечет память. Но зачем это делать? Порадок действий такой:
1. инициализировали
2. вызвали конструктор
3. отработали данные
4. вызвали деструктор
Таким же образом возможно добавить и любые другие методы в объект vetcor_t. Вы говорите что пишете велосипед для некоторых задач линейной алгебры, алгебры групп. Перечислите операции, которые вы планируете реализовать с над векторами. Я попробую это реализовать и протестировать.
0
Мозгоправ
1713 / 1014 / 461
Регистрация: 01.10.2018
Сообщений: 2,124
Записей в блоге: 2
07.10.2019, 23:36 15
Цитата Сообщение от zeroalef Посмотреть сообщение
Если объект инициализировать повторно, то конечно утечет память. Но зачем это делать? Порадок действий такой:
zeroalef, это всё хорошо в идеальном мире. Однако есть
Цитата Сообщение от executor Посмотреть сообщение
кривые руки моих друзей
Поэтому executor хочет подстраховаться. И в чём-то он прав.
0
196 / 230 / 33
Регистрация: 29.03.2019
Сообщений: 657
08.10.2019, 02:00 16
Цитата Сообщение от L0M Посмотреть сообщение
Поэтому executor хочет подстраховаться. И в чём-то он прав.
Конструктор повторно вызывать можно. Повторный вызов просто ничего не сделает. Но инициализация вызывается единожды. Так всегда в любой библиотеке. Это фундаментальный принцип. Язык предполагает много способов прострелить себе ногу. Вот один из них во всей красе. В сиплюсплюсе RAII -- функция компилятора. В сишке же придется все самому ручками и внимательно следить за последовательностью своих действий. Как функция инициализации определит выделен объект на стеке или в куче? Придется глубоко зарыться в системщину. Поэтому в силу вступают соглашения об использовании интерфейсов, во избежание проблем.

Добавлено через 33 минуты
Вот рабочий пример с векторами. API конечно лучше вынести в отдельный файл vector.c. Утечек нет, работает как часы. Релизовано:
- выделение/осаобождение памяти под вектор (массив) типа 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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#ifndef HAVE_BZERO
#define bzero(ptr,n) (memset(ptr,0,n))
#endif
 
#define VEC_INCREASE (128u)
 
typedef struct vector * vector_ptr;
typedef struct vector {
  int * data;
  size_t length;
  size_t size;
  void (*create)(vector_ptr);
  void (*free)(vector_ptr);
  void (*push)(vector_ptr, int);
  int (*pop)(vector_ptr);
  int (*get)(vector_ptr, size_t);
  int (*increase)(vector_ptr);
  int (*decrease)(vector_ptr);
} vector_t;
 
void
vector_create (vector_ptr self) {
  if ((self == NULL) || (self->data != NULL)) {
    return;
  }
  if ((self->data = malloc(VEC_INCREASE * sizeof(int))) == NULL) {
    fprintf(stderr, "Error vector_create: refused OS get memory\n");
    return;
  }
  bzero(self->data, VEC_INCREASE * sizeof(int));
  self->size += VEC_INCREASE;
}
 
void
vector_free(vector_ptr self) {
  if ((self == NULL) || (self->data == NULL)) {
    return;
  }
  free(self->data);
  self->length = 0;
  self->size = 0;
}
 
int
vector_increase (vector_ptr self) {
  int * ptr = NULL;
 
  if ((ptr = malloc((self->size + VEC_INCREASE) * sizeof(int))) == NULL) {
    fprintf(stderr, "Error vector_increase: refused OS get memory\n");
    return EXIT_FAILURE;
  }
  bzero(ptr, (self->size + VEC_INCREASE) * sizeof(int));
  memmove(ptr, self->data, self->length * sizeof(int));
  free(self->data);
  self->data = ptr;
  self->size += VEC_INCREASE;
  return EXIT_SUCCESS;
}
 
int
vector_decrease (vector_ptr self) {
  int * ptr = NULL;
 
  if ((ptr = malloc((self->size - VEC_INCREASE) * sizeof(int))) == NULL) {
    fprintf(stderr, "Error vector_decrease: refused OS get memory\n");
    return EXIT_FAILURE;
  }
  bzero(ptr, (self->size - VEC_INCREASE) * sizeof(int));
  memmove(ptr, self->data, self->length * sizeof(int));
  free(self->data);
  self->data = ptr;
  self->size -= VEC_INCREASE;
  return EXIT_SUCCESS;
}
 
void
vector_push (vector_ptr self, int value) {
  if ((self == NULL) || (self->data == NULL)) {
    return;
  }
  if (self->length >= self->size) {
    if ((self->increase(self)) == EXIT_FAILURE) {
      fprintf(stderr, "Error vector_push: vector_increase returned\n");
      exit(EXIT_FAILURE);
    }
  }
  self->data[self->length] = value;
  self->length++;
}
 
int
vector_pop (vector_ptr self) {
  int returned = 0;
  if (self->length <= 0) {
    return EXIT_FAILURE;
  }
  self->length--;
  returned = self->data[self->length];
 
  if ((self->size - self->length) >= VEC_INCREASE) {
    if ((self->decrease(self)) == EXIT_FAILURE) {
      fprintf(stderr, "Error vector_pop: vector_decrease returned\n");
      exit(EXIT_FAILURE);
    }
  }
  return returned;
}
 
int
vector_get (vector_ptr self, size_t index) {
  if ((self == NULL) || (self->data == NULL)) {
    fprintf(stderr, "Error vector_get: incomplete data passed\n");
    return EXIT_FAILURE;
  }
  if (index < self->length) {
    return self->data[index];
  }
  return index;
}
 
void
init_vector (vector_ptr vec) {
  vec->length = 0;
  vec->size = 0;
  vec->data = NULL;
  vec->create = vector_create;
  vec->free = vector_free;
  vec->push = vector_push;
  vec->pop = vector_pop;
  vec->get = vector_get;
  vec->increase = vector_increase;
  vec->decrease = vector_decrease;
}
 
int
main (int argc, char ** argv)
{
  vector_t vec; // создали объект
  init_vector(&vec); // проинициализировали
  vec.create(&vec); // вызов конструктора
  /* отработали с объектом */
  for (int i = 0; i < 18; i++) {
    vec.push(&vec, i);
  }
  fprintf(stdout, "%i\n", vec.get(&vec, 4));
  fprintf(stdout, "%i\n", vec.get(&vec, 6));
  while (vec.length > 0) {
    fprintf(stdout, "%i  ", vec.pop(&vec));
  }
  putchar('\n');
  vec.free(&vec); // вызов деструктора
  exit(EXIT_SUCCESS);
}

Таким образом видно что расширить функционал объекта типа vector_t довольно тривиальная задача. Другое дело что подобная игрушка надо одним типом становится бессмысленной и затратной в сравнении с обычной императивщиной. Хоть и не значительно, но все же. Вот если мы хотим полиморфный контейнер, то да, можно и заморочиться. Однако вернемся к задаче. На основе данного типа таким же образом реализуется и тип matrix_t, где контейнер будет содержать массив векторов. Индекс строки есть индекс массива, индекс столбца есть индекс массива вектора. Ну и т.д.
1
1 / 1 / 0
Регистрация: 15.12.2015
Сообщений: 24
08.10.2019, 11:43  [ТС] 17
zeroalef, спасибо большое. Вы очень помогли с кодом и информацией, как лучше реализовать.
Просто выше я писал, что один из моих друзей может по ошибке засунуть объект повторно в конструктор.
Но эту проблему я решаю, спасибо большое L0M.
Думаю тему можно закрыть.
0
196 / 230 / 33
Регистрация: 29.03.2019
Сообщений: 657
08.10.2019, 20:48 18
Цитата Сообщение от executor Посмотреть сообщение
один из моих друзей может по ошибке засунуть
Вы никогда не застрахуетесь от подобных проблем. По ошибке можно и -1 передать в функцию, ожидающую беззнаковое число, и за границы массива выйти и с десяток другой типовых ошибок. Предоставляя api необходимо дать ему описание и правила использования. Только соблюдая правила, пользователь сможет избежать проблем. Так, в порядке оффтопа.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
08.10.2019, 20:48

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

Массив с динамическим выделением памяти
Господа Программисты, суть вопроса на простом примере: int s=2;//Глобальная переменная ...

Двумерный массив с динамическим выделением памяти
Помогите пожалуйста вставить вот в эту вот задачу динамическое выделение памяти: #include...

Почему не работает 2-мерный массив с выделением памяти?
Почему не работает 2-мерный массив с выделением памяти? #include &lt;iostream&gt; using namespace...

Не могу разобраться с выделением количества памяти - массив, указатель
Правильно ли я понимаю: когда мы используем массив, в примере ниже, то литерал копируется в массив,...


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

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

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