Все значения от s1 до s5 сами по себе не char , они указатели на char . Итак, вы сравниваете адреса памяти каждой строки, а не сами строки.
Если вы отобразите адреса таким образом, вы увидите, над чем в действительности работают операторы сравнения:
#include <stdio.h>
int main() {
char *s1 = "Andreas";
char *s2 = "Andreas";
char s3[] = "Andreas";
char s4[] = "Andreas";
char *s5 = "Hello";
printf("%p\n", s1); // 0x80484d0
printf("%p\n", s2); // 0x80484d0
printf("%p\n", s3); // 0xbfef9280
printf("%p\n", s4); // 0xbfef9278
printf("%p\n", s5); // 0x80484d8
}
Точное расположение строк в памяти зависит от конкретной реализации. В этом случае s1 и s2 указывают на один и тот же статический блок памяти, но я не ожидаю, что это поведение будет переносимым.