Edit: I got tired of seeing too many incorrect answers getting upvotes so I did some actual experiments to show the validity of my claims and rewrote my answer.
tl;dr tab is an array of pointers to char. That means tab isn't storing char (which take 8 bits each) but rather is storing x pointers which take (generally) 64 bits each. You need to find a way to use tab as a pointer to a single array of char: char * tab
The Problem
In this loop:
for (int i = 0; i < x+2; i++) {
tab[i] = new char [y+2];
}
You are running new x+2 times (btw, why +2??). As you should know, new returns pointers not chars. It allocates memory for the data type you are requesting i.e. char and then returns a pointer to that memory address. The call to new in the loop thus allocates 8-bits. Since new returns a memory address, you need to store it somewhere. Thankfully you've allocated space to store that address with this line:
tab = new char* [x+2];
Now you are not asking new to reserve space for an array of char but rather you are asking for it to reserve space for an array of pointers to char.
On most modern architectures, pointers require 64 bits. Those pointers are being stored on the heap in the memory address that tab is pointing to. i.e. tab[0] holds the first pointer to char, tab[1] holds the second, etc... These pointers hold the locations of yet additional memory that has been allocated to hold the chars.
So in total, you are allocating room for x+2 pointers with this line:
tab = new char* [x+2];
and (x+2)*(y+2) chars with this line:
tab[i] = new char [y+2];
If you do the math, that's (x+2)*8B for the pointers plus (x+2)*(y+2)*1B for the chars. From looking at the equations, you'll see that for a given number of chars i.e for any x*y you'll see more memory usage if x is larger than y.
To test this, I ran the valgrind massif tool on your code (except I got rid of the +2 with the following results:
| x | y |useful-heap(B)|
|----|---|--------------|
| 0 | 1 | 0 |
| 1 | 0 | 8 |
| 1 | 1 | 9 |
| 1 | 2 | 10 |
| 1 | 3 | 11 |
| 2 | 0 | 16 |
| 2 | 1 | 18 |
| 2 | 2 | 20 |
| 3 | 0 | 24 |
| 3 | 1 | 27 |
| 20 | 0 | 160 |
|100 | 0 | 800 |
look at how memory usage increases by 8B each time x increases. This is the allocation of space to store your array of pointers. Note that for the y=0 cases there are no chars stored at all... so when x=100 and y=0 you are using 800B of memory for absolutely nothing.
fyi, massif also reports extra allocations that the system made on your behalf due to minimum allocation size, efficiency, etc. but the numbers I gave above are the exact amounts that massif claims you asked for
how to fix it?
The key is going to be to rearrange how you're storing the chars and how you address them. You are storing chars so you could make one big array of chars and find a different way to index them. That would require no heap allocation other than the chars themselves.
I'd also recommend staying away from raw arrays and pointers and using std::array or std::vector instead but I assume you've been specifically told to use them for an assignment...
new), 16 kB is an insanely small amount of memory on modern machines. In fact, the underlying memory allocator fornew char[]will by itself probably reserve more than 16 kB to satisfy future memory requests. Why is 16 kB such a problem, and why is 5 kB your limit?