0

This isn't so much of a problem as a generalized question...

I just learned about the pointer-like nature of array structures in C; it seems to me that this relies very heavily upon the array being indexed across an unbroken band of memory for "pointer math" (i. e. int* pValue incrementing by the value of sizeof(int) on pValue++) to work effectively. But it occurs to me that sometimes the OS might not be able to find a concatenated stretch of memory segments to meet the demands of the declaration, particularly for large arrays on low-performance systems.

What happens then? Does this create a runtime error or is there some sort of workaround that gets deployed?

Pleas forgive me if my code is poor... I'm still learning and C seems very important, so I'd like to get it right.

MrMyWay
  • 3
  • 3
  • 2
    For a dynamic allocation using malloc and such if there is not enough contiguous memory available then the allocation fails. How the program handles that is up to the program. If the array is on the stack and there is not enough space you'd generally get a stack overflow runtime error. – Retired Ninja Mar 15 '23 at 02:58
  • Yes, arrays, as well as heap-allocated memory chunks, are all contiguous in memory. The C compiler assumes that all arrays will always fit, and if it doesn't then you'll get a runtime error. – Some programmer dude Mar 15 '23 at 02:59
  • 2
    ^ only for the stack. For malloc, the compiler doesn't assume arrays will fit it just returns yes or no for whether it found a space large enough. Stack overflow is generally fatal, malloc failures are not -- unless you ignore the error response and use the pointer pointing to nothing. – Dave S Mar 15 '23 at 03:01
  • 1
    Also there's a few big differences between arrays and heap-allocated memory: An array is allocated by the compiler at build-time, heap-allocation through `malloc` is done at runtime. Therefore the two memory areas tend to be located in different segments of memory. Also if you have an array you can get its actual size with the `sizeof` operator, which is not possible with heap-allocated memory (or once an array has decayed to a pointer). – Some programmer dude Mar 15 '23 at 03:02
  • ^ " between arrays and heap-allocated memory: " you mean between *the stack* and and heap allocated memory -or- local variable arrays allocated on the stack? – Dave S Mar 15 '23 at 03:04
  • 1
    @DaveS No, arrays are arrays wherever they're created: In block-scope inside a function, at file-scope outside of any function, or in a structure. Typically only block-scope variables are on the stack. – Some programmer dude Mar 15 '23 at 03:12

2 Answers2

2

I just learned about the pointer-like nature of array structures in C; it seems to me that this relies very heavily upon the array being indexed across an unbroken band of memory for "pointer math" (i. e. int* pValue incrementing by the value of sizeof(int) on pValue++) to work effectively.

Well yes, but you don't have to deduce that from pointer math. The language spec is pretty clear on the topic:

An array type describes a contiguously allocated nonempty set of objects with a particular member object type

(C17 6.2.5/20; emphasis added)

But it occurs to me that sometimes the OS might not be able to find a concatenated stretch of memory segments to meet the demands of the declaration, particularly for large arrays on low-performance systems.

That can happen.

What happens then? Does this create a runtime error or is there some sort of workaround that gets deployed?

The language spec does not say, but in practice, it probably depends on the storage duration of the array:

  • In the very unlikely event that it happens for an array with static storage duration, the program likely fails at startup in a way characteristic of the C implementation.
  • If it happens for an array with automatic storage duration then the program likely crashes -- on most implementations, this would constitute a variety of stack overflow.
  • If it happens for an array with thread storage duration then probably the creation of the affected thread fails, but this is not inherently fatal.
  • It cannot happen for an array with allocated storage duration, because allocated objects do not have a declared type, and they obtain an effective type only by having a value written to them.
    • An array larger than the allocated object cannot be written to that object to set its effective type.
    • The allocation itself can fail (which is not inherently fatal), but that's a different matter.
John Bollinger
  • 160,171
  • 8
  • 81
  • 157
0

It depends on the allocation type and the OS, compiler etc...

Regadrding allocation type - staticly allocated on the stack will be limited by the size of the stack and i think the compiler will show an error if you try and allocate something that is too big. You can control the max stack size in linux via ulimit.

For global arrays - this depends on os and compiler also as it depends on data / bss max size. I dont know if you can change these. But the compiler will tell you the array is too big.

For dynamic allocation on the other hand - the fail will appear on run time, thats the nature of dynamic allocation.

But when checking it its worth noting that some systems use optimistic memory allocation - which means that malloc can return successfuly, but trying to write to the array may fail you as the memory is not guarnteed. see also this part of man malloc:

By default, Linux follows an optimistic memory allocation strategy. This means that when malloc() returns non-NULL there is no guarantee that the memory really is available. In case it turns out that the system is out of memory, one or more processes will be killed by the OOM killer. For more information, see the description of /proc/sys/vm/overcommit_memory and /proc/sys/vm/oom_adj in proc(5), and the Linux kernel source file Documentation/vm/overcommit-accounting.

you can also read some more about it here, its talking about cpp but its the same principle.

Linux optimistic malloc: will new always throw when out of memory?

Uriel.Gi
  • 69
  • 1
  • 6