In theory you should call delete [].
EDIT: The following applies only to Microsoft Visual C++ (I should have said this).
In practice, in Microsoft Visual C++ , it doesn't matter which delete you use when the objects in the array don't have destructors. Since you have an array of pointers, and pointers can't have destructors, you should be OK.
However, as others have pointed out, it is incorrect C++ to mix new [] and delete without []. Although it may work in Visual C++ in this case, the code is not portable and may fail in other compilers.
But going back to the specific case of Visual C++, even if you call delete [], the compiler will realize that it doesn't need to iterate through the array calling destructors when it's an array of primitive types like int, char, or pointers. Calling delete in that case actually works and won't break anything. It would not be slower to do the right thing and call delete [], but it won't be faster either.
In fact, in MSVC++, delete[] p immediately calls the regular operator delete(void *p) when p is a pointer to a simple type, or one without destructors.
Those who don't believe me, step through this code into the CRT code for the first two calls to delete[].
#include "stdafx.h"
#include <malloc.h>
#include <iostream>
using namespace std;
class NoDestructor
{
int m_i;
};
class WithDestructor
{
public:
~WithDestructor()
{
cout << "deleted one WithDestructor at " << (void *) this<< endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
int **p = new int *[20];
delete [] p;
p = (int**) malloc(80);
free(p);
NoDestructor *pa = new NoDestructor[20];
delete [] pa;
WithDestructor *pb = new WithDestructor[20];
delete [] pb;
return 0;
}