Loading...
fristgerb avatar fristgerb 50 Точки

[Homework] C Pointers

Здравейте! :)

Това е моето домашно за C Pointers - всички задачи. Надявам се да ви е от полза: http://www.libtec.org/dev/softuni/09-pointers/

С Mercurial може да изтегляте всички мои домашни, примерно през терминал с комндата:

hg clone http://www.libtec.org/dev/softuni/
Тагове:
2
C Programming 27/10/2015 22:59:10
itonev avatar itonev 22 Точки

Всъщност  fristgerb  искаше ми се да изкоментирам нещо във връзка с твоя код.

Смятам, че пишеш качествен код.

Мисля, че си и по-добър от мен. 

Но наистина ми е чудно защо така инклудваш  "c"  файл ?

Инклудват се хедъри. Компилаторът сам ще си намери  "c"  файл-ът.

Та, ако може да ми обясниш каква е целта на тая практика ?

 

0
fristgerb avatar fristgerb 50 Точки

Извинявай, че малко се забавих с отговора.

Правя го така, защото иначе е излишен труд. :)

Така не пиша излишно декларациите на функциите по два пъти (.c и .h) и не трябва да ги синхронизирам файловете когато правя нови функции или редактирам стари.  Същевременно нямам никаква полза да е разделено на два файла.

Като цяло смятам, че в повечето случаи ползването на header файла и предеклариране на функции (прототипи) е безсмислено, вредно и не помага изобщо.  Губи се време в излишно писане и кодът става ненужно по-дълъг и по-трудено за разбиране.  Файловете също стават двойно повече от нужното.

В някои случаи наистина трябва да се правят тези неща, когато няма как иначе.  Примерно, когато имаш две функции, които се извикват помежду си, тогава е нужно да се предекларират тези функции.  Хедър файлове може да са нужни когато искаш част от програмата да се компилира отделно от друга, примерно за да ползваш различни настройки за комплиране за отделните части.

Някои хора разделят на .c и .h за да не компилират всичкия код едновременно, като оптимизация на компилирането, но при повечето програми нещата не се забързват значително и съответно няма полза от това.  От друга страна, като бонус, директно иклудването на .c файлове и компилирането на всичко като едно позволява на компилатора да inline-ва повече функциите, което оптимизира изпълняването на програмата.

Компилаторът сам ще си намери  "c"  файл-ът.

Компилаторът не намира автоматично .c файла.  Трябва да му казваш да компилира .c файла и да линква резултата към основната програма.

Инклудват се хедъри.

Мисля, че повечето хора препоръчват да се правят винаги .c и .h файлове, защото правят нещата наизуст, за да се презастраховат или просто защото "така се прави".  Но смятам, че е много по-разумно да се прави нещо само когато се виждаш, че има полза от него в конкретния случай.

Сходно ми е мнението и за освобождаването на заделена памет с (free()) преди края на програмата.  Абсолютна загуба на време, както за програмиста така и за процесора.  Хората го правят наизуст без никаква логика, просто защото "така се прави".  Освобождаването на памет трябва да се прави само когато конкретния случай го изисква.

1
03/11/2015 19:42:20
itonev avatar itonev 22 Точки

O, да коригирам се затова, че компилаторът си намирал сам файл. Малко си скъсих така мисълта, че чак я измених.  :) Сам ще си намери дефиницията на  функцията във "c"  файла  стига да му го укажеш, да. Иначе настрана от това, разбрах твоите аргументи относно инклудването

За free -ването си има доста логика. 

Щото случая е аналогичен като при викане на  exit();

Разбира се,  така няма да ти се валидира на  Valgrind

Но кои са според теб онези важни случаи на изрично викане на  free ?

Например когато във функция  преалокираш, виждаш че преалокирането е неуспешно и преди да върнеш  NULL   от функцията зачистваш поинтера, който не е могъл да бъде реалокнат (по каквито и да е причини), но преди това успешно е бил malloc-nat .

1
fristgerb avatar fristgerb 50 Точки

Щото случая е аналогичен като при викане на exit();

Не разбирам какво имаш предвид.

Но кои са според теб онези важни случаи на изрично викане на free ?

Например когато във функция преалокираш, виждаш че преалокирането е неуспешно и преди да върнеш NULL от функцията зачистваш поинтера, който не е могъл да бъде реалокнат (по каквито и да е причини), но преди това успешно е бил malloc-nat .

Типично няма смисъл да викаш free в такава ситуация. Обикновено в една практическа програма, ако не успееш да malloc-неш или realloc-неш, единственото следващо нещо което може да направиш е да прекратиш програмата. Ако трябва да прекратиш, това означава, че няма смисъл да правиш free.

Случаите в които има смисъл от free общо взето стават ясни, когато се сблъскаш с тях, стига да разбираш какво се случва на ниво операционна система, когато правиш free, malloc и realloc.

