I am very beginner in c++ and trying to understand pointers, arrays and dynamic allocations. And in this code I am trying to allocate and then deallocate a 2d string array but the code doesn't work. The part delete[] contents[i] doesn't do the job that I want it to do. I did the same thing for 2d integer array and it worked. So I am really confused.
#include <iostream>
using namespace std;
int main() {
    // Write C++ code here
    string** contents = new string* [2]; //contents going to be 2(rows)x3(column) 2D string Array
    string* sptr; // to test the memory leak
    
    for(int i = 0; i < 2; i++) {
        //contents[i] is an array of pointers which the every element are pointing 
        //to string arrays with the size of 3
        contents[i] = new string[3];
    }
    
    contents [1] [1] = "safe";
    sptr = contents[1]; 
    cout << "sptr[1]: " << sptr[1] <<endl;
    cout << "contents[1][1]: " << contents[1][1] <<endl;
    
    for(int i = 0; i < 2; i++) {
        //Problemetic PART !!!
        //deleting the string arrays with size 3 (actually not working but I didn't understand why.)
        delete[] contents[i];
    }
    
    cout<<"--After delete[] contents[i] for each i {0,1};"<<endl;
    cout << "sptr[1]: " << sptr[1]  <<endl; //nothing changed
    cout << "contents[1][1]: " << contents[1][1] <<endl; //nothing changed
    
    contents[1][1] = "dang";
    
    cout<<"--contents[1][1] is changed to dang"<<endl;
    cout << "sptr[1]: " << sptr[1]  <<endl;
    
    //I can delete the pointers in the pointer array but I just lose the adresses of the strings 
    //arrays and they still remain to be exist in the memory. (Memory Leak)
    delete[] contents;
    
    cout<<"--After delete[] contents;"<<endl;
    cout << "contents[1][1]: " << contents[1][1] <<endl;//since I lost the pointer I can't 
                                                        //have acces to the string with using
                                                        //the contents
                                                        
    cout << "sptr[1]: " << sptr[1]  <<endl; //but I still have the string in memory
    
    
    return 0;
}
output is :
sptr[1]: safe
contents[1][1]: safe
--After delete[] contents[i] for each i {0,1};
sptr[1]: safe
contents[1][1]: safe
--contents[1][1] is changed to dang
sptr[1]: dang
--After delete[] contents;
contents[1][1]: 
sptr[1]: dang
