Char x [256] против char * = malloc (256 * sizeof (char));
Кто-то здесь недавно указал мне в куске кода, который я использую
char* name = malloc(256*sizeof(char));
// more code
free(name);
У меня создалось впечатление, что этот способ настройки массива был идентичен использованию
char name[256];
и что для обоих способов потребуется использование free(). Я ошибаюсь, и если да, то может кто-нибудь объяснить на низком уровне, какая разница?
Ответы
Ответ 1
В первом коде память динамически выделяется в куче. Эта память должна быть освобождена с помощью free(). Его время жизни произвольное: оно может пересекать границы функций и т.д.
Во втором коде 256 байтов выделяются в стеке и автоматически возвращаются, когда функция возвращается (или при завершении программы, если она находится вне всех функций). Поэтому вам не нужно (и не может) называть free() на нем. Он не может протекать, но он также не будет жить за пределами функции.
Выберите один из двух в зависимости от требований к памяти.
Добавление (Pax):
Если я могу добавить к этому, Ned, большинство реализаций, как правило, предоставляют больше кучи, чем стек (по крайней мере, по умолчанию). Это обычно не имеет значения для 256 байтов, если у вас уже не закончилось стека или не было сильно рекурсивно.
Кроме того, sizeof (char) всегда 1 в соответствии со стандартом, поэтому вам не нужно, чтобы избыточное умножение. Несмотря на то, что компилятор, вероятно, оптимизирует его, он делает код уродливым IMNSHO.
Конечное дополнение (Pax).
Ответ 2
и что для обоих способов потребуется использование free().
Нет, только первое нужно использовать бесплатно. Второе выделено в стеке. Это делает его невероятно быстрым. Смотрите здесь:
void doit() {
/* ... */
/* SP += 10 * sizeof(int) */
int a[10];
/* ... (using a) */
} /* SP -= 10 */
Когда вы его создаете, компилятор во время компиляции знает свой размер и выделяет для него правильный размер в стеке. Стек представляет собой большой кусок непрерывной памяти, расположенной где-то. Помещение чего-то в стек будет просто увеличивать (или уменьшать в зависимости от вашей платформы) стек-указатель. Выход из области действия будет обратным, и ваш массив будет освобожден. Это произойдет автоматически. Поэтому переменные, созданные таким образом, имеют автоматическую продолжительность хранения.
Использование malloc отличается. Он будет заказывать некоторый произвольный большой кусок памяти (из места, называемого freestore). Среда выполнения должна будет искать достаточно большой блок памяти. Размер может быть определен во время выполнения, поэтому компилятор обычно не может оптимизировать его во время компиляции. Поскольку указатель может выйти из области видимости или быть скопирован, нет никакой неотъемлемой связи между выделенной памятью и указателем, которому назначен адрес памяти, поэтому память все еще выделена, даже если вы давно оставили функцию, Вы должны позвонить бесплатно, передав ему адрес, который вы получили из malloc вручную, если настало время сделать это.
Некоторая "недавняя" форма C, называемая C99, позволяет предоставить массивы размер времени выполнения. Вам разрешено делать:
void doit(int n) {
int a[n]; // allocate n * sizeof(int) size on the stack */
}
Но эту функцию следует избегать, если у вас нет причины ее использовать. Одна из причин заключается в том, что он не защищен от сбоев: если память больше не доступна, все может произойти. Другим является то, что C99 не очень переносима среди компиляторов.
Ответ 3
Здесь существует третья возможность, которая заключается в том, что массив может быть объявлен внешним по отношению к функции, но статически, например,
// file foo.c
char name[256];
int foo() {
// do something here.
}
Я был довольно удивлен ответами на другой вопрос о том, что кто-то считает, что это не подходит для C; здесь он даже не упоминается, и я немного смущен и удивлен (например, "чему они учат детей в школе в эти дни?" ) об этом.
Если вы используете это определение, память распределяется статически, ни в куче, ни в стеке, а в пространстве данных на изображении. Таким образом, ни одно из них не должно управляться, как с помощью malloc/free, и вам не нужно беспокоиться о том, что адрес повторно используется, как вы бы с автоматическим определением.
Полезно вспомнить здесь всю "объявленную" и "определенную" вещь. Вот пример
/* example.c */
char buf1[256] ; /* declared extern, defined in data space */
static char buf2[256] ; /* declared static, defined in data space */
char * buf3 ; /* declared extern, defined one ptr in data space */
int example(int c) { /* c declared here, defined on stack */
char buf4[256] ; /* declared here, defined on stack */
char * buf5 = malloc(256)] /* pointer declared here, defined on stack */
/* and buf4 is address of 256 bytes alloc'd on heap */
buf3 = malloc(256); /* now buf3 contains address of 256 more bytes on heap */
return 0; /* stack unwound; buf4 and buf5 lost. */
/* NOTICE buf4 memory on heap still allocated */
/* so this leaks 256 bytes of memory */
}
Теперь в целом другом файле
/* example2.c */
extern char buf1[]; /* gets the SAME chunk of memory as from example.c */
static char buf2[256]; /* DIFFERENT 256 char buffer than example.c */
extern char * buf3 ; /* Same pointer as from example.c */
void undoes() {
free(buf3); /* this will work as long as example() called first */
return ;
}
Ответ 4
Это неверно - объявление массива не требует свободного доступа. Кроме того, если он находится внутри функции, он выделяется в стеке (если память обслуживается) и автоматически освобождается с возвратом функции - не передавайте ссылку на нее обратно вызывающему абоненту!
Ответ 5
Разделите ваше выражение
char* name = malloc(256*sizeof(char)); // one statement
char *name; // Step 1 declare pointer to character
name = malloc(256*sizeof(char)); // assign address to pointer of memory from heap
name[2]; // access 3rd item in array
*(name+2); // access 3rd item in array
name++; // move name to item 1
Перевод: имя теперь является указателем на символ, которому присваивается адрес некоторой памяти в куче
char name[256]; // declare an array on the stack
name++; // error name is a constant pointer
*(name+2); // access 3rd item in array
name[2]; // access 3rd item in array
char *p = name;
p[2]; // access 3rd item in array
*(p+2); // access 3rd item in array
p++; // move p to item 1
p[0]; // item 1 in array
Перевод: Имя является постоянным указателем на символ, который указывает на некоторую память в стеке
В C массивах и указателях одно и то же. Массивы являются постоянными указателями на память. Основное различие заключается в том, что когда вы вызываете malloc, вы берете память из кучи, и любая память, взятая из кучи, должна быть освобождена от кучи. Когда вы объявляете массив с размером, ему присваивается память из стека. Вы не можете освободить эту память, потому что бесплатно освобождается память из кучи. Память в стеке будет автоматически освобождена при возврате текущего программного модуля. Во втором примере также будет ошибка (p). p - указатель на массив имен в стеке. Таким образом, освобождая p, вы пытаетесь освободить память в стеке.
Это не отличается от:
int n = 10;
int *p = &n;
освобождение p в этом случае будет ошибкой, потому что p указывает на n, которое является переменной в стеке. Поэтому p хранит ячейку памяти в стеке и не может быть освобожден.
int *p = (int *) malloc(sizeof(int));
*p = 10;
free(p);
в этом случае свободен правильно, потому что p указывает на ячейку памяти в куче, которая была назначена malloc.
Ответ 6
в зависимости от того, где вы выполняете это, пространство стека может быть огромным. Если, например, вы пишете код BREW для телефонов Verizon/Alltel, вы, как правило, ограничены минимальными стеками, но всегда увеличиваете доступ к куче.
Кроме того, поскольку char [] чаще всего используются для строк, это не плохая идея, позволяющая методу построения строки выделять нужную ему память для рассматриваемой строки, а не надеяться, что навсегда и всегда 256 (или какой бы номер вы ни указали) будет достаточно.