- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我是 C 的新手,虽然我认为我几乎了解了有关指针和数组的全部逻辑,但我遇到了一个对我来说没有任何意义的问题。
考虑一个二维数组,比如说
double arr[][3] = { {1,2,3}, {4,5,6} };
和一个指向指针的指针
double ** ptrptr;
现在,假设打印arr
和arr[0]
分别指向的地址,即
printf( "%ld \n", (long) arr);
printf( "%ld \n", (long) *arr);
产生类似的东西
140734902565640
140734902565640
因为 arr
(数组的数组)的第一个元素和 *arr
( double 组)的第一个元素具有相同的位置。到目前为止,一切都很好。现在我的问题:
我这样做:
ptrptr = (double **) arr;
printf( "%ld \n", (long) ptrptr);
printf( "%ld \n", (long) *ptrptr);
我希望得到与以前相同的输出,但相反我得到的是
140734902565640
4607182418800017408
所以看起来 ptrptr
和 arr
都评估为指向同一位置的指针 - 正如预期的那样 - 但是 *ptrptr
和 *arr
不。为什么?
此外,如果我再次取消引用,即 **ptrptr
,我会遇到段错误。
我的逻辑是……像这样,松散地说:ptrptr == arr == &arr[0]
应该指向*ptrptr == *arr == arr[0] == &arr[0][0]
又应该指向**ptrptr == *arr[0] == arr[0][0]
。
虽然我找到了一个可以满足我的目的的解决方法,但我仍然很想知道为什么这不起作用。
最佳答案
让我们谈谈表达式和类型。
除非它是 sizeof
或一元 &
运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字,类型的表达式“T
的 N 元素数组”被转换(“衰减”)为“指向 T
的指针”类型的表达式,表达式的值是数组的第一个元素。
表达式 arr
的类型为“double
的 3 元素数组的 2 元素数组”。在行中
printf( "%ld \n", (long) arr);
arr
不是 &
或 sizeof
运算符的操作数,因此它被转换为“指向 3- 的指针”类型的表达式double
”的元素数组,其值为第一个元素的地址,即&arr[0]
。
行内
printf( "%ld \n", (long) *arr);
由于表达式 arr
的类型为“指向 double
的 3 元素数组的指针”,表达式 *arr
(相当于表达式 arr[0]
) 的类型为“double
的三元素数组”。由于此表达式不是 sizeof
或一元 &
运算符的操作数,因此它被转换为“指向 double
的指针”类型的表达式,其值为第一个元素的地址,即&arr[0][0]
。
在 C 中,数组的地址与数组的第一个元素的地址相同(没有为指向第一个元素的指针预留单独的存储;它是从数组表达式本身计算的)。该数组在内存中的布局为
+---+
arr: | 1 | 0x0x7fffe59a6ae0
+---+
| 2 | 0x0x7fffe59a6ae8
+---+
| 3 | 0x0x7fffe59a6aec
+---+
| 4 | 0x0x7fffe59a6af0
+---+
| 5 | 0x0x7fffe59a6af8
+---+
| 6 | 0x0x7fffe59a6afc
+---+
所以下面的表达式都会产生相同的值,但是类型会不同:
Expression Type Decays to
---------- ---- ---------
arr double [2][3] double (*)[3]
&arr double (*)[2][3] n/a
*arr double [3] double *
arr[i] double [3] double *
&arr[i] double (*)[3] n/a
*arr[i]
和 arr[i][j]
都产生一个 double
值。
现在让我们看看ptrptr
:
double **ptrptr = (double **) arr;
printf( "%ld \n", (long) ptrptr);
printf( "%ld \n", (long) *ptrptr);
我们注意到的第一件事是 ptrptr
不是数组表达式,因此上面的转换规则不适用。我们将它指定为指向 arr
的第一个元素,但之后它的行为与任何其他指针一样,因此表达式 ptrptr
和 *ptrptr
将具有不同的值。由于 ptrptr
指向数组的第一个元素 (&arr[0][0]
),*ptrptr
产生 value 存储在第一个元素,即 1.00
。碰巧的是,当您将 1.00
的位模式解释为该特定平台上的长整数时,它会显示为 4607182418800017408。
下面是一些代码,可以使上面的内容更加清晰:
#include <stdio.h>
int main( void )
{
double arr[][3] = {{1,2,3},{4,5,6}};
double **ptrptr = (double **) arr;
printf( " arr: %p\n", (void *) arr );
printf( " &arr: %p\n", (void *) &arr );
printf( " *arr: %p\n", (void *) *arr );
printf( " arr[0]: %p\n", (void *) arr[0] );
printf( "&arr[0]: %p\n", (void *) &arr[0] );
printf( " ptrptr: %p\n", (void *) ptrptr );
printf( "*ptrptr: %p (%f %ld)\n", (void *) *ptrptr,
*(double *) ptrptr, *(long int *) ptrptr );
return 0;
}
这是输出:
arr: 0x7fffe59a6ae0
&arr: 0x7fffe59a6ae0
*arr: 0x7fffe59a6ae0
arr[0]: 0x7fffe59a6ae0
&arr[0]: 0x7fffe59a6ae0
ptrptr: 0x7fffe59a6ae0
*ptrptr: 0x3ff0000000000000 (1.000000 4607182418800017408)
同样,*ptrptr
为我们提供了数组第一个元素的值,即 1.0
,但我们将该位模式解释为指针值 ( 0x3ff0000000000000
) 和一个长整数 (4607182418800017408
)。
关于c - 指向分配给二维数组的指针的指针,指向错误的地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21565036/
我刚接触 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 <<
我是一名优秀的程序员,十分优秀!