C usando gratis correctamente

I believe I am doing this right but wanted to make sure. In a program I am using two pointers that point to allocated memory returned by a function. When I finish using that memory I free() it, but then I use those same pointers to point at a new allocated memory space. Here is my program to give an example of what I mean (Commented to show my thought process):

int main(void)
{
    char *data, *url;
        int i = 1;

    while(i)
    {
        printf("Enter URL: ");
        if(!(url = getstr())) return 1;                                  //url now points to allocated memory from getstr();
        if(strlen(url) <= 0) i = 0;
        if(data = readsocket(url, 80, "http")) printf("\n%s\n\n", data); //data now points to allocated memory from readsocket();
        else printf("\n\n");
        free(url);                                                       //free allocated memory that url points to url
        free(data);                                                      //free allocated memory that data points to data
    }
    return 0;
}

Is this correct, or is there a better more generally preffered method of doing this? Or am I just completely doing it wrong?

preguntado el 28 de agosto de 12 a las 14:08

¿Cuáles son las semánticas de readsocket? -

It retrieves data from a socket -

A small tip, strlen will never return a negative number. -

I meant what does it return, how does it fail, etc. I'm worried that free(data) may be a problem. -

OK, then you're fine. Freeing NULL is perfectly legit. -

4 Respuestas

Assuming your functions getstr y readsocket malloc the memory internally then this is perfectly fine.

My only suggestion is that it's often helpful to allocate memory in the same scope that you free it, this often helps reason about when things need to be freed.

Por ejemplo:

url = malloc(URL_MAX_LEN);
if (!url) return 1;
if (!getstr(url)) {
    free(url);
    return 1;
}
/* do something with url */
free(url);

It can be nice to do this using goto, if you have lots of objects and exit points.

object1 = malloc(OBJECT1_SIZE);
/* do work, if there's an error goto exit1 */
object2 = malloc(OBJECT2_SIZE);
/* do work, if there's an error goto exit2 */
object3 = malloc(OBJECT3_SIZE);
/* do work, if there's an error goto exit3 */
exit3:
free(object3);
exit2:
free(object2);
exit1:
free(object1);
return 1;

If your objects get more complex and require a lot of work to create and destroy then you can wrap malloc and free, but it's critical you apply exactly the same rules to your create/destroy functions as you would to malloc/free to avoid leaks. As a matter of good practice you should always have a destroy to match a create, even if it just wraps free. It's much harder to go wrong that way.

struct x *create_x() {
    struct x *p = malloc(10);
    p->val1 = 7;
    return p;
}
void destroy_x(struct x *p) {
    free(p);
}

Respondido 28 ago 12, 17:08

As a general guideline, I propose C's Regla de tres: malloc, goto y free should always come together, or not at all. - Kerrek SB

I this rule is good, but it prevents you from having "factory functions" which create new objects. If you want to use that pattern, you should do one or both of the following: (a) invent consistently name the factory functions (new_XYZ and create_XYZ are good conventions), so that you get in the habit of free()ing them. (b) define a matching "destroy_XYZ" function for each new_XYZ, which might or might not be a simple wrapper for free(). - Adrián Ratnapala

@KerrekSB Or you should forget about goto and write an inline function cleanup() which frees all malloc:ed memory. It is perfectly safe to pass a null pointer as parameter to malloc so the clean up function can look the same no matter from where it is called. - Lundín

@AdrianRatnapala: That's true. There's a somewhat transitive gotcha to the rule, I suppose: You pueden leak one surplus malloc, but that in turn makes your entire function count as a malloc-type function itself, which then becomes subject to the Rule... if that makes any sense :-) - Kerrek SB

@AdrianRatnapala I very much agree with this. I'm going to update my answer to include a reference to factory functions. - jleahy

There is no problem in your code, but you can pre-allocate memory for data and url and pass these as arguments to getstr y readsocket functions. This will be more efficient.

Respondido 28 ago 12, 14:08

@JanSpurny, perhaps he will implement this later ;) - perreal

If the functions getstr y readsocket allocates memory using e.g. malloc then it's what you are doing is okay.

Respondido 28 ago 12, 14:08

No es necesario verificar NULL prior to calling free, free simply does nothing if passed a NULL. - Hasturkun

Freeing a NULL pointer is legal C and should have no negative consequences - obviously getting a null back might be a sign of other problems but by itself free(NULL); isn't an error. - Nigel Harper

@KerrekSB I still remember when bad stuff happened, and seem to forget that apparently it's okay these days. - Algún tipo programador

@JoachimPileborg: In soviet Russia, null deletes ! - Kerrek SB

Here's some things I've noticed:

  1. Estas usando i to control the loop, but when you set i = 0, the program has to go all the way to closing curly bracket. I'd recommend using while (1) y break statements and getting rid of i variable:

    while(1) {
        ...
        if (strlen(url) <= 0)
            break;
        ...
    }
    
  2. Tu estas usando if (data = readsocket(url, 80, "http")) which is not technically wrong, but it is a bit misleading as someone may mistake it for comparison if (data == readsocket(url, 80, "http"). This is almost a "pattern" in C programming and it's generally a good idea to write just like you did on if (!url = getstr())) línea:

    if ((data = readsocket(url, 80, "http")) != NULL) ...
    

    or

    if (!(data = readsocket(url, 80, "http"))) ...
    
  3. this is more a "style"-related, but it is better to write separate statements on separate lines, so don't write

    if (!(url = getstr())) return 1
    

    sino más bien

    if (!(url = getstr()))
        return 1;
    
  4. as for free-ing memory, you're doing just fine

Respondido 28 ago 12, 14:08

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.