2009-11-06 1 views
1
char *a() { 
    char *t = malloc(8); 
    t[0] = 'a'; 
    t[1] = 'b'; 
    //... 
    t[7] = 'h'; 
    return t; 
} 

int main(void) { 
    char *x = a(); 
    //do something with x 
    //... 
    free(x); 
    return 0; 
} 

Имеет ли этот код какие-либо потенциальные проблемы, так как память выделена в a() и использована память в main()?Является ли это использование C-указателей безопасным от утечки памяти?

ответ

0

Нет, у вас не будет проблем, потому что вы назначили функцию в a и используете ее в main.

1

Никаких проблем — на самом деле, это не правильный способ выделить память, которая по-прежнему будет использоваться после того, как функция возвращает — но вы можете free() память, когда вы закончите его использования. Восемь байтов не будут проблемой, но кодирование против утечек памяти - хорошая привычка.

+1

+1, даже если вы пропустили проблему возврата значений из 'void a()' (я почти пропустил это тоже, и @Ed победил всех нас на удар). –

+0

Ack - хороший улов! –

0

Пока вы не забываете освободить память, на которую указывает x, тогда у вас не будет никаких проблем. Используя malloc(), вы выделили память в куче, которая остается одна, когда возвращается к вызывающей функции.

10

Во-первых, a() объявляется возвращающим void, но вы пытаетесь вернуть char *. Измените подпись, чтобы вернуть char *.

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

В-третьих, как указал gbrandt, вы не проверяете успех после вызова malloc. malloc может потерпеть неудачу, и проверить, действительно ли это - хорошая привычка.


Другой способ сделать это было бы передать указатель на указатель в() вместо, а затем вызывающий должен создать указатель себя перед передачей его к(), но в любом случае вы по-прежнему необходимо освободить память. Если честно, я бы пошел с вашим подходом к этому в этом случае. Нет никаких веских оснований для этого, просто подумал, что я бы сказал об этом.

void a(char **p) 
{ 
    *p = malloc(8); 
    if (*p) 
    { 
     **p[0] = 'a'; 
     **p[1] = 'b'; 
     ... 
     **p[7] = 'h'; 
    } 
} 

int main(void) 
{ 
    char *x; 
    a(&x); 
    //do something with x 
    ..... 
    free(x); 
} 

Если этот альтернативный подход путает вас, пожалуйста, дайте мне знать, как я был бы счастлив дать объяснение (хотя, на данный момент, мне нужно, чтобы вернуться к работе!)

+1

+1 для избиения меня до удара с возвратом из функции 'void', но серьезно, почему бы просто не вернуть' char'''? Было бы намного проще (и меньше смущать кого-то нового для C, как я подозреваю, что OP может быть). –

+0

Да, я не был уверен, что я должен включить эту часть вообще. Я отредактировал сообщение, чтобы сказать, что оригинальный способ в порядке, и вот альтернативный способ сделать то же самое. –

1

Помимо того, неправильный тип возврата на a() (должен быть char * вместо void), код не вызывает проблем.

Обязательно укажите free() память, которую вы выделили, когда закончите с ней.

3

Весь хороший совет выше. Небольшие проблемы с кодом, большой ...

Вы не проверяете успех в malloc или после вызова функции. Никогда не забывайте об обработке ошибок.

+0

+1, потому что я также забыл об обработке ошибок. –

+0

Фактически там * есть * некоторая проблема с кодом (неправильный тип возврата), но +1 для проверки памяти malloc'ed. – Francesco

+0

+1, потому что я также забыл проверить, какой malloc вернулся. –

1

Большинство ответов здесь указывает, что это не проблема, просто забудьте освободить() позже. Это технически верно, но это действительно проблема. Каждый раз, когда вы выделяете память в одной области и ожидаете ее освобождения в другой, вы просите утечку памяти. Люди не помнят, чтобы освободить память. Также возникает проблема, что вызывающий должен знать, что вы использовали malloc, а не alloca() или new() или что-то еще. Если они вызывают что-либо, кроме согласованной процедуры дезадаптации, результаты не определены.

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

Лучше ожидать, что память будет выделена вызывающим абонентом, потому что, если они ее распределяют, они не забудут освободить ее и сделать это правильно.

+2

Это не проблема с кодом OP, это проблема с пользователями (воображаемыми) кода OP. Если вы программист на C, вы помните 'free()' memory. Период. Любой, кто не понимает управление памятью и не читает документацию о том, какая память им нужна для 'free()', когда они сделаны, не знает C. –

+1

Да, я согласен с Крисом. Это C, а не C++. –

+0

@Ed - Ouch. Это довольно жестко для программистов на С ++. Не сказать, что это не обязательно так ... –

0

Спасибо. Я только что редактировал код. Думаю, на этот раз у него не должно возникнуть проблемы. Btw, в C, когда функция заканчивается, компилятор очищает все переменные (включая массив & указатель) в стеке?

+0

Если это локальная переменная в функции, она исчезнет из стека, когда функция вернется. Но если вы выделили его в кучу (ala malloc() или такой), хотя указатель, указывающий на него, будет потерян с фреймом стека, выделенная память будет сохраняться, если вы не освободили() перед возвратом. Конечно, в этом примере, поскольку вы возвращаете указатель на него, вызывающая функция может хранить дескриптор в памяти. –