关于指针常量和常量指针发现编译的一个有关问题,实在无法解释。求大神指教。

关于指针常量和常量指针发现编译的一个问题,实在无法解释。求大神指教。。
#include<stdio.h>
void main()
{
char  *p="abcde";
*p='t';
printf("%c",*p);
}
对于这个程序编译不报错,但我知道到肯定不能运行,运行的时候的却如此~(常量指针不能修改数据)
对于下面这个
#include<stdio.h>
void main()
{char a[5]="abcd";
char  *p;
p=a;
*p='t';
printf("%c",*p);
}
为什么竟然可以修改*p的值而且成功的运行了?输出了‘t’;
然后我又修改写成这样的:
#include<stdio.h>
void main()
{char a[5];
char  *p;
p="abcd";
*p='t';
printf("%c",*p);
}
编译不报错,但也无法运行。
自己想了想,本来应该都是编译不报错,都不能运行,但是第二个为什么可以运行成功。然后分析了下,由于没有写成const char *p,这个完整的形式,所以编译系统不知道,对于1和3由于都进行了p=“abcd”,所以系统对其进行了判别,变成const从而无法修改数据,对于2,始终没有对p进行类似的行为,所以,系统依旧无法辨别,一直到最后,导致可以成功进行数据的修改。。不知道这样理解对么? 还有就是平时需要写成const char *p么?如果不这样写,写成char *p,该默认为哪种情况呢?这样是不是会造成编译的一些错误?
指针常量 常量指针 字符串

------解决方案--------------------
#include<stdio.h>
void main()
{char a[5]="abcd";//a数据存在栈中(Main)连续5个字节,不是在数据区,其和p的地位相同,可以随意修改
char  *p;
p=a;
*p='t';
printf("%c",*p);
}


#include<stdio.h>
void main()
{char a[5];
char *p;
p=a;
p="abcd";//p指向a后,又马上转到程序数据区("abcd";和a没有关系,是一个字符串指针,数据在程序数据区)
*p='t';
printf("%c",*p);

------解决方案--------------------
char  *p="abcde";将指针p指向数据区的"abcde"
从语法上,p是可以修改其指向的内存的(语言标准怎么规定这种情况的我不记得了)
从实现上,"abcde"不能修改,不管你是通过指针p还是别的什么方式
在编译选项里可以设置"abcde"可修改,这样就可以通过p修改数据区的数据了,但不推荐这种行为
推荐的方式还是const char * p = "abcde";
------解决方案--------------------
第一种char *p和const char *p是一样的,但char *p="abcde";是分配在文字常量区的不能被修改。保持等价跟C语言的历史有关,C++建议用const char *p="abcde";而不是用char *p="abcde";可以避免看错而范不必要的错误。

第二种char a[5]="abcd",这个是数组,分配在栈上。然后char *p=a,使指针指向这个数组的地址。这个和第一种是完全不同的。
------解决方案--------------------
楼主,好好体会下!

char  *p="abcde";// 这句的意思:把"abcde"这个字符串常量地址的值赋值给char *p
                //也就是p指向了"abcde"这块内存地址,而“abcde”是存放在静态区,
     //不可修改,只可读,所以当你通过地址试图修改它的内容的时候,内存报错,只是可读


 char p[] = "abcde"; //这句的意思:把"abcde"这的字符串的值赋初始化给 p[]这个栈区间上
                    //而且这个只是在初始化时才能作的操作,其实的时候
                    //则用strcpy,memcpy!  和上面的意思完全不一样! 

------解决方案--------------------
你必须明白“左值”和“右值”明白了就解决了。

如;n=n+1; 
(n+1)这个是右值。右值是不允许修改,如果可以修改计算是不可能的。
想想,n+1,n/1,n*1,n-1;,n是多少呢,n是不变的,如果可以改变,计算是不确定的和无效的。

(n=)这个是左值。他必须是可修改的,如果不可修改计算将不可执行。

*p 在解引用时,你可以得到三个值中的一个,左值,右值和对象值(也就是地址。如果,他是一个指向指针的指针)。

char a[5];
char *p;
p=a;
*p //这时,你得到的是左值,即可修改的对象。

p="abcd";
*p;//这时解引用得到的是右值,即不可修改的值。

不知道,你理解了没有。
------解决方案--------------------

#include <stdio.h>
void main()
{
char  *p="abcde";
*p='t'; //Turbo C 下就能正常运行并且修改成功,得看编译器的实现
printf("%c",*p);
}

下面是除了Turbo C那种OK的情况

#include <stdio.h>
void main()
{
char a[5]="abcd"; //"abcd"的内存分配在栈区,可修改
char  *p;
p=a;
*p='t';
printf("%c",*p);
}


#include<stdio.h>
void main()
{
char a[5];
char  *p;
p="abcd";//"abcd"的内存分配在常量区,不可修改
*p='t';
printf("%c",*p);
}

上面的你都理解了const的问题也就明白了