C - Деклариране на променливи и извикване на malloc

Не разбирам защо трябва да правиш и двете. Malloc не създава ли динамична памет за вас? Тогава защо трябва да посочваме например "int" в началото, когато по-късно ще преобразувам тази променлива. Нов съм в malloc, съжалявам, ако този въпрос има очевиден отговор.

Пример:

В основното:

int *p;

След това по-късно във функцията:

int *p = malloc(1000 * sizeof(int));

person user3753834    schedule 08.08.2014    source източник
comment
Malloc се използва с указатели, защото те сочат (както казва името) към някакъв обект в паметта. За да съхраните някаква нова стойност в указател, трябва да разпределите (резервирате) памет за него.   -  person Igor    schedule 08.08.2014
comment
malloc често се използва за масиви с неизвестен размер   -  person Drew McGowen    schedule 08.08.2014
comment
Но защо имам две места в паметта за това int? Веднъж в int декларирах преди и след това в malloc   -  person user3753834    schedule 08.08.2014
comment
Не можете да зададете malloc на променлива, защото променливата има име. Винаги правете ясна разлика между обект, указател към обект и (незадължително) име на обект.   -  person Deduplicator    schedule 08.08.2014
comment
Кодът във въпроса не се компилира. Имате две декларации на p, което е една твърде много. Вие правите живота си ненужно труден, като разкривате само малки откъси от вашия код. Ако можете да успеете да покажете пълна функция, животът ни би бил по-лесен.   -  person David Heffernan    schedule 08.08.2014


Отговори (4)


Malloc не създава ли динамична памет за вас?

Това го прави. Трябва обаче да можете да задържите някъде и адреса на тази памет.

int *ptr = malloc(1000 * sizeof(int));
...
free(ptr); // Once you are done, you need to release the memory by calling free

Адресът се съхранява в указател ptr, който се нуждае от малко количество памет, за да бъде съхранен. Вие използвате този указател, за да посочите паметта, която сте разпределили.

person Sergey Kalinichenko    schedule 08.08.2014
comment
Трябва да се отбележи, че free трябва да се извика на ptr, за да се предотврати изтичане на памет. - person Fiddling Bits; 08.08.2014
comment
Така че, основно int, деклариран в началото, съдържа малкото памет, която указателят изисква. - person user3753834; 08.08.2014
comment
Той съдържа паметта, необходима, за да може указателят да бъде съхранен някъде. - person Igor; 08.08.2014
comment
@user3753834 ptr не е int, а int*. Звездичката обозначава указател, докато int предоставя типа на елемента, към който сочи този указател. Указателите заемат малко памет. Този размер не зависи от размера на частта памет, към която сочат. Прилична аналогия би била намирането на пасаж в книга: без значение колко голяма е книгата, малко място, необходимо за запис на страницата, реда и номера на знака, е достатъчно, за да се запише местоположението на всеки пасаж. Показалецът също може да се счита за много кратък пасаж, така че се нуждае от малко място за съхранение. - person Sergey Kalinichenko; 08.08.2014
comment
Направих редакция на въпроса по-горе, за да стане по-ясно. Това бяха двата int, които също имах предвид. Това, което питах, защо имам нужда от два указателя int, които могат да се видят в main и в другата функция. - person user3753834; 08.08.2014
comment
@user3753834 Първият int *p е декларация на указател без инициализация. Той отделя място за показалеца, но показалецът не сочи към нищо. Втората декларация има инициализация. Имайте предвид, че извършването на двете декларации в една и съща функция няма да се компилира, защото името p се декларира отново. - person Sergey Kalinichenko; 08.08.2014

Има голяма разлика между следните две определения:

int i;
int *pI;

i и int. Има място в паметта, в което можете да запишете стойност.

pI обаче не е int. Това е указател към int. Стойността му е адрес. Не можете да запишете стойност в мястото на паметта, към което сочи, докато не го посочите на валидно място в паметта, достатъчно голямо, за да побере int. Например:

pI = &i;
*pI = 10;

Можете да създадете общ указател, като използвате ключовата дума void, но не можете да дереферирате void указател. Компилаторът трябва да знае типа дата, за да дереферира указател.

int i;
void *pV;

pV = &i;
*(int *)pV = 10;
person Fiddling Bits    schedule 08.08.2014

Ако декларирате int *p в main и отново във функция, тогава имате два указателя с различни обхвати, p in функцията е в обхват само когато функцията е въведена и става неуместна, когато функцията се върне, освен ако вашата функция не върне адреса на p на функцията към main.

person crypticfool    schedule 10.08.2014
comment
Ако се върне адресът на p на функцията, той трябва да бъде static или дереферирането му е невалидно. - person Fiddling Bits; 10.08.2014
comment
Вярно е, че указателят е в стека и malloc във функцията е в купчината, но указателят ще бъде невалиден при връщане на функцията, затова не декларирам указатели във функциите, вместо това ги предавам на функции, по-безопасна работа с масиви. - person crypticfool; 11.08.2014

В конкретния случай на int вероятно не искате да създавате динамично пространство в паметта. Бихте искали да направите това само когато не знаете най-лошия сценарий за използването на вашата памет.

Би било съвсем различна история, ако създадете int указател. Повече информация можете да намерите в тази публикация

person Funonly    schedule 08.08.2014
comment
Възможно е да декларирате структура или масив без malloc. Освен това е също толкова валидно да използвате malloc за примитивен тип. - person Drew McGowen; 08.08.2014