数组的名字是C语言中的指针吗? 如果不是,数组的名称和指针变量之间的区别是什么?
当前回答
下面的示例提供了数组名和指针之间的具体区别。假设你想用给定的最大维数表示一条一维线,你可以用数组或指针来实现:
typedef struct {
int length;
int line_as_array[1000];
int* line_as_pointer;
} Line;
现在让我们看看下面代码的行为:
void do_something_with_line(Line line) {
line.line_as_pointer[0] = 0;
line.line_as_array[0] = 0;
}
void main() {
Line my_line;
my_line.length = 20;
my_line.line_as_pointer = (int*) calloc(my_line.length, sizeof(int));
my_line.line_as_pointer[0] = 10;
my_line.line_as_array[0] = 10;
do_something_with_line(my_line);
printf("%d %d\n", my_line.line_as_pointer[0], my_line.line_as_array[0]);
};
这段代码将输出:
0 10
这是因为在do_something_with_line函数调用中,对象被复制,因此:
指针line_as_pointer仍然包含它所指向的相同地址 数组line_as_array被复制到一个没有超出函数作用域的新地址
因此,当你直接将数组输入到函数时,数组不是由值给出的,当你将它们封装在结构中时,它们是由值给出的(即复制),这概述了与使用指针实现相比,在行为上的主要区别。
其他回答
数组是数组,指针是指针,但在大多数情况下,数组名被转换为指针。经常使用的一个术语是它们衰减为指针。
这是一个数组:
int a[7];
A包含7个整数的空格,你可以在其中一个整数中赋值,就像这样:
a[3] = 9;
这里有一个指针:
int *p;
P不包含任何整数的空格,但它可以指向整数的空格。例如,我们可以将它设置为指向数组a中的一个位置,例如第一个:
p = &a[0];
让人困惑的是,你也可以这样写:
p = a;
这不会将数组a的内容复制到指针p(不管这意味着什么)。相反,数组名a被转换为指向其第一个元素的指针。这个分配和之前的一样。
现在你可以像使用数组一样使用p:
p[3] = 17;
这样做的原因是C语言中的数组解引用操作符[]是用指针定义的。X [y]的意思是:从指针X开始,在指针指向的地方向前移动y个元素,然后取那里的任何元素。使用指针算术语法,x[y]也可以写成*(x+y)。
为了使它适用于普通数组,例如我们的a,[3]中的名称a必须首先转换为一个指针(指向a中的第一个元素)。然后我们向前推进3个元素,并取其中的任何元素。换句话说:取数组中位置为3的元素。(它是数组中的第四个元素,因为第一个元素编号为0。)
因此,总的来说,C程序中的数组名(在大多数情况下)被转换为指针。一个例外是在数组上使用sizeof操作符。如果在这种情况下a被转换为指针,sizeof a将给出指针的大小,而不是实际数组的大小,这将是相当无用的,所以在这种情况下a意味着数组本身。
下面的示例提供了数组名和指针之间的具体区别。假设你想用给定的最大维数表示一条一维线,你可以用数组或指针来实现:
typedef struct {
int length;
int line_as_array[1000];
int* line_as_pointer;
} Line;
现在让我们看看下面代码的行为:
void do_something_with_line(Line line) {
line.line_as_pointer[0] = 0;
line.line_as_array[0] = 0;
}
void main() {
Line my_line;
my_line.length = 20;
my_line.line_as_pointer = (int*) calloc(my_line.length, sizeof(int));
my_line.line_as_pointer[0] = 10;
my_line.line_as_array[0] = 10;
do_something_with_line(my_line);
printf("%d %d\n", my_line.line_as_pointer[0], my_line.line_as_array[0]);
};
这段代码将输出:
0 10
这是因为在do_something_with_line函数调用中,对象被复制,因此:
指针line_as_pointer仍然包含它所指向的相同地址 数组line_as_array被复制到一个没有超出函数作用域的新地址
因此,当你直接将数组输入到函数时,数组不是由值给出的,当你将它们封装在结构中时,它们是由值给出的(即复制),这概述了与使用指针实现相比,在行为上的主要区别。
当数组用作值时,它的名称表示第一个元素的地址。 当数组不用作值时,其名称代表整个数组。
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 */
数组名的行为类似于指针,指向数组的第一个元素。例子:
int a[]={1,2,3};
printf("%p\n",a); //result is similar to 0x7fff6fe40bc0
printf("%p\n",&a[0]); //result is similar to 0x7fff6fe40bc0
这两个print语句将为一台机器提供完全相同的输出。在我的系统中,它给出:
0x7fff6fe40bc0
如果数组类型的表达式(例如数组名)出现在更大的表达式中,并且它不是&或sizeof操作符的操作数,则数组表达式的类型将从“T的n元素数组”转换为“指向T的指针”,并且表达式的值是数组中第一个元素的地址。
简而言之,数组名不是指针,但在大多数上下文中,它被视为指针。
Edit
在评论中回答这个问题:
如果我使用sizeof,我只计算数组元素的大小吗?然后数组“head”也占用了关于长度和指针的信息的空间(这意味着它占用了更多的空间,比一个正常的指针会)?
当你创建一个数组时,唯一分配的空间是元素本身的空间;没有为单独的指针或任何元数据具体化存储。鉴于
char a[10];
你在记忆中得到的是
+---+
a: | | a[0]
+---+
| | a[1]
+---+
| | a[2]
+---+
...
+---+
| | a[9]
+---+
表达式a指向整个数组,但是数组元素本身没有对象a。因此,sizeof a给出整个数组的大小(以字节为单位)。表达式&a给出了数组的地址,它与第一个元素的地址相同。&a和&a[0]之间的区别是result1的类型- char(*)[10]在第一种情况下,char *在第二种情况下。
奇怪的是,当你想访问单个元素时——表达式a[i]被定义为*(a + i)的结果——给定一个地址值a,从该地址偏移i个元素(不是字节)并解引用结果。
The problem is that a isn't a pointer or an address - it's the entire array object. Thus, the rule in C that whenever the compiler sees an expression of array type (such as a, which has type char [10]) and that expression isn't the operand of the sizeof or unary & operators, the type of that expression is converted ("decays") to a pointer type (char *), and the value of the expression is the address of the first element of the array. Therefore, the expression a has the same type and value as the expression &a[0] (and by extension, the expression *a has the same type and value as the expression a[0]).
C语言源自早期的一种叫做B的语言,在B中a是一个独立于数组元素[0]、[1]等的指针对象。Ritchie想要保留B的数组语义,但他不想在存储单独的指针对象时搞得一团糟。所以他把它扔掉了。相反,编译器会在必要时将数组表达式转换为指针表达式。
记住,我说过数组不存储任何关于其大小的元数据。一旦数组表达式“衰减”为指针,您所拥有的就是一个指向单个元素的指针。该元素可以是元素序列的第一个,也可以是单个对象。根据指针本身是无法知道的。
当你将一个数组表达式传递给一个函数时,函数接收到的只是一个指向第一个元素的指针——它不知道数组有多大(这就是为什么gets函数如此危险,最终被从库中删除了)。为了让函数知道数组中有多少个元素,必须使用哨兵值(例如C字符串中的0结束符),或者必须将元素数量作为单独的参数传递。
这*可能*影响地址值的解释方式-取决于机器。
推荐文章
- 如何读一个文本文件到一个列表或数组与Python
- 如何在Python中将十六进制字符串转换为字节?
- C多行宏:do/while(0) vs作用域块
- 与push()相反;
- 用“+”(数组联合运算符)合并两个数组如何工作?
- time_t最终的类型定义是什么?
- 我需要显式处理负数或零时,总和平方数字?
- 函数名周围的括号是什么意思?
- 用C语言创建自己的头文件
- 使arrayList.toArray()返回更具体的类型
- 如何从对象数组中通过对象属性找到条目?
- 如何从关联数组中删除键及其值?
- 格式化IO函数(*printf / *scanf)中的转换说明符%i和%d之间的区别是什么?
- main()中的Return语句vs exit()
- 如果不是内存地址,C指针到底是什么?