LINUX.ORG.RU

Как правильно создавать структуры в Си? (Закрыто, FAIL, будем дальше курить литературу)

 


1

4

Накорябал такой код. Вроде всё работает, память очищается, а вот структуру приходится создавать через левые значения переменных (struct date *today = date_create (1, 1, 1);). Как это правильно делается?

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>


	struct date
{
	int year;
	int month;
	int day;
};
	
struct date *date_create(int year, int month, int day)
{
	struct date *when = malloc(sizeof(struct date));
	assert(when != NULL);
		
	when->year = year;
	when->month = month;
	when->day = day;
		
	return when;
}

void date_destroy(struct date *when)
{
	assert(when != NULL);
	free(when);
}
	
void date_print(struct date *when)
{
	printf (" date is %i/%i/%i\n", when->year, when->month, when->day);
}

int main(void)
{
	const int dayspermonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	
	struct date *today = date_create (1, 1, 1);
	printf ("Enter today`s date yyyy mm dd:\n");
	scanf ("%i %i %i", &today->year, &today->month, &today->day);
	struct date *tomorrow = date_create (today->year, today->month, today->day);
	
	if (today->day != dayspermonth[today->month - 1])
	{
		tomorrow->year = today->year;
		tomorrow->month = today->month;
		tomorrow->day = today->day + 1;
	}
	
	else if (today->month == 12)
	{
		tomorrow->year = today->year + 1;
		tomorrow->month = 1;
		tomorrow->day = 1;
	}
	
	else
	{
		tomorrow->year = today->year;
		tomorrow->month = today->month + 1;
		tomorrow->day = today->day;
	}
	

	date_print(today);
	date_print(tomorrow);
	date_destroy(today);
	date_destroy(tomorrow);
	return 0;
}
★★★★★

Последнее исправление: cetjs2 (всего исправлений: 2)

Замени malloc на calloc и не парься!

Eddy_Em ☆☆☆☆☆
()
struct date *date_create_empty()
{
	struct date *when = malloc(sizeof(struct date));
		
	when->year = 0;
	when->month = 0;
	when->day = 0;
		
	return when;
}

assert(when != NULL);

Ассерты не для того нужны.

crowbar
()
struct date *date_create();
void date_init(struct date *, int year, int month, int day);
anonymous
()
Ответ на: комментарий от crowbar

Вот так правильно:

typedef struct date sdate;
sdate *date_create_empty(){
    return calloc(1, sizeof(sdate));
}

а еще лучше — через #define:


#define ALLOC(n,s)  calloc(n,sizeof(s))
...
sdate *today = ALLOC(1, sdate);
Eddy_Em ☆☆☆☆☆
()
 	assert(when != NULL);
	free(when);

Вот это вот всё зачем?

esandmann
()
Ответ на: комментарий от crowbar

К этому добавляю в тело struct date *today = date_create (today->year, today->month, today->day); и получаю ошибку сегментирования.

steemandlinux ★★★★★
() автор топика

const int dayspermonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

28

нет.

anonymous
()

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

wakuwaku ★★★★
()
Ответ на: комментарий от anonymous

Я знаю, что функцию проверки leapyear писать надо.

steemandlinux ★★★★★
() автор топика
Ответ на: комментарий от steemandlinux

И что твоя проверка делает? Зачем там она? Если ты уже не используешь этот объект, делаешь на нем free, то не пофиг ли NULL там или не NULL (тем более, что free абсолютно пофиг).

К тому же assert вызывает abort при неудачном условии, так что зачем ронять программу на ровном месте? Напиши что-то в stderr, если так хочешь

esandmann
()
Ответ на: комментарий от steemandlinux

И что если твой указатель равен не NULL (что нормально), а 0xcafebabe?

esandmann
()
#include <stdlib.h>

typedef struct _DATE
{
  short year;
  char month;
  char day;

} DATE, *PDATE;

int main ()
{
  PDATE pDate = calloc(1, sizeof(struct _DATE));
  if (NULL == pDate)
    {
      return 1;
    }

  pDate->day = 27;
  pDate->month = 7;
  pDate->year = 2014;

  free(pDate);
  return 0;
}
Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от anonymous

вдруг он не может себе позволить пк для любой нормальной ide

anonymous
()
Ответ на: комментарий от esandmann

то не пофиг ли NULL там или не NULL (тем более, что free абсолютно пофиг).

Сейчас тебе расскажут какая разница между сишной ф-ей free() и сиплюсплюсным оператором delete.

nanoolinux ★★★★
()
Ответ на: комментарий от steemandlinux
#include <stdlib.h>
#include <stdio.h>

typedef struct _DATE
{
  short year;
  char month;
  char day;

} DATE, *PDATE;

int main ()
{
  PDATE date = calloc(1, sizeof(struct _DATE));
  if (NULL == date)
    {
      return 1;
    }

  scanf ("%4hi %2hhu %2hhu", &date->year, &date->month, &date->day);

  free(date);
  return 0;
}

anonymous

вдруг он не может себе позволить пк для любой нормальной ide

Если ты про венгерскую нотацию, то использую только для указателей (префикс 'p').

Deleted
()
Последнее исправление: Deleted (всего исправлений: 2)
Ответ на: комментарий от Deleted

