int (*p)[2] is a pointer to an int [2] type, which itself is essentially a int * type but with some additional type checking on the array bounds.
So in p = &s[i]; you are setting p to be the address of the pointer to the area in memory where the array s[i] is.
It's much much easier to just make p also an array (i.e., "essentially" a pointer to an area in memory with additional machinery), and then use that directly to point at the array memory area (p = s[i]). However, in that case, that's exactly what pint (as a true pointer instead) is doing, so we can remove p entirely.
So:
#include <stdio.h>
int main(){
int s[4][1] = {{1234,1},{1233,2},{1232,3},{1331,4}};
int i,j,*pint;
for(i=0;i<4;++i){
pint = (int*)s[i];
printf("\n");
for(j=0;j<=1;++j)
printf("%d ",*(pint+j));
}
return 0;
}
See Arrays and pointers or google for "C arrays and pointers" and also Pointer address in a C multidimensional array.
Note, I assume you are just doing this to play around and understand how pointers and arrays interact, so I make no comment on whether it is ideal to use pointers arithmetic or array notion and so on in each case.
Note also, that I say an array is "essentially a pointer [...]", however, this is not strictly true, it just acts like a pointer in a lot of cases and for the most part this is a reasonable way to think of how things are working. In reality, arrays are treated in a special way. See Is array name equivalent to pointer? and Arrays.