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)
它没有分配任何ints.你可以修改它:
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 次 |
| 最近记录: |