Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C中数组变量vs指针的地址和内容_C_Arrays_Pointers - Fatal编程技术网

C中数组变量vs指针的地址和内容

C中数组变量vs指针的地址和内容,c,arrays,pointers,C,Arrays,Pointers,我知道C中的数组本质上就像指针一样,除了在(sizeof())这样的地方。除此之外,指针和数组变量除了在声明上没有区别 例如,考虑两个声明: int arr[] = {11,22,33}; int *arrptr = arr; 下面是它们的行为方式: printf("%d %d", arrptr[0], arr[0]); //11 11 printf("%d %d", *arrptr, *arr); //11 11 但我发现他们还有一个不同之处: //the outpu

我知道C中的数组本质上就像指针一样,除了在(
sizeof()
)这样的地方。除此之外,指针和数组变量除了在声明上没有区别

例如,考虑两个声明:

int arr[] = {11,22,33};
int *arrptr = arr; 
下面是它们的行为方式:

printf("%d  %d", arrptr[0], arr[0]);  //11  11
printf("%d  %d", *arrptr, *arr);      //11  11
但我发现他们还有一个不同之处:

//the outputs will be different on your machine
printf("%d  %d", &arrptr, &arr);   //2686688  2686692 (obviously different address)
printf("%d  %d", arrptr, arr);     //2686692  2686692 (both same)

这里的问题是最后一行。我知道
arrptr
包含
arr
的地址。这就是为什么最后一行中打印的第一个地址是
2686692
。我还了解到,
arr
的地址(
&arr
)和内容(
arr
)在逻辑上应该与
arrptr
相同。但是,究竟是什么(在实现级别内部)导致了这种情况发生?

当一元
&
运算符应用于数组时,它返回指向数组的指针。当应用于指针时,它返回指向指针的指针。此运算符与
sizeof
一起表示数组不衰减为指针的少数上下文

换句话说,
&arrptr
类型为
int**
,而
&arr
类型为
int(*)[3]
&arrptr
是指针本身的地址,
&arr
是数组的开头(如
arrptr

微妙的部分:
arrptr
&arr
具有相同的值(都指向数组的开头),但类型不同。如果您对它们执行任何指针运算,则会显示此差异–使用
arrptr
时,隐含偏移量将为
sizeof(int)
,而使用
&arr
时,隐含偏移量将为
sizeof(int)*3


此外,您应该使用
%p
格式说明符打印指针,在强制转换到
void*

后,当一元
&
运算符应用于数组时,它返回指向数组的指针。当应用于指针时,它返回指向指针的指针。此运算符与
sizeof
一起表示数组不衰减为指针的少数上下文

换句话说,
&arrptr
类型为
int**
,而
&arr
类型为
int(*)[3]
&arrptr
是指针本身的地址,
&arr
是数组的开头(如
arrptr

微妙的部分:
arrptr
&arr
具有相同的值(都指向数组的开头),但类型不同。如果您对它们执行任何指针运算,则会显示此差异–使用
arrptr
时,隐含偏移量将为
sizeof(int)
,而使用
&arr
时,隐含偏移量将为
sizeof(int)*3

此外,在转换到
void*
之后,您应该使用
%p
格式说明符打印指针

我知道C中的数组本质上就像一个指针,除了在(sizeof())这样的地方。除此之外,指针和数组变量除了在声明上没有区别

事实并非如此。在大多数情况下,数组表达式被视为指针表达式,但数组和指针是完全不同的

当您将数组声明为

T a[N];
它在记忆中被列为

   +---+ 
a: |   | a[0]
   +---+
   |   | a[1]
   +---+
   |   | a[2]
   +---+
    ...
   +---+
   |   | a[N-1]
   +---+
有一件事很明显——数组的第一个元素的地址与数组本身的地址相同。因此,
&a[0]
&a
将产生相同的地址值,尽管这两个表达式的类型不同(
T*
vs.
T(*)[N]
),并且该值可能会根据类型进行调整

这里有点让人困惑——除非它是
sizeof
或一元
&
运算符的操作数,或者是用于初始化声明中字符数组的字符串文字,否则“N-element array of
T
”类型的表达式将转换为(“decay”)类型的表达式“指向
T
”的指针,表达式的值将是数组第一个元素的地址

这意味着表达式
a
也会产生与
&a[0]
&a
相同的地址值,并且具有与
&a[0]
相同的类型。综合起来:

Expression        Type        Decays to         Value
----------        ----        ---------         -----
         a        T [N]       T *               Address of a[0]
        &a        T (*)[N]    n/a               Address of a
        *a        T           n/a               Value of a[0]
      a[i]        T           n/a               Value of a[i]
     &a[i]        T *         n/a               Address of a[i]
  sizeof a        size_t      n/a               Number of bytes in a
那么,为什么这个转换规则首先存在呢

C源于早期的一种叫做B(go figure)的语言。B是一种无类型的语言 语言-一切基本上都被视为一个无符号整数 被视为固定长度“单元格”的线性数组。当您声明 数组中,留出一个额外的单元格来存储到第一个数组的偏移量 数组的元素:

  +---+
a:|   | ----+
  +---+     |
   ...      |
    +-------+
    |
    V
  +---+
  |   | a[0]
  +---+
  |   | a[1]
  +---+
   ...
  +---+
  |   | a[N-1]
  +---+
数组下标操作
a[i]
被定义为
*(a+i)
;也就是说,获取存储在
a
中的偏移值,添加
i
,并取消对结果的引用

当Ritchie设计C时,他想保留B的数组语义,但不知道如何处理指向第一个元素的显式指针,所以他放弃了它。因此,C保留了数组订阅定义
a[i]=*(a+i)
(给定地址
a
,从该地址偏移
i
元素并取消对结果的引用),但不为指向数组第一个元素的单独指针留出空间-而是将数组表达式
a
转换为指针值

这就是为什么在打印
arr
arrptr
的值时会看到相同的输出。请注意,应该使用
%p
转换说明符打印指针值,并将参数强制转换为
void*

printf( "arr = %p, arrptr = %p\n", (void *) arr, (void *) arrptr );
在C中,这几乎是唯一需要显式将指针值转换为
void*
的地方

我知道C中的数组的行为本质上类似于po