Страницы

Поиск по вопросам

понедельник, 25 марта 2019 г.

Как узнать, когда нужно удалять память?

char * buf = (char*) malloc (PWD_BUF_SIZE * sizeof (char)); buf = getcwd (buf, PWD_BUF_SIZE); ... free(buf); Удалили память, потому что выделили. char * buf = getcwd(NULL, PWD_BUF_SIZE); ... free(buf) Удалили память, но на этот раз мы не выделяли. char f[] = "/home/user/1.txt"; char * b = basename(f); ... free(b); // привело к ошибке. Почему последний вариант привел к ошибке? Чтобы лучше понять, нужно реализовать функцию basename. Как? Если представим, что внутри ее выделяется память через alloca, то внутри функции она должна была бы освободится. То есть я хочу понять, когда освобождать память, и научится создавать функции такого типа как basename, которые возвращают указатель на память, которую не нужно удалять. С первыми двумя примерами все понятно. Если мы передает NULL, то память выделяется автоматически размером PWD_BUF_SIZE.


Ответ

@andrey1, освобождать (free()) можно только ту память, которая получена в результате malloc()/calloc()/realloc() (или функций, которые возвращают результат вызова malloc/calloc/realloc). Обратите внимание, в free нельзя передавать адрес откуда-то из середины выделенного блока (только начальный адрес) и нельзя передавать его более одного раза. Конечно, я говорю о стандартной (общепринятой) их реализации. В принципе же вполне можно представить аллокатор, хранящий адреса и размеры всех выделенных блоков, (например в rb-tree), который позволяет удалять "хвосты" (и даже расщеплять ранее выделенный блок) и безболезненно реагирует на realloc/free по неправильным адресам. Расплатой за возможность таких "вольностей" будет потеря эффективности. По поводу dirname() и basename(). Думаю, тривиальный примерчик (с печатью адресов) все ставит на свои места: #include #include #include #include
int main (int ac, char *av[]) { char *s = "/usr/lib/", *p = strdup(s), *d = dirname(p), *b = basename(p); printf ("s = %p\t[%s]
" "p = %p\t[%s]
" "d = %p\t[%s]
" "b = %p\t[%s]
", s, s, p, p, d, d, b, b);
char *q = strdup(s), *n = basename(q); printf ("q = %p\t[%s]
" "n = %p\t[%s]
", q, q, n, n);
free(p); // or free(d); free(q);
return 0; } Результат запуска: avp@avp-ubu1:hashcode$ gcc c.c avp@avp-ubu1:hashcode$ ./a.out s = 0x4007d8 [/usr/lib/] p = 0x242b010 [/usr] d = 0x242b010 [/usr] b = 0x242b011 [usr] q = 0x242b030 [/usr/lib] n = 0x242b035 [lib] avp@avp-ubu1:hashcode$ Тут становится очевидно, что uname -a Linux avp-ubu1 3.13.0-34-generic #60-Ubuntu SMP Wed Aug 13 15:45:27 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux эти функции меняют переданный аргумент (ставят нули) "по месту" (никакого копирования).

Комментариев нет:

Отправить комментарий