Does C allocate memory automatically for me?

前端 未结 8 2110
情话喂你
情话喂你 2020-12-19 14:18

I have been writing C for only a scant few weeks and have not taken the time to worry myself too much about malloc(). Recently, though, a program of mine return

相关标签:
8条回答
  • 2020-12-19 14:34

    My question is, how does C allocate memory when I haven't actually malloc()ed the appropriate amount of memory? What's the default?

    To not allocate memory. You have to explicity create it on the stack or dynamically.

    In your example, subcells points to an undefined location, which is a bug. Your function should return a pointer to a Cell struct at some point.

    0 讨论(0)
  • 2020-12-19 14:35

    I'm going to pretend I'm the computer here, reading this code...

    typedef struct Cell {
      struct Cell* subcells;
    }
    

    This tells me:

    • We have a struct type called Cell
    • It contains a pointer called subcells
    • The pointer should be to something of type struct Cell

    It doesn't tell me whether the pointer goes to one Cell or an array of Cell. When a new Cell is made, the value of that pointer is undefined until a value is assigned to it. It's Bad News to use pointers before defining them.

    Cell makeCell(int dim) {
      Cell newCell;
    

    New Cell struct, with an undefined subcells pointer. All this does is reserve a little chunk of memory to be called newCell that is the size of a Cell struct. It doesn't change the values that were in that memory - they could be anything.

      for(int i = 0; i < dim; i++) {
        newCell.subcells[i] = makeCell(dim -1);
    

    In order to get newCell.subcells[i], a calculation is made to offset from subcells by i, then that is dereferenced. Specifically, this means the value is pulled from that memory address. Take, for instance, i==0... Then we would be dereferencing the subcells pointer itself (no offset). Since subcells is undefined, it could be anything. Literally anything! So, this would ask for a value from somewhere completely random in memory. There's no guarantee of anything with the result. It may print something, it may crash. It definitely should not be done.

      }
    
      return newCell;
    }
    

    Any time you work with a pointer, it's important to make sure it's set to a value before you dereference it. Encourage your compiler to give you any warnings it can, many modern compilers can catch this sort of thing. You can also give pointers cutesy default values like 0xdeadbeef (yup! that's a number in hexadecimal, it's just also a word, so it looks funny) so that they stand out. (The %p option for printf is helpful for displaying pointers, as a crude form of debugging. Debugger programs also can show them quite well.)

    0 讨论(0)
  • 2020-12-19 14:38

    There are really three sections where things can be allocated - data, stack & heap.

    In the case you mention, it would be allocated on the stack. The problem with allocating something on the stack is that it's only valid for the duration of the function. Once your function returns, that memory is reclaimed. So, if you return a pointer to something allocated on the stack, that pointer will be invalid. If you return the actual object though (not a pointer), a copy of the object will automatically be made for the calling function to use.

    If you had declared it as a global variable (e.g. in a header file or outside of a function) it would be allocated in the data section of memory. The memory in this section is allocated automatically when your program starts and deallocated automatically when it finishes.

    If you allocate something on the heap using malloc(), that memory is good for as long as you want to use it - until you call free() at which point it is released. This gives you the flexibility to allocate and deallocate memory as you need it (as opposed to using globals where everything is allocated up front and only released when your program terminates).

    0 讨论(0)
  • 2020-12-19 14:39

    Anything not allocated on the heap (via malloc and similar calls) is allocated on the stack, instead. Because of that, anything created in a particular function without being malloc'd will be destroyed when the function ends. That includes objects returned; when the stack is unwound after a function call the returned object is copied to space set aside for it on the stack by the caller function.

    Warning: If you want to return an object that has pointers to other objects in it, make sure that the objects pointed to are created on the heap, and better yet, create that object on the heap, too, unless it's not intended to survive the function in which it is created.

    0 讨论(0)
  • 2020-12-19 14:47

    Short answer: It isn't allocated for you.

    Slightly longer answer: The subcells pointer is uninitialized and may point anywhere. This is a bug, and you should never allow it to happen.

    Longer answer still: Automatic variables are allocated on the stack, global variables are allocated by the compiler and often occupy a special segment or may be in the heap. Global variables are initialized to zero by default. Automatic variables do not have a default value (they simply get the value found in memory) and the programmer is responsible for making sure they have good starting values (though many compilers will try to clue you in when you forget).

    The newCell variable in you function is automatic, and is not initialized. You should fix that pronto. Either give newCell.subcells a meaningful value promptly, or point it at NULL until you allocate some space for it. That way you'll throw a segmentation violation if you try to dereference it before allocating some memory for it.

    Worse still, you are returning a Cell by value, but assigning it to a Cell * when you try to fill the subcells array. Either return a pointer to a heap allocated object, or assign the value to a locally allocated object.

    A usual idiom for this would have the form something like

    Cell* makeCell(dim){
      Cell *newCell = malloc(sizeof(Cell));
      // error checking here
      newCell->subcells = malloc(sizeof(Cell*)*dim); // what if dim=0?
      // more error checking
      for (int i=0; i<dim; ++i){
        newCell->subCells[i] = makeCell(dim-1);
        // what error checking do you need here? 
        // depends on your other error checking...
      }
      return newCell;
    }
    

    though I've left you a few problems to hammer out..

    And note that you have to keep track of all the bits of memory that will eventually need to be deallocated...

    0 讨论(0)
  • 2020-12-19 14:52

    Local variables are "allocated" on the stack. The stack is a preallocated amount of memory to hold those local variables. The variables cease to be valid when the function exits and will be overwritten by whatever comes next.

    In your case, the code is doing nothing since it doesn't return your result. Also, a pointer to an object on the stack will also cease to be valid when the scope exits, so I guess in your precise case (you seems to be doing a linked list), you will need to use malloc().

    0 讨论(0)
提交回复
热议问题