数组与指针

有一天无意之间看到一篇文章很不错,里面总结了一些指针与数组的关系,概括性很强,文章在下面,看的时候发现有些问题,说的不是很好懂,我说说我的见解:

首先指针和数组的名字表示的就是一个首地址,这一点可以肯定,但是数组是在堆里分配,而指针是在栈里分配,两者有者本质的区别,数组是有固定的地址,但是指针如果不使用new或者malloc的话,那么他就是处在一个“游离”的状态。

先看下面的文章,我再说说一些要记住的,或者说要注意的!

什么时候数组与指针相同

所有作为函数参数的数组名总是可以通过编译器转换为指针。
在其他所有情况下,数组的声明就是数组,指针的声明就是指针,两者不能混淆。

但在语句或表达式中引用时,数组总是可以写成指针的形式,两者可以互换。

然而,数组和指针在编译器处理时是不同的,在运行时的表示形式也是不一样的。
对编译器而言,一个数组就是一个地址,一个指针就是一个地址的地址,你应该根据情况做出选择。

为什么会发生混淆

当人们学习编程时,一开始总是把所有的代码都放到一个函数里。
随着水平的进步,他们把代码分别放在几个函数中。
在水平继续提高后,他们最终学会了如何用几个文件来构造一个程序。

什么时候数组和指针是相同的?C语言标准对此作了如下说明:
规则1 表达式中的数组名(与声明不同)被编译器当作一个指向该数组第一个元素的指针。
规则2 下标总是与指针的偏移量相同。
规则3 在函数参数的声明中,数组名被编译器当作指向该数组的第一个元素的指针。

规则1:“表达式中的数组名”就是指针

规则1和2合在一起理解,就是对数组下标的引用总是可以写成“一个指向数组的起始地址的指针加上偏移量。”
(个人认为,表述为“一个指向该数组第一个元素的指针加上偏移量”更明确。)

对数组的引用如a[i]在编译时总是被编译器改写成*(a+i)的形式。
C语言标准要求编译器必须具备这个概念性的行为。
于是,a[6]和6[a]都是正确的。

编译器自动把下标值的步长调整到数组元素的大小。
这就是为什么指针总是有类型限制,每个指针只能指向一种类型的原因,
因为编译器需要知道对指针进行解除引用操作时应取几个字节,以及每个下标的步长应取几个字节。

规则2:C语言把数组下标作为指针的偏移量

事实上,下标范围检测被认为并不值得加入到C语言中。

数组下标是定义在指针的基础上的,所以优化器常常可以把它转换为更有效率的指针表达式,
并生成相同的机器指令。

C语言把数组下标改写成指针偏移量的根本原因是指针和偏移量是底层硬件所使用的基本模型。

为什么C语言把数组形参当作指针

之所以要把传递给函数的数组参数转换为指针是出于效率的考虑,
这个理由常常也是对违反软件工程做法的辩解。

我们倾向于始终把参数定义为指针,因为这是编译器内部所使用的形式。
但从另一方面,有些人觉得int table[]比int *table更能表达程序员的意图。

数组片段的下标

向函数传递数组前面一个位置的地址(a[-1]),这样就可以使数组下标从1到N,而不是从0到N-1。
不幸的是,这个手段完全为标准所不容,所以你千万不要告诉别人是我告诉了你这个方法。

C语言的多维数组

但所有其他语言都把这称为“数组的数组”

C语言里有一种别的语言称为数组的数组的形式,但C语言称它为多维数组。
C语言中的数组就是一维数组,而这个数组的元素可以是另一个数组。

编译器在编译时会把carrot[i][j]解析为*(*(carrot+i)+j)的形式。

如何分解多维数组

在“数组的数组的数组”中的每一个单独的数组都可以看作是一个指针。
这是因为在表达式中的数组名被编译器当作“指向数组第一个元素的指针”。

内存中数组是如何布局的

在C语言的多维数组中,最右边的下标是最先变化的,这个约定称为“行主序”。

如何对数组进行初始化

只能够在数组声明时对它进行整体的初始化。
之所以存在这个限制,并没有过硬的理由。

在IEEE754标准浮点数实现中,0.0和0的位模式是完全一样的。

初始化二维字符串数组:
char vegetables[][9] =
{
"beet",
"barley",
"basil",
"broccoli",
"beanes"
};

一种有用的方法是建立指针数组,字符串常量可以数组初始化值:
char *vegetables[] =
{
"beet",
"barley",
"basil",
"broccoli",
"beanes"
}; 

以上是人家的文章的内容,看完之后肯定感觉很不错吧,在上面的内容之余我再补充点东西:

对于:

char heart[] = "asdfasdf";

char *head = "gggggggggg";

由上面的文章我们可以知道,使用数组的方法和指针的方法都可以,即:可以用heart[i],head[i],又可以使用*(heart+i),*(head+i),但是是不是都可以自加或者自减 哦?

不是

指针可以,开始我们说了指针可以认为是游离的,所以他本身的值可以变化,而自加就是让指针的首地址变化,但是数组是固定的,要变化一个数组的首地址就要用到双指针,如**heart,这里不说,试图用单指针变化数组的首地址是不行的。

另外,可以把一个数组赋值给指针,但是不可以把一个指针赋值给数组,也是这个道理!这也就是为什么指针申明和定义分开进行可以,如:

char *p;

p = "asdf";

但是指针不可以如

char p[5];

p = "asdf";//试图改变数组的首地址!wrong!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值