Aren't char *s1 and char s1[] declarations same ?
The declaration
char *s1 = "Hello";
declares a pointer to a string literal. You may not change a string literal. Any attempt to change a string literal like for example that
strcpy(s1,s2);
results in undefined behavior.
This declaration
char s1[] = "Hello";
declares a character array elements of which are initialized by elements of the string literal. The above declaration is equivalent to
char s1[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
You may change the character array because it is not declared as a constant array.
So this call of strcpy is correct for the array
strcpy(s1,s2);
You could also write for example
char s1[] = "Hello";
char *p = s1;
//...
strcpy(p,s2);
because in this case the pointer p does not point to a string literal. It points to the non-constant character array s1.
And the message in the call of printf
printf("copied is %s into %s",s1,s2);
is wrong. Actually this call
strcpy(s1,s2);
copies characters from s2 into s1.