Как отмаллочить память для элемента структуры в Си?

bvasilik

Подскажите, плз...
Есть некая структура.
struct dat {
int dat1;
int dat2;
int dat3;
char *dat4;
double dat5;
};
Во-первых, когда я пытаюсь сделать
struct out date[number];
При очень больших number прога вываливается.
Во-вторых, для *dat4 как-то надо выделить место, а как?
Заранее спасибо!

Marinavo_0507

Вываливается, это скорее всего стека не хватает.
Можно выделять статически, в сегменте данных. Или в куче.
Под char * выделять очень просто:

dat4 = (char *)malloc(N);
if (dat4 == NULL) {
fprintf(stderr, "Out of memory\n");
exit(1);
}
И прочитать-таки книжку про язык C.

bvasilik

Да как выделять-то я знаю, только это что, мне для каждого элемента в цикле for (k = 1; k <= number; k++) date[k].dat4 так выделять?
А насчёт стека... он же как-то выделяется из оперативной памяти? Так оперативки-то не используемой в этот момент дохрена

garikus


#include <stdlib.h>
...
struct out date[number];
Выделить место для dat4 ( ( i >= 0 ) && ( i <= number - 1 ) ):

date[i].dat4 = ( char * ) calloc ( n, sizeof( char ) );
if ( date[i].dat4 == NULL ) { do_something_on_error; }
В C память нужно освобождать вручную:

free( date[i].dat4 ); date[i].dat4 = NULL;
Да, нужно всё делать для каждого элемента dat4 структур, в цикле

bvasilik

Да, нужно выделять для всех элементов структуры, в цикле
Пипец какой-то, у меня в структурах этих элементов двадцать с лишним, и у каждого уникальное название

Marinavo_0507

> А насчёт стека... он же как-то выделяется из оперативной памяти? Так оперативки-то не используемой в этот момент дохрена
Во многих системах есть ограничение на размер стека, и по умолчанию максимальный размер не очень большой.

bvasilik

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

Marinavo_0507

в линуксе по умолчанию 8Мб
это если треды не используются

bvasilik

Ок, спасибо, пойду ботать

garikus


for (k = 1; k <= number; k++)

for (k = 0; k < number; k++)

rosali

Пипец какой-то, у меня в структурах этих элементов двадцать с лишним
Просто начни программировать на С++. Там есть std::string.

lord2476

так разве нельзя?
 
struct dat
{
int a;
float b;
double c;
float *m;
...
};
dat *d;

