初始化一个数组来储存字符串和初始化一个指针来存储字符串的区别是?
char arr[]="Hello";
const char* ptr="Hello"; //这是规范的写法
他们有什么区别?
主要的区别在于数组名arr是一个常量,而指针ptr是一个变量。
实际用起来呢?
1.两者都能用数组来表示和输出
for(i=0;i<5;i++)
{
putchar(arr[i]);
}
putchar("\n");
for(i=0;i<5;i++)
{
putchar(ptr[i]);
}
putchar("\n");
//Hello
//Hello
//两个输出结果是一样的
2.两者都能进行指针的加法操作
for(i=0;i<5;i++)
{
putchar(*(arr+i));
}
putchar("\n");
for(i=0;i<5;i++)
{
putchar(*(ptr+i));
}
putchar("\n");
//输出同上,也是一样的
但是只有指针能进行递增操作
指针表示:
while(*(ptr)!='\0')
{
putchar(*(ptr++));
}
如果你想对数组进行操作:
就会这样
或者你想把指针赋给arr?
还是会这样
原因就是最开始就说的,arr是一个常量,而常量只能作为右值,不能作为左值被赋值。
(例:x=3是被允许的,而3=x是不被允许的)
顺带一提:如果使用 ptr=arr 进行赋值,是没有任何问题的,但是会导致ptr指向其他的地址。
为什么要写const char* ptr?
首先来看 char* ptr
#include<stdio.h>
int main(void)
{
char *ptr="Hello";
ptr[1]='a';
}
或许编译器会允许这么做,但是这么做会导致一个很严重的后果,等会细说,先来看一个地址:
#include<stdio.h>
int main(void)
{
char arr[]="Hello";
char *ptr="Hello";
printf("%p\n",arr);
printf("%p\n",ptr);
printf("%p\n","Hello");
printf("%p\n","Hello");
}
这说明了什么?
第一,ptr和"Hello"的地址相同,而和arr的地址不同。
第二,"Hello"在printf函数中使用了两次,但地址都是一样的。
要注意的是,ptr的 "Hello" 非 arr 的 "Hello" ,两个是不一样的。
原因在于编译的时候,有一个静态存储区用来存储"Hello"这个字符串。
1.内存在开始运行后才会给数组分配内存,并且把"Hello"这个字符串拷贝到数组,数组他有自身的地址。
2.而指针只能指向一个地址,所以它仅仅是指向了"Hello"的地址,所以ptr的地址和"Hello"的地址是一致的。
那么再回到最开始的问题,为什么要用const?
现在我们已经知道了 ptr 和 arr 初始化的不同,一个是拷贝地址,一个是拷贝字符串。
所以当你打算
#include<stdio.h>
int main(void)
{
char *ptr="Hello";
ptr[1]='a';
printf("%s","Hello");
}
在你对ptr进行赋值后,程序编译后,"Hello"就已经分配在了静态内存里,以后计算机想要输出"Hello"都会使用同一个地址。
但你改变了这个地址上的值,就会导致内存访问出错,无法找到"Hello"的地址
所以即使编译通过了,你一运行,程序还是会直接挂掉。
(这个虽然运行,但是已经挂了,你打其他函数在里面也没办法执行)
不同编译器的结果
所以最好的写法,就是把指针初始化为字符串字面量的时候加上const,防止出错!!
或者干脆别用指针,直接用数组!!