Does C automatically allocate memory for me?

I wrote C for only a few weeks and did not take the time to worry too much about malloc() . However, recently my program returned a string of happy faces instead of the true / false values ​​that I expected from it.

If I create a structure like this:

 typedef struct Cell { struct Cell* subcells; } 

and then initialize it as follows

 Cell makeCell(int dim) { Cell newCell; for(int i = 0; i < dim; i++) { newCell.subcells[i] = makeCell(dim -1); } return newCell; //ha ha ha, this is here in my program don't worry! } 

Am I going to end up accessing happy faces stored somewhere in the memory, or perhaps write down existing cells or what? My question is, how does C allocate memory when I actually didn't have malloc () the corresponding amount of memory was allocated? What is the default?

+4
source share
8 answers

There is no default value for your pointer. Your pointer will indicate what it currently stores. Since you did not initialize it, the line

 newCell.subcells[i] = ... 

Effectively accesses some undefined part of memory. Remember that subelements [i] are equivalent

 *(newCell.subcells + i) 

If there is garbage on the left side, you add i to the garbage value and gain access to memory in this undefined location. As you said correctly, you will need to initialize the pointer to point to some valid memory area:

 newCell.subcells = malloc(bytecount) 

After this line, you can access this number of bytes. As for other memory sources, there are different types of storage that everyone uses. What kind you get depends on what kind of object you have and what storage class you specify for the compiler.

  • malloc returns a pointer to an object without a type. You can point to a pointer to this memory area, and the type of the object will actually become the type of the specified type of object. The memory is not initialized with any value, and access is usually slower. Objects thus obtained are called allocated objects .
  • You can place objects around the world. Their memory will be initialized to zero. For points, you get NULL pointers; for floats, you also get zero zero. You can rely on the right starting value.
  • If you have local variables, but use the static class specifier, then you will have the same initial value rule as for global objects. Usually, memory is allocated in the same way as global objects, but this is by no means a necessity.
  • If you have local variables without a storage class specifier or with auto , then your variable will be allocated on the stack (even if it is not defined by C, this is what compilers do, of course, of course). You can take its address, in which case the compiler will have to omit the optimization, for example, insert it into registers.
  • Local variables used with the register storage class specifier are marked as having special storage. As a result, you can no longer use your address. Recent compilers usually do not need to use register more because of their complex optimizers. If you are truly an expert, then you can get some performance if you use it.

Objects have associated storage durations that can be used to display various initialization rules (formally they define only the lifespan of at least objects). Objects declared with auto and register have automatic storage durations and are not initialized. You must explicitly initialize them if you want them to contain some value. If you do not, they will contain everything that the compiler left on the stack before they begin life. Objects allocated by malloc (or another function of this family, for example calloc ) are allocated storage time. Their storage is also not initialized. An exception is the use of calloc , in which case the memory is initialized to zero ("real" zero, that is, all bytes 0x00, regardless of any representation of the NULL pointer). Objects declared using static and global variables have a static storage duration. Their memory is initialized to zero, corresponding to their type. Note that an object must not have a type, but the only way to get an object without a type is to use dedicated storage. (An object in C is a "storage area").

So what? Here is the fixed code. Because, as soon as you have allocated a block of memory, you can no longer get more, how many items you have allocated, it is best to always keep this account. I injected variale dim into the structure in which the account is stored.

 Cell makeCell(int dim) { /* automatic storage duration => need to init manually */ Cell newCell; /* note that in case dim is zero, we can either get NULL or a * unique non-null value back from malloc. This depends on the * implementation. */ newCell.subcells = malloc(dim * sizeof(*newCell.subcells)); newCell.dim = dim; /* the following can be used as a check for an out-of-memory * situation: * if(newCell.subcells == NULL && dim > 0) ... */ for(int i = 0; i < dim; i++) { newCell.subcells[i] = makeCell(dim - 1); } return newCell; } 

Now everything looks like this: dim = 2:

 Cell { subcells => { Cell { subcells => { Cell { subcells => {}, dim = 0 } }, dim = 1 }, Cell { subcells => { Cell { subcells => {}, dim = 0 } }, dim = 1 } }, dim = 2 } 

Note that in C, the return value of a function is not required to be an object. No storage is required at all. Therefore, you cannot change it. For example, the following is not possible:

 makeCells(0).dim++ 

You will need a "free function" that will free up the allocated memory again. Because storage of selected objects is not automatically freed. You must call free to free this memory for each subcells pointer in your tree. This left an exercise for you to write it :)

+16
source

Short answer: It is not intended for you.

Slightly long answer: The subcells pointer subcells not initialized and can point anywhere. This is a mistake, and you should never allow it to occur.

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