Примерен случай когато може да ти трябва free е когато многократно заделяш (и използваш) много памет и има опасност да попречиш на системата и на другите програми да работят добре. Да кажем, ако заделяш и си използвал над 100 MB памет или нещо такова. Колкото точно е "много памет" зависи много от това каква програма правиш, колкото дълго ще работи тя и на какви системи ще работи.

Друг примерен случай е, когато правиш програма, която работи дълго без да спира и постоянно заделяш памет с malloc. Да кажем, ако програмираш текстов редактор.

Между другото, няма значение колко памет заделяш с malloc или подобни, а е важно единствено колко информация си записал върху заделената памет. Операционните системи са достатъчно умни. Може да си malloc-неш и цялата RAM ако искаш, но частта върху която не си записвал операционната система знае, че е свободна.

На уроците учим как да правим read_line() функция в която malloc-ваш и realloc-ваш многократно, така че да "пести" колкото може повече памет, но това е подвеждащо. Всъщност не се случва никакво пестене, а точно обратното - губи се процесорно време без да се пести памет. Ако си записвал само върху първите 64 байта в дадена памет, използваната памет си е все толкова, без значение дали си malloc-нал 1 GB или си malloc/realloc-нал така, че да е точно 64 байта.

Друг е въпросът, че Valgrind ще се оплаче, а на изпита ще те скъсат понеже не правиш излишните malloc, realloc и free повиквания. Това е бъг в типичното преподаване на C и C++, и той засяга включително и този курс.

1
03/11/2015 21:35:46
itonev avatar itonev 22 Точки

По тази логика излиза, че напракика в нашите случаи никога реално няма да се наложи да  free-ваме.

И  free e за много тежки случай , така да се каже :)

1
fristgerb avatar fristgerb 50 Точки

Да, досега не съм видял задача в курса при която да има практическа полза от free. :)

По-скоро free е за доста конректни случаи, a не винаги когато е направен malloc мислейки, че е „добра практика“. Същото важи за fclose() и close().

1
04/11/2015 13:03:21
a_rusenov avatar a_rusenov 1103 Точки

Прав си, че от практическа гледна точка няма полза от free(), когато програмта веднага свършва и OS зачиства паметта. Това сме го споменавали.

Но както сам казваш при long-running програми зачистването е просто задължително. Такива програми са извън рамките на курса, а ние учим само практитите, затова и на моменти може да изглеждат извън контекст. Но е всеобща добра практика да се зачистват ръчно заделени ресурси, било то heap memory или файлове, сокети и т.н. Нищо не губиш, ако извикваш free(). Същото нещо важи и за fclose(). 

Ако искаш да се възползваш от заделянето на огромна памет и да пестиш realloc - давай. Но не всички компютри ползват виртуална памет (напр. embedded системи). От практична гледна точка много по-добре е да имаш навика да заделяш правилното количество памет и да я освобождаваш, а когато не е нужно - да си спестиш тези действия. А не обратното.

Накратко, съгласен съм с казанато от теб, но не съм съгласен, че така трябва да се учи човек.

А относно хедър файловете - основното им предимство е, че при промяна на 1 сорс файл в голям проект, не се налага да прекомпилираш всичко, a само променения файл (понеже останалите файлове го ползват през неговия .h файл).

1
04/11/2015 16:03:50
HPetrov avatar HPetrov 822 Точки

Има едни общоприети правила от сорта на "ползвай колкото ти трябва" и "затваряй каквото си отворил ти" (като последното се отнася повече за streams) което в случая може да се преведе на "освобождавай това, което не ти трябва". Да, можем да си заделим 1гб памет и да си мажем на воля но това не ни прави по-добри. Даже напротив - това те подвежда все повече и повече към лоши практики и на края нивото ти спада без да се усетиш. Когато програмираш за embedded systems не те боли толкова дали процесора трябва да пусне 1 инструкция повече отколкото с каква памет работиш и правилното менажиране. В крайна сметка правилните практики са такива по причина, и те ни правят по-добри програмисти ;)

0
Можем ли да използваме бисквитки?
Ние използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Можете да се съгласите с всички или част от тях.
Назад
Функционални
Използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Използваме „сесийни“ бисквитки, за да Ви идентифицираме временно. Те се пазят само по време на активната употреба на услугите ни. След излизане от приложението, затваряне на браузъра или мобилното устройство, данните се трият. Използваме бисквитки, за да предоставим опцията „Запомни Ме“, която Ви позволява да използвате нашите услуги без да предоставяте потребителско име и парола. Допълнително е възможно да използваме бисквитки за да съхраняваме различни малки настройки, като избор на езика, позиции на менюта и персонализирано съдържание. Използваме бисквитки и за измерване на маркетинговите ни усилия.
Рекламни
Използваме бисквитки, за да измерваме маркетинг ефективността ни, броене на посещения, както и за проследяването дали дадено електронно писмо е било отворено.