今天在读《C和指针》时,读到了“字符串常量”这个东西,书里提到了“字符串常量的直接值是一个指向字符类型的指针,即char*,因此不能直接将一个字符串常量赋值给字符数组”,读到这里我也是似懂非懂,因此特地去网上查了查。以下是我的收获:
以下部分内容摘自(https://blog.csdn.net/yahohi/article/details/7427724)
首先要搞清楚编译程序占用的内存的分区形式:
一、预备知识—程序的内存分配
一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap)—一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。
4、文字常量区—常量字符串就是放在这里的。程序结束后由系统释放。
5、程序代码区
这是一个前辈写的,非常详细
int a=0; //全局初始化区
char p1; //全局未初始化区
main()
{
int b;栈
char s[]=“abc”; //栈
char p2; //栈
char p3=“123456”; //123456\0在常量区,p3在栈上。
static int c=0; //全局(静态)初始化区
p1 = (char)malloc(10);
p2 = (char)malloc(20); //分配得来得10和20字节的区域就在堆区。
strcpy(p1,“123456”); //123456\0放在常量区,编译器可能会将它与p3指向的"123456"优化成一个地方。
}
首先,我们要知道
char *a中的a是个指向字符类型的指针,这是一个变量;
char a[]中的a也是一个指向字符类型的指针,但它是一个常量,常量是不能再给它赋值的,就像比不能写 3=2 这样的代码来给3赋值。
通过阅读我们可以知道,char * a=“abc”和char a[]="abc"在内存中存放是有差别的,即char *a=“abc”中的“abc”是存放于字符常量区的,指针a只是指向了这个地址;
char a[]="abc"中的“abc”其实是放在栈中的,它是字符常量区中“abc”的一份拷贝。
看看下面这段代码你就明白了
#include <stdio.h>
int main()
{
char * a1 = "abc";
char a2[] = "abc";
char *a3 ="abc";
char a4[] = "abc";
printf("char * a:%p\n",a1);//打印a1的值
printf("char a2[]:%p\n",a2);//打印a2的值
printf("char *a3:%p\n",a3);//打印a2的值
printf("char a4[]:%p\n",a4);//打印a2的值
return 0;
}
我在这段代码里声明了两个字符指针变量、两个数组常量指针,代码执行结果如下:
显而易见字符指针变量a 和a3的值是一样的,这说明它们指向同一块内存,这块内存就是上文所说的字符常量区;字符数组指针a2和a3的值不同且相差4字节,这说明它们指向的内存是不相同的,它们的“abc”其实是对字符常量区中“abc”的一份拷贝,并且数据是存放在栈中的,至于它们的地址相差四个字节,是因为字符数组中在结尾加了一个结束符——‘\0’(也称为NUL)。
至于之前说的“不能直接将一个字符串常量赋值给字符数组”可以这样理解:的确是不能直接赋值,但可以通过复制以后再赋值呀,即把字符串拷贝到栈中,然后给数组指针赋值!代码的话就是:char a[]=“abc”。
我们再来考虑一个问题:能不能修改char*a指向的字符常量区的值呢?
代码如下:
#include <stdio.h>
#include <string.h>
int main()
{
char * a="abc";
*a = 'b';
printf("%c\n",*a);
return 0;
}
我将指针a所指向的第一个字符——‘a’修改为字符‘b’。
结果程序崩溃了
这说明字符常量区的数据是不可以修改的!为什么呢?因为在你的程序中可能有很多个类似于char *a这样的指针变量在使用到了字符常量区的“abc”,如果你在这里通过指针修改了“abc”的值,那么程序中使用“abc”的其他地方就变得不确定了!
其实如果你翻看了《c和指针》你还会发现,在K&R C标准中,这里的修改操作是可以的,因为在该标准中字符串常量是分开存储的,而不是只存储在一个地方。
怎么样,有没有感受到C语言指针的危险和魅力所在?