数组与指针区别的个人理解
在编程中我们经常会会用到数组与指针,也都知道可以通过指针来访问数组,那这二者又有什么区别呢?
我们来看下面的几个代码:
head.c
char *p = "abcdefg";
test.c
#include<stdio.h>
extern char *p;
int main()
{
printf("%s\n", p);
return 0;
}
我们创建了一个工程,将head.c和test.c 一起放入源文件中,在head.c中创建指针变量char *p = “abcdefg”,然后再在test.c中声明它,再通过%s的形式将其输出。这时屏幕上输出了abcdefg的值。
我们对代码做部分修改:
head.c
char *p = "abcdefg";
test.c
#include<stdio.h>
extern char p[];
int main()
{
printf("%s\n", p);
return 0;
}
在这我们可以看到,在head.c中,我们定义的变量为字符指针变量,而在test.c中我们将它声明为了字符数组,这时,再对p以%s输出,输出的值为随机值。那这是什么原因呢?
我们再对它做研究:
我们知道,对于head.c中的指针变量p,对它的初始化,并不是将”abcdefg”的值存入了p中,而是常量字符串中首元素‘a’的地址存储到了p中。对于test.c中声明的数组p来说,它是将head.c中的指针变量声明为了数组,由于它们是同一块空间,所以它是将指针p的值,也就是‘a’的地址,当成了值存到了数组中,因此我们在这里输出的就是‘a’的地址,我们可以对它做进一步的验证。
我们将test.c中p数组的每个元素以16进制输出,然后再重新定义一个指针指向常量字符串“abcdefg”(相同的常量字符串在一个程序中,只存在一份,所以地址相同),由于此电脑存储为小端存储,因此将两个输出对比,我们可以看p中存储的正是常量字符串的首地址,也就是‘a’的地址。图解如下:
那如果我们已经将p指针声明成了p数组,我们怎么保证它输出的正确性呢?我们看下面的代码:
以%s格式输出,我们需要给到abcdefg的地址,而现在p[]数组的值就是字符串的地址,因此我们只需要一次将数组的所有内容读出即可,我们知道p(数组名)的值也代表了首元素的地址,因此,我们将p强制类型转换为char**,这样p中的值就可以被以地址的形式一次全部访问到,我们再对其解引用,就得到了a的地址,这时我们就可以得到想要得到的值,同时,这也印证了我们前面的分析。
那如果在head.c中将其定义为数组,在test.c中将其声明为指针呢?指针大小为4个字节,所以我们将字符串改为4个字节(包括’/0’,所以为’abc’)。
head.c
char p[] = "abc";
test.c
#include<stdio.h>
extern char *p;
int main()
{
printf("%s\n", p);
return 0;
}
用与前面一样的分析方法,我们可以得出结论,当前p中存储的并不是”abc”的地址而是”abc“的值。我们可以以16进制输出p,看到p的值具体是多少:
我们对其做以图解:
现在,我们要以%s格式输出“abc”,我们只需要拿到a的地址,就可以将其输出,而p的值正是“abc”,所以这次我们要输出的值为p,而不是p指向的空间的值,因此,我们只要拿到p的地址,将其强转为char*类型,那么以%s形式输出就得到了我们需要的值。