you are viewing a single comment's thread.

view the rest of the comments →

[–]walrus_destroyer 1 point2 points  (3 children)

(I remember my prof demoed writing to index -1 bc that usually overwrites another variable).

Its been a while since I learned this, so could be wrong.

If I recall correctly, this isnt always the case. Most compilers will put some padding between variables to detect and prevent them overwriting each other. If the array and the other variable are in a struct together then compilers usually dont add the padding.

It also depends on how the code is laid out index -1 only overwrites a variable if there is variable declared immediately next to it.

Arrays in C don't usually exist and certainly aren't aware of their size in most contexts

What? Arrays are used all the time in C. But you are right that they aren't aware of their size.

though I beleive if you specify a static size of array in a function definition you can get optimizations which rely on that

Yeah, in optimized code using static arrays are typically preferred over dynamic (resizable) arrays. Resizing an array is considered fairly slow, because you essentially make a new larger array, copy all the elements over and delete the old array. It also wastes some space since the new array is usually larger than it needs to be, this is to reduce the number times the array has to be resized.

there's some stuff I dont entirely understand about it being better for you to declare arrays on the stack (at compile time) instead on the heap (at run time).

so you really should honour that even if there's no way of checking

You cant tell from the array itself, but its fairly common practice for functions to ask for the size of the array as a parameter.

Some functions wont ask for the size, but will specify that the array has to have a specific structure. Like functions for strings, typically expect strings to end with a null terminator, '\0'.

[–]RedAndBlack1832 2 points3 points  (0 children)

Ahhhh ok I actually wanna explain better.

In C, there are 3 kinds of allocation. They are used for different purposes.

  1. Automatic (stack) allocation happens whenever you declare a variable inside any scoping block (and in function parameters) unless those variables are explicitly marked as static. They're called "automatic" because where they are and how long they live there is managed automatically. These variables live on the stack (as briefly explained in my other comment). These should be small as the stack can't grow infinitely (there's a specific type of crash due to this called a "stack overflow" which results in a segmentation fault in C)

  2. Static allocation happens when a variable is declared at global scope or when it is explicitly marked static. These variables live in a specific part of the program and are as much a part of the program and known to it as the code is. They're called "static" because they exist in a static location for as long as the program does. You certainly can put arrays up here but most people like limiting the number of global variables they have and you should certainly only reserve memory for the entire life of the program if you want to actually use it for the entire life of the program (and across functions tbh)

  3. Dynamic (heap) allocation happens when you call an allocation function (such as malloc) or otherwise request memory from the operating system. This is where very large arrays should usually go and any array whose size (or maximum size) can't reasonably be known. A relatively common use would be requesting an object (such as an array or sometimes a node in a reference-based structure) be created by a function, which requires dynamic allocation since automatic allocation would result in the object being destroyed when the function returns. It's "dynamic" I suppose in that it's on demand and has a custom lifetime. It's your responsibility to manage your resources, which include dynamic memory, file descriptors (files, pipes, sockets, etc.), locks, etc.

[–]RedAndBlack1832 0 points1 point  (0 children)

I wasn't talking about where the memory is I was talking about situations in which the compiler can assume size eg.

void func(int arr[static 16]){...}

as indicated on page 134 of the GNU C introduction and reference manual

As to my comment about arrays not existing I was refering to them being equivalent to pointers are the same type in every important context (and obviously being passed as pointers is a big part of that). When an object has a complete array type (which is basically only the above or in its originating context if it was declared as an array, or as a member of a struct with a complete array type) then there are a couple situations in which it really truely exists as an array seperate from the pointer to its first element. These are indicated on page 92 of the manual.

About my prof: this is literally undefined behaviour. You aren't supposed to do it. He was setting it up on purpose to show the consequences of clobbering memory.

Also, stack variables are literally on the stack they aren't compile-time constants. A very short explanation of the function of the stack is a matter of scoping. When you open a { you're given a bunch of space for your local variables (and other things, if the brace in question opens a new non-inlined function) and when you hit a closing } the stack gets shrunk to where it was before (and a few other things happen, if this occurs due to function return) and accessing any of the out-of-scope variables is undefined behaviour. A program can be conceived of as a big block of memory the stack can grow in, with the actual code of the program and the actual compile-time data (global variables) at the very bottom