我有一个非常奇怪的指针示例,需要您的帮助。通常,指针用于指向变量(请参阅下面的第一个示例),但指向数组时。我不明白为什么它不再需要引用来获取数组(参见下面的第二个例子)
printf("TEST: %i\n", x[i]);// I expect this should be *x[i]
这确实很奇怪。它只是一个C约定或你如何解释这个?
编辑::由于很多人提供了明确的答案,我想提出另一个小的跟进问题,因为你们所有人都提到了x [i] = *(x + i),怎么样? x [i] [j]对于二维数组?它等同于什么?是否需要取消引用?
使用正常变量
int j = 4;
int* pointerj=&j;//pointerj holds address of j or points to j
printf("%d",*pointerj); returns the value that pointer j points to
使用数组:
#include <stdio.h>
#include <stdlib.h>
int *function(unsigned int tags) {
int i;
int *var;
var = (int*)malloc(sizeof(int)*tags); // malloc is casted to int* type , allocated dynamical memory, it returns a pointer!
//so now var holds the address to a dynamical array.
for (i = 0; i < tags; i++) {
var[i] = i;
}
return var;
}
int main() {
int *x;
int i;
x = function(10);
for (i = 0; i < 10; i++) {
printf("TEST: %i\n", x[i]);// I expect this should be *x[i]
}
free(x); x = NULL;
return 0;
}
答案 0 :(得分:3)
不明白为什么它不再需要取消引用来获取数组(元素)
嗯,你 解除引用,它只是没有使用解除引用运算符*
。
数组下标运算符[]
在此处作为解除引用的工作。引用C11
,章节§6.5.2.1
后缀表达式后跟方括号
[]
中的表达式是下标 指定数组对象的元素。下标运算符[]
的定义 是E1[E2]
与(*((E1)+(E2)))
相同。由于转换规则 应用于二进制+
运算符,如果E1
是一个数组对象(等效地,指向 数组对象的初始元素)和E2
是一个整数,E1[E2]
表示E2
- thE1
的元素(从零开始计算)。
这是一种语法糖。表达式x[i]
和*(x+i)
是等效的。后者满足了你的期望,而第一个,伪装了解除引用操作符,但完成了你预期的完全相同的工作。
那就是说,也要密切关注数据类型。你所期待的,*x[i]
行的某些东西将是无效的,因为它归结为类似`((x + i))的东西。现在,
x
的类型为int []
(整数数组,它衰减为指向整数的指针)x+i
为您提供指向int
类型结果的指针。int
。*
,现在将尝试对类型int
(不是指针)的操作数进行操作,并且此操作将是语法错误,因为解除引用运算符的约束说,一元
*
运算符的操作数应具有指针类型。
在C11
中,章节§6.5.3.2。
回答其他问题:
让我再次使用这句话,第2段,第6.5.2.1章
连续的下标运算符指定多维数组对象的元素。 如果
E
是尺寸为n
的{{1}}维数组(n ≥ 2)
,则为i × j × . . . × k
(用作 除了左值之外)转换为指向E
- 维数组的指针 尺寸(n − 1)
。如果一元j × . . . × k
运算符明确地应用于此指针,或 隐式地,作为下标的结果,结果是引用的*
- 维度 数组,如果用作左值而不是lvalue,它本身会被转换为指针。它跟随 从这个角度来看,数组以行主要顺序存储(最后一个下标变化最快)。考虑声明
定义的数组对象(n − 1)
此处
int x[3][5];
是x
的{{1}}数组;更准确地说,3 × 5
是一个由三个元素对象组成的数组,每个对象都是一个 五个整数阵列。在表达式int
中,相当于x
,x[i]
首先转换为 指向五个整数的初始数组的指针。然后根据概念上(*((x)+(i)))
的类型调整x
需要将i
乘以指针所指向的对象的大小,即五个x
的数组 对象。添加结果并应用间接以产生五个整数的数组。在使用时 表达式i
,该数组又转换为指向第一个整数的指针,因此int
产生x[i][j]
。
答案 1 :(得分:1)
这没关系。不*那里。
如果指针template <typename T> class abc{
void method(T i)
{
if(i is a string)
do sth
else if(i is an integer)
do sth else
else if(i is a double)
do sth else else
}
}
指向有效数据数组,例如:
int *a
使用int *a;
int arr[5] = {1, 2, 3, 4, 5];
a = arr;
您已取消引用指针,a[0]
不需要*
,因为a[0]
与*(a + 0)
相同。
您可以进一步为读者提供更复杂的代码。
您可以在示例中使用i[x]
而不是x[i]
。为什么?
x[i]
等于*(x + i)
但它也等同于*(i + x)
,这是C中的数组。
即使使用数字,例如x[3]
或3[x]
也可以获得相同的结果。
答案 2 :(得分:1)
在C中,在[x]处做x [i]是等价的(是的,我知道)。您的编译器通过执行以下操作来编译它:
*(x + i),您可以在其中检索自己喜欢的符号。
x + i是一个指针,你从x开始并由i前进。结果考虑了指针的类型(0xff与char *的地址不同于int *的地址)。
答案 3 :(得分:1)
你误解了数组是如何工作的。实际上,当使用int
之类的变量时,您应该通过
int x;
int *p2x = &x
但是在使用数组时,它有点不同。 int y[SOME_SIZE];
是内存中的一大块字节,*y
将带您到该内存位置的第一个元素,并取消引用它。 y[0]
也会这样做。 *y[0]
将首先获取y[0]
中的值,然后尝试取消引用它...而不是您通常想要的内容:(
答案 4 :(得分:1)
您问题的简单答案是:
数组的名称是指向数组第一个元素的指针。