n度あることはn+1度ある

憶測が多いブログなので鵜呑みにしないこと

C言語のchar配列の不思議

C言語の文字列の宣言は、よく入門書などにchar str[10]、文字数が決まっていない場合はchar str[]といったように、変数名の後に大カッコをつけた宣言がよく知られると思う。
この方法だと文字列の扱いが少し面倒くさい。
以下のようなプログラム(test.c)をコンパイルしてみる。

#include <stdio.h>

int main(void){
    char str1[] = "str1";
    char str2[] = "str2";
    s1 = s2;
    printf("%s\n",s2);
    return 0;
}
$ gcc test.c
test.c: In function ‘main’:
test.c:7:5: error: assignment to expression with array type
  s1 = s2;

当たり前だけどエラー
strcpyなどを使用せざるをえない。
しかし以下のようにポインタで宣言を行うと

#include <stdio.h>

int main(void){
    char *s1_ = "str1";
    char *s2_ = "str2";
    s1_ = s2_;
    printf("%s\n",s2_);
    return 0;
}
$ gcc test.c
$ ./a.out
str2

実行できる
str1もstr1_も"str1"の's'へのポインタだと思うのだが、恐らく前者の方法だとint型の配列同様に扱われ配列同士の代入が禁止になってるのではないかと考えられる。
ポインタで宣言すれば配列で宣言したわけではないので、ポインタ変数同士のアドレスの交換でこのように文字列を代入できるのではないだろうか。
この原因に関してはよくわからないので、詳しい方いたら教えてください。