- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
数组和指针在 C 和 C++ 中的实现方式不同吗?我遇到了这个问题,因为在这两种情况下,我们都从元素的起始地址访问元素。所以,它们之间应该有密切的关系。请解释它们之间的确切关系。谢谢。
最佳答案
让我们先把重要的东西弄清楚:数组不是指针。数组类型和指针类型是完全不同的东西,编译器的处理方式也不同。
产生混淆的地方在于 C 如何处理数组表达式。 N1570 :
6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of thesizeof
operator, the_Alignof
operator, or theunary&
operator, or is a string literal used to initialize an array, an expression that hastype ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that pointsto the initial element of the array object and is not an lvalue. If the array object hasregister storage class, the behavior is undefined.
让我们看看下面的声明:
int arr[10] = {0,1,2,3,4,5,6,7,8,9};
int *parr = arr;
arr
是 int
的 10 元素数组;它指的是一 block 足够大的连续内存块,可以存储 10 个 int
值。第二个声明中的表达式 arr
是数组类型,但由于它不是&
或sizeof
的操作数> 并且不是字符串字面量,表达式的类型变成“指向int
的指针”,值为第一个元素的地址,或者&arr[0]
。
parr
是一个指向 int 的指针;它指的是一 block 大到足以容纳单个 int
对象的地址的内存块。如上所述,它被初始化为指向 arr
中的第一个元素。
这是一个假设的内存映射,显示了两者之间的关系(假设 16 位整数和 32 位地址):
Object Address 0x00 0x01 0x02 0x03------ ------- ---------------------- arr 0x10008000 0x00 0x00 0x00 0x01 0x10008004 0x00 0x02 0x00 0x03 0x10008008 0x00 0x04 0x00 0x05 0x1000800c 0x00 0x06 0x00 0x07 0x10008010 0x00 0x08 0x00 0x09 parr 0x10008014 0x10 0x00 0x80 0x00
The types matter for things like sizeof
and &
; sizeof arr == 10 * sizeof (int)
, which in this case is 20, whereas sizeof parr == sizeof (int *)
, which in this case is 4. Similarly, the type of the expression &arr
is int (*)[10]
, or a pointer to a 10-element array of int
, whereas the type of &parr
is int **
, or pointer to pointer to int
.
Note that the expressions arr
and &arr
will yield the same value (the address of the first element in arr
), but the types of the expressions are different (int *
and int (*)[10]
, respectively). This makes a difference when using pointer arithmetic. For example, given:
int arr[10] = {0,1,2,3,4,5,6,7,8,9};
int *p = arr;
int (*ap)[10] = &arr;
printf("before: arr = %p, p = %p, ap = %p\n", (void *) arr, (void *) p, (void *) ap);
p++;
ap++;
printf("after: arr = %p, p = %p, ap = %p\n", (void *) arr, (void *) p, (void *) ap);
“之前”行应该为所有三个表达式打印相同的值(在我们的假设映射中,0x10008000
)。 “after”行应该显示三个不同的值:0x10008000
、0x10008002
(base plus sizeof (int)
)和0x10008014
(基数加 sizeof (int [10])
)。
现在让我们回到上面的第二段:数组表达式在大多数情况下都被转换为指针类型。让我们看一下下标表达式arr[i]
。由于表达式 arr
不是作为 sizeof
或 &
的操作数出现,并且因为它不是用于初始化另一个的字符串文字数组,它的类型从“int
的10元素数组”转换为“指向int
的指针”,并且正在对这个指针<进行下标操作/em> 值。事实上,当您查看 C 语言定义时,您会看到以下语言:
6.5.2.1 Array subscripting
...
2 A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th element of E1 (counting from zero).
实际上,这意味着您可以将下标运算符应用于指针对象就好像它是一个数组。这就是为什么代码喜欢
int foo(int *p, size_t size)
{
int sum = 0;
int i;
for (i = 0; i < size; i++)
{
sum += p[i];
}
return sum;
}
int main(void)
{
int arr[10] = {0,1,2,3,4,5,6,7,8,9};
int result = foo(arr, sizeof arr / sizeof arr[0]);
...
}
按照它的方式工作。 main
处理的是 int
数组,而 foo
处理的是指向 int
的指针,但两者都是能够使用下标运算符就好像他们都在处理一个数组类型。
这也意味着数组下标是可交换的:假设a
是一个数组表达式,i
是一个整数表达式,a[ i]
和 i[a]
都是有效的表达式,并且都会产生相同的值。
关于c++ - 数组是指针吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3959705/
我刚接触 C 语言几周,所以对它还很陌生。 我见过这样的事情 * (variable-name) = -* (variable-name) 在讲义中,但它到底会做什么?它会否定所指向的值吗? 最佳答案
我有一个指向内存地址的void 指针。然后,我做 int 指针 = void 指针 float 指针 = void 指针 然后,取消引用它们以获取值。 { int x = 25; vo
我正在与计算机控制的泵进行一些串行端口通信,我用来通信的 createfile 函数需要将 com 端口名称解析为 wchar_t 指针。 我也在使用 QT 创建一个表单并获取 com 端口名称作为
#include "stdio.h" #include "malloc.h" int main() { char*x=(char*)malloc(1024); *(x+2)=3; --
#include #include main() { int an_int; void *void_pointer = &an_int; double *double_ptr = void
对于每个时间步长,我都有一个二维矩阵 a[ix][iz],ix 从 0 到 nx-1 和 iz 从 0 到 nz-1。 为了组装所有时间步长的矩阵,我定义了一个长度为 nx*nz*nt 的 3D 指针
我有一个函数,它接受一个指向 char ** 的指针并用字符串填充它(我猜是一个字符串数组)。 *list_of_strings* 在函数内部分配内存。 char * *list_of_strings
我试图了解当涉及到字符和字符串时,内存分配是如何工作的。 我知道声明的数组的名称就像指向数组第一个元素的指针,但该数组将驻留在内存的堆栈中。 另一方面,当我们想要使用内存堆时,我们使用 malloc,
我有一个 C 语言的 .DLL 文件。该 DLL 中所有函数所需的主要结构具有以下形式。 typedef struct { char *snsAccessID; char *
我得到了以下数组: let arr = [ { children: [ { children: [], current: tru
#include int main(void) { int i; int *ptr = (int *) malloc(5 * sizeof(int)); for (i=0;
我正在编写一个程序,它接受一个三位数整数并将其分成两个整数。 224 将变为 220 和 4。 114 将变为 110 和 4。 基本上,您可以使用模数来完成。我写了我认为应该工作的东西,编译器一直说
好吧,我对 C++ 很陌生,我确定这个问题已经在某个地方得到了回答,而且也很简单,但我似乎找不到答案.... 我有一个自定义数组类,我将其用作练习来尝试了解其工作原理,其定义如下: 标题: class
1) this 指针与其他指针有何不同?据我了解,指针指向堆中的内存。如果有指向它们的指针,这是否意味着对象总是在堆中构造? 2)我们可以在 move 构造函数或 move 赋值中窃取this指针吗?
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: C : pointer to struct in the struct definition 在我的初学者类
我有两个指向指针的结构指针 typedef struct Square { ... ... }Square; Square **s1; //Representing 2D array of say,
变量在内存中是如何定位的?我有这个代码 int w=1; int x=1; int y=1; int z=1; int main(int argc, char** argv) { printf
#include #include main() { char *q[]={"black","white","red"}; printf("%s",*q+3); getch()
我在“C”类中有以下函数 class C { template void Func1(int x); template void Func2(int x); }; template void
我在64位linux下使用c++,编译器(g++)也是64位的。当我打印某个变量的地址时,例如一个整数,它应该打印一个 64 位整数,但实际上它打印了一个 48 位整数。 int i; cout <<
我是一名优秀的程序员,十分优秀!