The newCell function in your function is automatic and not initialized. You have to fix it prono. Either give newCell.subcells meaningful value quickly, or point it to NULL until you allocate some space for it. This way you will throw a segmentation violation if you try to dereference it before allocating some memory for it.

Worse, you return the Cell value by value, but assigning it Cell * when you try to populate the subcells array. Either return a pointer to the selected heap object, or assign a value to the locally selected object.

The usual idiom for this would have a form similar to

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

although I left you with a few problems to work out milk.

And note that you need to keep track of all the bits of memory that should eventually be freed ...

+26
source

Everything that is not allocated on the heap (via malloc and similar calls) is instead allocated on the stack. Because of this, everything that is created in a particular function without malloc will be destroyed when the function ends. This includes returned objects; when the stack expands after a function call, the returned object is copied to the space allocated to it in the stack by the caller's function.

Warning:. If you want to return an object that has pointers to other objects in it, make sure that the objects pointed to were created on the heap, and even better, create this object on the heap, if it is not intended to survive the function, which she created.

+4
source

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

Do not allocate memory. You must explicitly create it on the stack or dynamically.

In your example, subelements indicate an undefined location, which is an error. Your function should return a pointer to the cell structure at some point.

+3
source

Local variables are allocated on the stack. A stack is a preallocated amount of memory for storing these local variables. Variables cease to be valid when a function exits and will be overwritten by what comes next.

In your case, the code does nothing, because it does not return a result. In addition, the pointer to the object on the stack also ceases to be valid when the region exits, so I assume that in your specific case (it seems that you are making a linked list) you will need to use malloc ().

0
source

Am I going to end up accessing happy faces stored somewhere in the memory, or perhaps write down existing cells or what?

You are lucky to have a happy face. One of those bad days, he could cleanse your system;)

My question is, how does C allocate memory when I actually don't have malloc () ed with the appropriate amount of memory?

This is not true. However, what happens when you define you Cell NewCell, the subCells pointer is initialized to a garbage value. Which can be 0 (in this case you will crash) or an integer large enough to look like the actual memory address. The compiler, in such cases, will gladly receive any value located there and return it to you.

What is the default?

This behavior if you do not initialize your variables. And your makeCell function looks a bit underdeveloped.

0
source

There are three sections where you can highlight things - data, stack and heap.

In case you mentioned, it will be allocated on the stack. The problem with distributing something on the stack is that it is only valid for the duration of the function. As soon as your function returns, this memory will be restored. So, if you return a pointer to something allocated on the stack, that pointer will be invalid. If you return the actual object (but not a pointer), a copy of the object will be automatically made for the call function used.

If you declared it a global variable (for example, in a header file or outside a function), it will be allocated in the memory data section. The memory in this section is automatically allocated when your program starts and is automatically freed upon termination.

If you allocate something on the heap using malloc (), that memory is good as long as you want to use it, until you call free () at what point it will be released. This gives you the flexibility to allocate and free memory as needed (as opposed to using globals where everything is distributed in front and only freed when your program terminates).

0
source

I am going to pretend that I am a computer reading this code ...

 typedef struct Cell { struct Cell* subcells; } 

This tells me:

  • We have a type of structure called Cell
  • It contains a subcategory index
  • The pointer must be something like struct Cell

This does not tell me whether the pointer goes to a single cell or an array of Cells. When a new cell is created, the value of this pointer is undefined until a value is assigned. This is bad news to use pointers before defining them.

 Cell makeCell(int dim) { Cell newCell; 

New cell structure with subcells undefined pointer. All this makes the reserve a small piece of memory, which will be called newCell, which is the size of the cell. He does not change the meanings that were in this memory - they can be anything.

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

To get newCell.subcells [i], the calculation is done for the offset from the subcell by i, then this is dereferenced. In particular, this means that the value is pulled from this memory address. Take, for example, i == 0 ... Then we will dereference the subelement pointer itself (without offset). Since subcells are undefined, this can be anything. Literally nothing! Thus, it will require values ​​from somewhere completely random in memory. As a result, nothing is guaranteed. He can print something, he can fall. This definitely should not be done.

  } return newCell; } 

Each time you work with a pointer, it is important to make sure that it is set to a value before you look for it. Encourage your compiler to give you any warnings it may; many modern compilers can catch such things. You can also specify default pointers such as 0xdeadbeef (yup!), That the number in hexadecimal is just a word, so it looks funny) to make them stand out. (The% p option for printf is useful for displaying pointers as a crude form of debugging. Debugger programs can also show them quite well.)

0
source

All Articles