Есть ли разница в следующем распределении памяти? - PullRequest
0 голосов
/ 07 августа 2009

Существует четыре способа динамического выделения памяти, есть ли различия между четырьмя способами? сначала так:

char *seq=(char *)malloc(100*sizeof(char));
void exam(char *seq){
    // using 'seq'
}

секунда, как это:

char *seq;
void exam(char *seq){
    seq=(char *)malloc(100*sizeof(char));
    // using 'seq'
}

третий такой:

char *seq=(char *)malloc(10*sizeof(char));
void exam(char *seq){
    char *change=(char *)malloc(100*sizeof(char));
    free(seq);
    seq=change;
    // using 'seq'
}

четвертый как этот:

char *seq=(char *)malloc(100*sizeof(char));
void exam(char *seq){
    free(seq);
    seq=(char *)malloc(100*sizeof(char));
    //using 'seq'
}

и вы должны знать, что Я буду использовать переменную 'seq' вне метода 'exam'. пожалуйста, объясните приведенные выше коды, большое спасибо.

Ответы [ 6 ]

2 голосов
/ 07 августа 2009

Действителен только первый случай, если вы собираетесь использовать seq вне экзамена.

Три других случая получают адрес, выделенный для seq, но не могут его изменить.

Чтобы изменить значение seq, вам нужно либо вернуть ему новое значение, либо явно изменить то, что в seq.

Вам нужно изучить Pass by Value, чтобы понять, почему это не работает. См. эту страницу .

1 голос
/ 07 августа 2009

Вы не должны приводить результат malloc (), если вы не используете реализацию C, которая предшествует стандарту ANSI 1989 года, или вы не собираетесь компилировать этот код как C ++, и в этом случае вы должны использовать new вместо malloc (); во-первых, в этом нет необходимости, а во-вторых, он будет маскировать диагностику компилятора, если у вас нет прототипа для malloc () в области видимости.

Кроме того, sizeof (char) равен 1 по определению; использование его в этом случае не имеет значения и просто добавляет визуальный шум.

Каноническая форма для записи оператора malloc () для любого типа T:

T *p = malloc(count * sizeof *p);

или

T *p;
...
p = malloc(count * sizeof *p);

Теперь рассмотрим ваши четыре дела ...

Ваш первый случай, как правило, правильный; Вы выделяете память для seq вне экзамена и передаете указатель по значению.

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

char *seq;
exam(&seq);
...
void exam(char **seq) { *seq = malloc(100); ... }

Если вы хотите изменить размер динамически выделяемого буфера, используйте realloc ():

char *seq = malloc(10);
exam(&seq);
...
void exam(char **seq) 
{
  char *tmp = realloc(*seq, 100);
  if (!tmp) 
  {
    /* realloc failed */
  }
  else
  {
    *seq = tmp;
    ...
  }

Обратите внимание, что

char *p = realloc(NULL, 10);

совпадает с

char *p = malloc(10);
1 голос
/ 07 августа 2009

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

У других методов у вас есть другие проблемы, если вы собираетесь использовать seq после вызова функции. Поскольку C передается по значению, вы передаете адрес, содержащийся в seq, подпрограмме, которая не изменит расположение памяти, связанное с seq, в последних трех примерах. Чтобы изменить расположение в памяти seq, вам нужно передать адрес указателя в подпрограмму для установки указателя. Это показано на примере Дэвида Курнапо.

Проблема с двумя последними случаями заключается в том, что вы «освободили» память, но вы все еще сохраняете указатель на память, поскольку значение seq не изменится, и вы можете использовать его для доступа к памяти, которую вы «освободили» ». Это известный висячий указатель.

Предложение Дэвида Курнапо об использовании функции для возврата указателя даст вам доступ к памяти, выделенной вам в функции. В противном случае вам нужно будет передать адрес seq в подпрограмму и разыменовать значение, чтобы установить его в выделенном пространстве.

1 голос
/ 07 августа 2009

Все зависит от того, что вы пытаетесь сделать. Если возможно, лучше сделать malloc / free в той же области, IMO, это делает код намного более читабельным - выделение памяти в C уже достаточно сложно. В вашем случае вы должны сначала выполнить malloc, вызвать функцию и освободиться после выхода за пределы функции. Но, конечно, это не всегда возможно.

Некоторые из ваших решений не будут работать: второе, например, не будет выполнять то, что вы хотите, потому что при вызове функции указатель копируется :

char *p;
function(p);

void function(char *q) {
    // q is a copy of p, so when q is set by malloc, it will not be reflected in p
    q = malloc(100);
}

Как правило, вы должны выполнять функции fopen: вы возвращаете указатель:

char* p function() {
    char* ret;
    ret = malloc(100);
    return ret;
}

char *p = function();

Или вы можете использовать указатель на указатель:

char *p;
function(&p);

void function(char **q) {
    // q is a copy of &p, so when *q is set by malloc, it is the same memory location as &p
    *q = malloc(100);
}

Я думаю, что первый намного лучше, хотя, в целом.

Кроме того, что касается вашего стиля: sizeof (char) бесполезен, он всегда равен 1 по определению, независимо от того, какой компилятор / платформа вы используете, и приведение malloc бесполезно и действительно опасно (потому что оно скрывает отсутствие включения заголовка, где malloc объявлен). Это полезно, только если вы используете malloc в C ++ (где приведение является обязательным).

0 голосов
/ 07 августа 2009

Чтобы пролить свет на ситуацию, рассмотрим переписывание:

char *seq=(char *)malloc(100*sizeof(char));
void exam(char *var){
    // using 'var'
}
//--
char *seq;
void exam(char *var){
    var=(char *)malloc(100*sizeof(char));
    // using 'var'
}
//--
char *seq=(char *)malloc(10*sizeof(char));
void exam(char *var){
    char *change=(char *)malloc(100*sizeof(char));
    free(var);
    var=change;
    // using 'var'
}
//--
char *seq=(char *)malloc(100*sizeof(char));
void exam(char *var){
    free(var);
    var=(char *)malloc(100*sizeof(char));
    //using 'var'
}

Когда вы звоните

exam(seq);

вышеуказанные версии идентичны вашим оригиналам.

0 голосов
/ 07 августа 2009

Я думаю, что это различия в объеме

...