d = (dat*) malloc(num*sizeof(dat;
for (i=0;i<num;i++)
d.m[i] = (float*) malloc(m_num*sizeof(float;
...
for (i=0;i<m_num;i++)
free(d.m[i]);
free(d);

vertyal17

Ты создавай struct dat * date[number]
{т.е. массив ссылок на объекты struct dat}
потом напиши:
for(i:=0 i<number; i++) date[ i ]=(struct dat *)new(struct dat) //тут может быть ошибка
{т.е. выделяешь память под date[ i ]. Если не будешь писать конструктор и тебе комфортнее, можешь выделять память маллоком. Но лучше new}
а чтобы инициализировать char *dat4;, просто напиши конструктор
или не пиши конструктор, и если будешь что нибудь присваивать, делай это типа так
free(date[ i ]->dat4); date[ i ]->dat4=strdup(твоя строка) // strdup выделяет память
вобщем это зависит от того, какие операции планируешь делать с этим атрибутом
Я бы так сделал как нибудь

vertyal17

>std::string
Это что такое?

vertyal17

Или еще круче
struct dat {
int dat1;
int dat2;
int dat3;
char *dat4;
double dat5;
dat
{
// конструктор
dat4=malloc(сколько надо байт);
}
};
struct dat ** date;
// ссылка на ссылки на объекты struct dat}
date = (struct dat **)mallocсколько хочу)* (sizeof(struct dat*;
for(i:=0 i<сколько хочу; i++) date[ i ]=(struct dat *)new(struct dat) //тут может быть ошибка
// т.е. выделяешь память под date[ i ], при этом конструктор сразу выделяет память под dat4
free(date[ какой тебе нужен ]->dat4); date[ какой тебе нужен ]->dat4=strdup(что хочешь присвоить)
// strdup выделяет память
Я бы так сделал как нибудь.

bvasilik

Я gcc компилирую, а он new не знает...
И ещё я, хотя и gcc компилирую, пишу на сях и конструкторов не пишу
А вообще - спасибо!

vertyal17

как же так то без new ..
Хорошо что я не линуксоид

bvasilik

Хорошо что я не линуксоид
Ща тебя съедят

sergey_m

> как же так то без new ..
new это не C. И линукс здесь не причем.

TYU_2008

а malloc кастить-то зачем ? типа это нехорошо считается

sergey_m

> а malloc кастить-то зачем ? типа это нехорошо считается
Поясни. Прокомментируй.

Chupa

> а malloc кастить-то зачем ?
чтоб варнинга не было

TYU_2008

#include <stdlib.h>
и не будет варнингов

Marinavo_0507

Ну вот, там ясно написано, что на современном C вроде бы пофиг, как писать.
А если вдруг нужно будет скомпилировать код как C++, явное приведение позволяет избежать варнинга.

TYU_2008

если надо компилировать как C++, то да, касты нужны. однако оставаясь в рамках языка C считается, что касты скорее вредны, чем полезны.

sergey_m

На Це тоже нужен каст, если -Wчего-то-там-точно не помню.

TYU_2008

что-то я не понял.... это стандартом утверждается, что void* преобразовывается без кастов. Какой еще -Wbla-bla ?

sergey_m

> что-то я не понял.... это стандартом утверждается, что void* преобразовывается без кастов. Какой еще -Wbla-bla ?
Хмм. Я не смог найти этот -W. Но я помню, что когда-то я добавлял касты для того, что бы не было warningов.

rosali

явное приведение позволяет избежать варнинга
В с++ отсутствие каста - это не warning, это error.
test.cpp:5: ANSI C++ forbids implicit conversion from `void *' in assignment

rosali

Вообще нет никакой _объективной_ причины разрешать кастить void* в любой указатель. Когда придумывали Си, подозреваю, что такое решение было принято _именно_ из-за этого убожества с malloc-ом.

Dasar

С с шаблонами бывает? т.е. без объектов, но с шаблонами?

voronina

какая разница, сколько у тебя оперативки? для защиты от бесконечной рекурсии стек ограничен, обычно максимум мегабайта 2
зависит от параметров компиляции, иногда настроек операционки

Marinavo_0507

> для защиты от бесконечной рекурсии стек ограничен
для защиты от бесконечной утечки памяти область данных ограничена

voronina

еще при бесконечной рекурсии сильно утекает процессорное время так что лучше не ждать, пока заполнятся гига 3 оперативы, а пресечь чуть пораньше

ava3443

Вопрос: а как я в своё время умудрялся делать программы на фортране (как под Windows, так и под Linux которые использовали порядка 500 мегабайт памяти, причём всё из стека? Динамического выделения памяти я не использовал, параметров компиляторам никаких специальных не передавал...

Marinavo_0507

> еще при бесконечной рекурсии сильно утекает процессорное время так что лучше не ждать, пока заполнятся гига 3 оперативы, а пресечь чуть пораньше
при бесконечной утечки памяти процессорного времени утекает ещё больше (выделять память на стеке проще, чем в куче
так что, казалось бы, зачем ждать, пока заполнятся почти 3 гига?
а на самом деле всё просто - на Си и подобных языках глубокая рекурсия не принята, а утечки памяти - приняты

Marinavo_0507

Вариант 1: у фортрана свои механизмы выделения памяти
Вариант 2: ты (или фортрановский рантайм) увеличил ограничения

rosali

параметров компиляторам никаких специальных не передавал
Ну значит фортран сам за тебя уносил большие массивы со стека. Они же известной длины были...

rosali

а на самом деле всё просто
Ко всему прочему, многотредовой программе нужно _много_ стеков, причем их (в отличие от однотредового случая) нельзя наращивать "по необходимости"... Поэтому должно быть некоторое разумное и зафиксированное ограничение.

Marinavo_0507

Да, в таких программах стека ещё меньше. Ненавижу.

rosali

Кстати, мы тут на работе недавно заметили. В Яве такой проблемы быть _не должно_. В ней нельзя сослаться на ячейку в стеке. То есть в Яве указатели в heap бывают, а в стек - нет, и следовательно vm может переносить стек треда куда угодно, если это нужно для того, чтобы его удлинить. Удивительно, но несмотря на это, в Яве такие же ограниченные стеки у тредов, странно...

Marinavo_0507

Ява - это хуйня.
Вот для функционального программирования рекурсия является основным механизмом,
а всё равно в тех рантаймах, что я смотрел, используют системный стек

Julie16

А разве Явовские треды не отображаются в нативные треды для данной платформы?

bastii


Кстати, мы тут на работе недавно заметили. В Яве такой проблемы быть _не должно_. В ней нельзя сослаться на ячейку в стеке.
А ты думаешь почему в Java нет передачи параметров по ссылке.

rosali

Даже интересно, ну и почему?

rosali

Ява - это хуйня.
Щас Глеб тебя ознакомит с правилами раздела!
Вот для функционального программирования рекурсия является основным механизмом
Ну хвостовую рекурсию компиляторы берут, да и вообще, в функциональном языке все данные в heap-е, на стеке только несколько ссылок хранить надо. Ты столько локальных переменных не поназаводишь, чтобы стек кончился

Marinavo_0507

Всё равно, глубина рекурсии ограничена.
map на длинный список не пройдет.

rosali

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

bastii

Даже интересно, ну и почему?
Для этого нужно, чтобы JVM поддерживала указатели на данные в стеке, хотя бы с ограничениями как в .NET

TYU_2008

pthread_attr_setstacksize ? или я не понял о чем речь ?

rosali

Это и есть "почему"? Ну должна поддерживать, ну и что дальше?

rosali

pthread_attr_setstacksize ?
Ну если в программу много тредов, то просто виртуальные адреса кончатся и все. И еще раз повторяю, если тредов несколько, то размер стека надо выбирать _заранее_, а если тред один, то можно наращивать по необходимости, основное отличие в этом.
PS куда-то разговор зашел..

Dasar

> И еще раз повторяю, если тредов несколько, то размер стека надо выбирать _заранее_, а если тред один, то можно наращивать по необходимости
Почему нельзя размер каждого стека наращивать по необходимости?
Это вызвано какими-то высшыми причинами?
или это связано с проблемами конкретной реализации?

Julie16

Потому что адресное пространство, в которое ты хочешь нарастить стек, может быть уже занятым данными другого треда. По моему так.

bastii

Это и есть "почему"? Ну должна поддерживать, ну и что дальше?
В смысле? Ну да, для реализации параметров по ссылке в JVM нужны указатели. Там их нет, вот и передачи по ссылке тоже. Я думаю, что Sun изначально не хотела сложную VM, чотбы не было проблем с реализациями на других платформах. На "чистоте языка" это ни как не сказывается. Есть фича, которой редко пользуются, ни кому не мешает. Но когда очень надо, то пожалуйста.

Dasar

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

bastii

Мне в целом не нравится позиция Sun в отношении к языку Java. Хотите язык, чтобы писать j2ee пиложения, ок, Java 5.0 вполне годится. Но ведь Java платформа - эта платформа одного языка. А на роль универсального языка Java не дотягивает. Вот лично я прогаю всякие алгоритмы под Java и постоянно сталкиваюсь в ограничениями (надуманными во многом). Часто я хочу выделить общие куски кода в один метод, но каждый раз приходится изворачиваться, если это код должен менять значения нескольких переменных.

Julie16

Я наверное плохо написал... Я имел в виду что стеки для тредов находятся один за другим в адресном пространстве(в стековом сегменте). Как ты предполагаешь их увеличивать?
PS: в стековом сегменте они и не могут находиться по другому. Если же поместить их в сегмент данных - то тогда уже нельзя увеличить размер стека так как в виртуальном адресном пространстве необходимые адреса уже могут быть занятыми.
PPS: сегментная модель памяти не всегда может быть доступной.

a_tischkevich

Такая фигня только раньше была - когда не было виртуальной памяти.
Сейчас же и для стека и для данных используются разные сегменты памяти.
"В огороде бузина, а в Киеве дядька"

Dasar

Согласен, проблему понял.
Проблема не в самой памяти (она все равно страничная и виртуальная а в адресации этой памяти.
Адресация-то у нас одна и линейная.
Но в Java-е и .Net-е можно было попытаться избежать этой проблемы - нативных адресов у них все равно нет.

bastii

ну в логической адресации стековый сегомент большой
вроде в винде есть ограничение (2048) на кол-во тредов в оном процессе, хотя может и гоню
тогда стеки могут быть довольно большими
а в 64bit архитектурах такой проблемы наверно вообще нет.

rosali

Сейчас же и для стека и для данных используются разные сегменты памяти.
Стековый сегмент остался в прошлом веке, он использовался как раз _до_ появления виртуальной памяти. Сейчас все виртуальное адресное пространство однородное, адресуется 32-х битным адресом, который является самодостаточным (то есть никакого указания сегмента не требуется). Понятие "сегмента" в современном процессоре имеет отношение только к тому, в каком виде на виртуальные страницы накладываются ограничения read/write. Короче - минус балл.

Marinavo_0507

> Сейчас все виртуальное адресное пространство однородное, адресуется 32-х битным адресом
У кого 32, а у кого и все 64

rosali

Пофиг, команды наподобие
mov [ds:ax], ...
сейчас используется только для старта ОС.

Chupa

> команды наподобие
> mov [ds:ax], ...
> сейчас используется только для старта ОС.
у x86_64 в long mode юзаются FS: и GS:

a_tischkevich

адресуется 32-х битным адресом, который является самодостаточным (то есть никакого указания сегмента не требуется)
Хуй там. В i386 никуда сегментация не делась.
Просто во всех популярных ОС дескрипторы сегментов настраиваются "вырожденным" образом. Впрочем, не всегда. Например, в винде FS указывает на блок параметров процесса (или что-то типа того, лень вспоминать).

rosali

у x86_64 в long mode юзаются FS: и GS:
Согласен, 64 для меня пока темный лес...

Chupa

В данном случае модель памяти всё равно плоская и сегменты не используются.
Только у этих двух сегментов база рассматривается в качестве смещения,
поэтому обобщение до конкретных команд не срабатывает.

Marinavo_0507

> минус балл
проверку на арифметическое переполнение не забудь
Оставить комментарий
Имя или ник:
Комментарий: