Compiler allowing allocation of memory to a garbage pointer index

This is a program of jagged array.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include<iostream>
using namespace std;
void display(int **Ptr, int row, int *p);
int main() {
	int r = 0, c = 0;
	cout << "Enter Rows in Array: "; cin >> r;
	int*ptr = new int[r];
	int**P = new int*[r];
	for (int i = 1; i <= r; i++)
	{
		cout << "Enter the Cols in Row#" << i << ": ";
		cin >> c;
		ptr[i - 1] = c;
		P[i] = new int[c];
		for (int j = 0, m = 1; j < c; j++)
		{
			cout << m++ << "- ";
			cin >> P[i][j];
		}
	}
	display(P, r, ptr);
	delete[] P;
	delete[] ptr;
	system("pause");
	return 0;
}
void display(int **Ptr, int row, int *p)
{

	for (int i = 1, m = 1; i <= row; i++)
	{
		cout << "Elements of Row " << i << ": ";
		for (int j = 0; j < p[i - 1]; j++)
		{
			cout << Ptr[i][j] << " ";
		}
		cout << endl;
	}
}


If you run the program, it will give you an output (for example, this is one output I got for a random set of values)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Enter Rows in Array: 3
Enter the Cols in Row#1: 2
1- 1
2- 2
Enter the Cols in Row#2: 4
1- 3
2- 2
3- 1
4- 6
Enter the Cols in Row#3: 3
1- 2
2- 3
3- 0
Elements of Row 1: 1 2
Elements of Row 2: 3 2 1 6
Elements of Row 3: 2 3 0


And at the end, I got this error, once the program was executed,

1
2
Heap Corruption Detected: after Normal block (#189) at 0x00AFE578.
CRT detected that this application wrote to memory after end of heap buffer


It clearly shows that there was some issue with heap memory to which memory was allocated and something like that.. but my question is, why did it allow the program to run at first?
At Line Number 14,
 
P[i] = new int[c];

When the loop controlling variable will be i = 3 (last iteration), then I am clearly allocating memory to a garbage index of the array (if you see, my double pointer is pointing to a array of pointers of size 3. That is, its indexes will be 0 1 and 2... 3rd index would be of garbage)
But still, it allows the allocation of memory at that index and even displays the values when I try to access that column in the Display function. Why does it do that? Can anyone explain?
> for (int i = 1; i <= r; i++)
Arrays begin at 0 and end at N-1
Every time you start trying to subscript at 1, you risk making a mess of it.

> P[i] = new int[c];
This is out of bounds on the last iteration.

> why did it allow the program to run at first?
Because corruption is usually detected on the next attempt to read a location, not on the first instance of writing to a location.

If you want to detect such things, try say
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ g++ -g foo.cpp
$ man valgrind
$ valgrind --vgdb=yes ./a.out
==6566== Memcheck, a memory error detector
==6566== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==6566== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==6566== Command: ./a.out
==6566== 
Enter Rows in Array: 2
Enter the Cols in Row#1: 2
1- 2
2- 2
Enter the Cols in Row#2: 2
==6566== Invalid write of size 8
==6566==    at 0x400B6D: main (foo.cpp:14)
==6566==  Address 0x5ab7560 is 0 bytes after a block of size 16 alloc'd
==6566==    at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6566==    by 0x400AC1: main (foo.cpp:8)
==6566== 
==6566== Invalid read of size 8
==6566==    at 0x400BBC: main (foo.cpp:18)
==6566==  Address 0x5ab7560 is 0 bytes after a block of size 16 alloc'd
==6566==    at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6566==    by 0x400AC1: main (foo.cpp:8)
==6566==  
To me, the root cause of your error is confusion about user-friendly indices (1 - n) and computer friendly indices (0 - n-1). See my comments below.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include<iostream>
using namespace std;
void display(int **Ptr, int row, int *p);
int main() {
	int r = 0, c = 0;
	cout << "Enter Rows in Array: "; cin >> r;
	int*ptr = new int[r];
	int**P = new int*[r];
	for (int i = 1; i <= r; i++) // i is user index
	{
		cout << "Enter the Cols in Row#" << i << ": ";
		cin >> c;
		ptr[i - 1] = c;  // convert i to computer friendly
		P[i] = new int[c];
		for (int j = 0, m = 1; j < c; j++) // uh... j is computer friendly and m is user friendly?
		{
		    cout << m++ << "- ";  // j is incremented in "for" construct above, m is incremented here.
		    cin >> P[i][j];   // oops, using user-friendly i and computer friendly j
		}
	}
	display(P, r, ptr);
	delete[] P;
	delete[] ptr;
	system("pause");
	return 0;
}
void display(int **Ptr, int row, int *p)
{

    for (int i = 1, m = 1; i <= row; i++)   // i is user friendly
	{
		cout << "Elements of Row " << i << ": ";
		for (int j = 0; j < p[i - 1]; j++)   // Convert i to computer friendly. j is computer friendly
		{
		    cout << Ptr[i][j] << " ";   // oops. Using user-friendly i and computer friendly j
		}
		cout << endl;
	}
}


As a general policy, I make the variables in the code computer-friendly. Convert to/from user-friendly values immediately upon input/output (or as close as possible). If you think this way, it's easy to keep the two straight.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include<iostream>
using namespace std;
void display(int **Ptr, int row, int *p);

int main() {
    int r = 0, c = 0;
    cout << "Enter Rows in Array: "; cin >> r;
    int*ptr = new int[r];
    int**P = new int*[r];
    for (int i = 0; i < r; i++)
    {
	// Prompt for user row number
	cout << "Enter the Cols in Row#" << i+1 << ": ";
	cin >> c;
	ptr[i] = c;
	P[i] = new int[c];
	for (int j = 0; j < c; j++) // one computer friendly index
	{
	    // convert to user-friendly index on output
	    cout << j+1 << "- ";
	    cin >> P[i][j];
	}
    }
    display(P, r, ptr);
    delete[] P;
    delete[] ptr;
    system("pause");
    return 0;
}

void display(int **Ptr, int row, int *p)
{

    for (int i = 0; i < row; i++)
    {
	// convert to user-friendly index on output
	cout << "Elements of Row " << i+1 << ": ";
	for (int j = 0; j < p[i]; j++)
	{
	    cout << Ptr[i][j] << " ";
	}
	cout << endl;
    }
}


Enter Rows in Array: 3
Enter the Cols in Row#1: 4
1- 6
2- 7
3- 8
4- 9
Enter the Cols in Row#2: 2
1- 1
2- 2
Enter the Cols in Row#3: 9
1- 9
2- 8
3- 7
4- 6
5- 5
6- 4
7- 3
8- 2
9- 1
Elements of Row 1: 6 7 8 9
Elements of Row 2: 1 2
Elements of Row 3: 9 8 7 6 5 4 3 2 1

Topic archived. No new replies allowed.