views:

226

answers:

6

There are four ways to dynamic allocate memory, is there differences among the four ways? first like this:

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

second like this:

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

third like this:

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

fourth like this:

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

and you should konw that, I will use the variable 'seq' outside of the method 'exam'. please explain the above codes, thank you very much.

A: 

I think these are differences in scope

DroidIn.net
+2  A: 

Only the first case is valid if you intend to use seq outside of exam.

The other three cases receive the address allocated for seq, but are unable to change it.

To change the value of seq, you need to either return a new value for it, or explicitly modify what's in seq.

You need to investigate Pass by Value to understand why this doesn't work. See this page.

Dave Gamble
+1  A: 

It all depends on what you are trying to do. If possible, it is better to do malloc/free in the same scope, IMO, it makes the code much more readable - memory allocation in C is already hard enough. In your case, you would first malloc, call the function, and free after outside the function. But of course, it is not always possible.

Some of your solutions will not work: the second one, for example, will not do what you want, because when you call the function, the pointer is copied:

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);
}

Generally, you should do as the fopen functions: you return a pointer:

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

char *p = function();

Or you could use a pointer to a pointer:

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);
}

I think the first one is much better, though, in general.

Also, concerning your style: sizeof(char) is useless, it is always equal to 1 by definition, whatever compiler/platform you are using, and casting the malloc is useless and actually dangerous (because it hides missing header inclusion where malloc is declared). It is only useful if you use malloc in C++ (where the cast is mandatory).

David Cournapeau
A: 

To cast some light on the situation, consider this rewriting:

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'
}

When you call

exam(seq);

the above versions are identical to your original.

Dave Gamble
+1  A: 

There are probably many ways to do what your doing. If you intend on using seq outside of the function, the first method you outlined will work.

The other methods you have have other issues if you intend on using seq after calling the function. Since C is pass by value, you are passing the address contained in seq to the routine, which will not change the memory location associated with seq in the last three examples. To change the memory location of seq, you need to pass the address of the pointer into the routine to set the pointer. This is shown in David Cournapeau example.

The issue with the last two cases is that you "freed" the memory, but you are still retaining a pointer to the memory as the value of seq will not be changed and you can use it to access memory you have "freed". This is known a a dangling pointer.

David Cournapeau suggestion of using a function to return the pointer would give you access to the memory you allocated in the function. Otherwise you will need to pass the address of seq into the routine and dereference the value to set it to the allocated space.

Glenn
+1  A: 

You should not cast the result of malloc() unless you're using an implementation of C that predates the 1989 ANSI standard, or you intend to compile this code as C++, in which case you should be using new instead of malloc(); first of all, it isn't necessary, and second of all, it will mask a compiler diagnostic if you don't have a prototype for malloc() in scope.

Also, sizeof(char) is 1 by definition; using it in this case makes no difference and just adds visual noise.

The canonical form for writing a malloc() statement for any type T is

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

or

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

Now addressing your four cases...

Your first case is generally correct; you're allocating the memory for seq outside of exam, and passing the pointer by value.

Your remaining cases all have a similar problem; the change to the pointer value seq is not going to be reflected in the caller, and you will have introduced a memory leak. If you're passing a pointer to a function, and you want the pointer value to be overwritten, then you need to pass a pointer to that pointer:

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

If you want to resize a dynamically allocated buffer, use realloc():

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

Note that

char *p = realloc(NULL, 10);

is the same as

char *p = malloc(10);
John Bode