Why does that work?
#include
using namespace std;
int main() {
float* tab[3];
int i = 0;
while(i < 3) {
tab[i] = ne
Memory access protection isn't very fine grained. When you allocate some memory, you get a whole page worth of memory allocated to your program. When you try and access that extra memory, it's likely to succeed, but you're also likely to run over other memory allocated to your program.
This is why buffer overruns work as an attack. In many cases it's predictable what that extra memory after your array is being used for. If I can control what you put there, I can overwrite data you don't want me overwriting. If I can overwrite your call stack, then I can execute any code I want in your process context. If this is a service running as an admin user, then I have a local privilege escalation. If this is a internet-facing service of some sort, then I have a remote execution attack.
Your best bet is to work with more robust structures like std::vector unless you have a specific purpose for using arrays. (And even then you might be able to get away with vectors).