Спасибо. Странно, только что самое писал, ругалось на тип переменных, а теперь нормально работает.

steemandlinux ★★★★★
() автор топика
Ответ на: комментарий от Deleted

ну ведь так короче, понятнее и красивее. зачем вообще объявлять тип указателя на структуру? звездочку сложно написать?

#include <stdlib.h>
#include <stdio.h>

typedef struct
{
  short year;
  char month;
  char day;

} DATE;

int main ()
{
  DATE *date = calloc(1, sizeof(DATE));
  if (NULL == date)
    {
      return 1;
    }

  scanf ("%4hi %2hhu %2hhu", &date->year, &date->month, &date->day);

  free(date);
  return 0;
}
anonymous
()
Ответ на: комментарий от anonymous

а еще лучше

DATE *date = calloc(1, sizeof *date);

anonymous
()
Ответ на: комментарий от esandmann

В контексте рассматриваемого вопроса это не имеет значение. Мой поинт в том, что говоря простым языком, скомпилируй free(NULL), запусти и удивись.

nanoolinux ★★★★
()
Последнее исправление: nanoolinux (всего исправлений: 1)
Ответ на: комментарий от Eddy_Em

что-то ты меня сподвиг поизвращаться. gcc/clang-only, зато прямо c++ look & feel.

#define new(t,s...) calloc(((size_t[]){0,##s,1})[1],sizeof(t))
int *counter = new(int);

double *readings = new(double, 128);
anonymous
()
Ответ на: комментарий от esandmann

Да нет. Ничего не будет. Я всё перепутал, бывает.

nanoolinux ★★★★
()
Ответ на: комментарий от nanoolinux

Кстати, да: я без макроса

#define FREE(x) do{free(x); x = NULL;}while(0)
никуда! Иначе есть шанс попытаться где-нибудь сделать double free.

Eddy_Em ☆☆☆☆☆
()

Кстати, про "dayspermonth": если ты не хочешь писать многостраничную простынь определения продолжительности месяцев в конкретном году, просто воспользуйся функциями libc!

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

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

esandmann
()
Ответ на: комментарий от esandmann

У меня эта привычка пошла после нескольких перезагрузок компьютера, когда на куде баловался: куда — она ж тупая, это в ядре есть проверка на всякие double free и memory corruption. В кудовском блобе — шиш! А возникающие забавные эффекты можно убрать только перезагрузкой.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от FIL

То, что можно сказать, инициализирован (+ аллоцирован) объект или нет.

esandmann
()
Ответ на: комментарий от Eddy_Em

Хм, драгонфлаевый kfree вроде небезопасный при передачи NULL.

esandmann
()
Ответ на: комментарий от anonymous

За typedef struct {..} XXX надо отрывать руки. Тебе struct лень написать? Зачем делать неявный код? Зачем скрывать struct за обычным именем? Зачем загрязнять глобальный namespace? Если бы создатели С хотели, чтобы struct-ы писались без struct, они бы просто так сделали по умолчанию, как страуструп сделал. Но они понимали, что лучше писать struct везде явно, чтобы читатели кода понимали, что это полновесная структура в пару сотен байтов.

Legioner ★★★★★
()
Ответ на: комментарий от esandmann

Не плевать ли, сколько там байтов?

Когда передаёшь в виде аргумента или возвращаешь в виде return value - не плевать. Лишнее копирование в С ни к чему.

Ну оторви руки тем, кто POSIX-совместимое окружение писал

В аду черти оторвут.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

Когда передаёшь в виде аргумента или возвращаешь в виде return value - не плевать

Никто же не мешает передавать указатели

esandmann
()
Ответ на: комментарий от Legioner

А что, С умеет передавать структуры через копирование? Не знал... Нафиг такое поведение?

А писать лишний раз struct — пусть индусы пишут. Я лучше 1 раз typedef сделаю!

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от sshvabodka

Не помню, с просто скобками тоже какая-то заподлянка была.

Eddy_Em ☆☆☆☆☆
()

malloc()

Царя внесли или нет?

EXL ★★★★★
()
Ответ на: комментарий от Legioner

начнём с того , что stuct изначальный был инструментом анализа для получения(интерпретации) некоторого смещения от известного указателя как значения некоторого типа.

поэтому и -> есть как отдельная конструкция

ну и имена полей были изначально общим пространством имён

что позволяло

struct {int a};struct{double b};struct{int (*f)()}

*p;

p->a;

p->b;

p->f();

qulinxao ★★☆
()
Ответ на: комментарий от Eddy_Em

никуда! Иначе есть шанс попытаться где-нибудь сделать double

Не проще использовать статические анализаторы кода?

λ> cppcheck fofofo.c
Checking fofofo.c...
[fofofo.c:23]: (error) Deallocating a deallocated pointer: bar
[fofofo.c:23]: (error) Memory pointed to by 'bar' is freed twice.

p.s. А то костыльный какой-то подход, в стиле «наляпаю везде, а ну и черт с ним, оно все-равно два раза не освободится».

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Deleted

Не проще использовать статические анализаторы кода?

Ты прямо какие-то сказки рассказываешь! Давай еще мне про gdb и valgrind расскажи!!!

Не использовал, не использую и не буду использовать (надеюсь) никогда! Потому что я — не погромист никакой!

Eddy_Em ☆☆☆☆☆
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.