Tho*_*thy 235
数组是一个数组,指针是指针,但在大多数情况下,数组名称将转换为指针.经常使用的一个术语是它们会衰减到指针.
这是一个数组:
int a[7];
Run Code Online (Sandbox Code Playgroud)
a
包含七个整数的空间,你可以在其中一个中赋值赋值,如下所示:
a[3] = 9;
Run Code Online (Sandbox Code Playgroud)
这是一个指针:
int *p;
Run Code Online (Sandbox Code Playgroud)
p
不包含任何整数空格,但它可以指向整数的空格.例如,我们可以将其设置为指向数组中的一个位置a
,例如第一个:
p = &a[0];
Run Code Online (Sandbox Code Playgroud)
可能令人困惑的是你也可以这样写:
p = a;
Run Code Online (Sandbox Code Playgroud)
这并没有数组的内容复制a
到指针p
(无论这将意味着).相反,数组名称a
将转换为指向其第一个元素的指针.因此,分配与前一个分配相同.
现在您可以p
以类似的方式使用数组:
p[3] = 17;
Run Code Online (Sandbox Code Playgroud)
这有效的原因是C,中的数组解除引用运算符[ ]
是根据指针定义的.x[y]
意思是:从指针开始x
,步骤y
元素在指针指向的位置之后前进,然后取出那里的任何东西.使用指针算术语法,x[y]
也可以写成*(x+y)
.
为了做到这与正常的阵列,比如我们的工作a
,该名称a
中a[3]
必须首先被转换为一个指针(在第一元件a
).然后我们向前迈出3个元素,并采取任何在那里.换句话说:将元素放在数组中的第3位.(这是数组中的第四个元素,因为第一个元素编号为0.)
因此,总之,C程序中的数组名称(在大多数情况下)转换为指针.一个例外是我们sizeof
在数组上使用运算符.如果a
在此上下文中转换为指针,sizeof a
则会给出指针的大小而不是实际数组的大小,这将是相当无用的,因此在这种情况下a
意味着数组本身.
pmg*_*pmg 33
当数组用作值时,其名称表示第一个元素的地址.
当数组未用作值时,其名称表示整个数组.
int arr[7];
/* arr used as value */
foo(arr);
int x = *(arr + 1); /* same as arr[1] */
/* arr not used as value */
size_t bytes = sizeof arr;
void *q = &arr; /* void pointers are compatible with pointers to any object */
Run Code Online (Sandbox Code Playgroud)
Joh*_*ode 17
如果数组类型的表达式(例如数组名称)出现在更大的表达式中并且它不是&
或sizeof
运算符的操作数,那么数组表达式的类型将从"N元素数组T"转换为"指向T的指针",表达式的值是数组中第一个元素的地址.
总之,数组名不是指针,但在多数情况下它被视为好像它是一个指针.
编辑
回答评论中的问题:
如果我使用sizeof,我是否只计算数组元素的大小?然后数组"head"也占用了有关长度和指针的信息的空间(这意味着它需要比普通指针更多的空间)?
创建数组时,唯一分配的空间是元素本身的空间; 没有存储实现单独的指针或任何元数据.特定
char a[10];
Run Code Online (Sandbox Code Playgroud)
你记忆中得到的是什么
+---+
a: | | a[0]
+---+
| | a[1]
+---+
| | a[2]
+---+
...
+---+
| | a[9]
+---+
Run Code Online (Sandbox Code Playgroud)
的表达 a
指的是整个阵列,但没有对象 a
从数组元素本身分离.因此,sizeof a
为您提供整个数组的大小(以字节为单位).表达式&a
为您提供数组的地址,该地址与第一个元素的地址相同.&a
和之间的差异&a[0]
是结果1的类型- char (*)[10]
在第一种情况下和char *
在第二种情况下.
事情变得奇怪的是当你想要访问单个元素时 - 表达式a[i]
被定义为*(a + i)
- 给定地址值a
,来自该地址的偏移i
元素(不是字节)并取消引用结果.
问题是它a
不是指针或地址 - 它是整个数组对象.因此,在C规则,无论何时编译器看到阵列类型的表达式(如a
,已键入char [10]
)和该表达式不是的操作数sizeof
或一元&
运算符,该表达式的类型被转换("衰变")到指针类型(char *
),表达式的值是数组的第一个元素的地址.因此,表达式 a
具有与表达式相同的类型和值&a[0]
(并且通过扩展,表达式*a
具有与表达式相同的类型和值a[0]
).
C由称为B更早的语言导出,B中a
是从数组元素一个单独的指针对象a[0]
,a[1]
等里奇想保持B的数组语义,但他不想惹存储单独的指针对象.所以他摆脱了它.相反,编译器将根据需要在转换期间将数组表达式转换为指针表达式.
请记住,我说数组不存储任何有关其大小的元数据.只要该数组表达式"衰减"到指针,您所拥有的就是指向单个元素的指针.该元素可以是元素序列中的第一个,也可以是单个对象.根据指针本身无法知道.
当你传递一个数组表达式的功能,所有功能接收到的是一个指向第一个元素-它不知道数组有多大(这就是为什么gets
功能是这样的威胁,并最终从库中移除).要使函数知道数组有多少元素,必须使用sentinel值(例如C字符串中的0终止符),或者必须将元素数作为单独的参数传递.
一个像这样声明的数组
int a[10];
Run Code Online (Sandbox Code Playgroud)
分配内存10 int
秒.你不能修改,a
但你可以用指针算术a
.
像这样的指针只为指针分配内存p
:
int *p;
Run Code Online (Sandbox Code Playgroud)
它没有分配任何int
s.你可以修改它:
p = a;
Run Code Online (Sandbox Code Playgroud)
并使用数组下标,你可以使用:
p[2] = 5;
a[2] = 5; // same
*(p+2) = 5; // same effect
*(a+2) = 5; // same effect
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
61817 次 |
最近记录: |