首页 > 试题广场 >

对于定义"int *p",下列哪些说明可能是正确的?()

[单选题]
对于定义"int *p",下列哪些说明可能是正确的?()
  • p是一个指向int型值的指针
  • p是一个指向一维数组的指针
  • p是一个指向二维数组的指针
  • p是一个动态数组
关于选项C,使用的是VS2010。
发表于 2015-09-01 16:45:29 回复(0)
A正确
B
int arr[10];
int *p = arr;
C,如果单纯冲指向来讲正确,如果考虑指针类型的话不正确。
int arr[100][100];
int *p;
p = arr;                //指针类型不相同,不可以。
p = (int *)arr;        //可以,我管你什么JB数组不数组的,什么函数不函数的,什么乱七八糟的。我就知道你是一个内存地址。

D:大概是说int * p =new int [1024]这个意思吧。
发表于 2015-10-08 16:36:32 回复(0)
感觉答案B有问题啊,二维数组指针才是指向一维数组的啊。
发表于 2015-09-01 10:34:59 回复(1)
int arr[10]; int *p1 = arr; int *p2 = (int*)&arr; int (*p3)[10] = &arr;
printf("%p %p %p", p1, p2, p3);

输出:
0x7fffaeaff340 0x7fffaeaff340 0x7fffaeaff340

我们知道 数组名可以理解为指向一维数组首元素的指针常量
然而由于数组是一种类型,所以并不能单纯的作为指针常量去判断所有问题
那么&arr是什么?如果arr是指针常量,那么&arr应当是arr的地址
但是 事实上arr与&arr是相等的
这是与指针没有直接关系的,而是数组本身内部的属性
亦即arr存储首元素地址,&arr存储数组地址,并且两个地址相同
基于以上前提,结合我的实验数据,咱们回归本题B选项

int *p1 = arr;
易水 认为是指向一维数组的指针
cocxx 认为是指向一维数组首元素的指针
造成这种分歧的原因正是因为两个指针存储的地址值是一样的缘故
而指针是由地址值+数据类型来决定的
所以不能单纯以地址值来谈论,还要基于其指向的数据类型
因为毕竟数据类型决定了指针移动的步长
所以我们写int *p=&arr;这样的语句是编译不通过的
编译器告诉我们:
error: cannot convert 'int (*)[10]' to 'int*' in initialization
那么由此可知,编译器认为int *指向数组元素,而'int (*)[10]'指向数组
这正是类型对指针的决定性影响
所以综上愚以为此处的int *p只能指向一维数组首元素
但是鉴于arr 与 &arr地址值的相等性
所以试验中我使用了强制类型转换 int *p2 = (int*)&arr;
这样编译就通过了
但无法改变int *只能指向单个元素的事实

类似的情况还有函数名
    void foo() {}
    printf("%p %p\n", foo, &foo);
这里打印出

0x100000f40 0x100000f40

与数组名的区别在于
此处foo和&foo是相同的函数指针void(*)()类型
而arr与&arr的指针类型不同
前者指向元素 后者指向数组

综合上述,A选项对;B选项错

至于有的朋友问动态一维数组算不算一维数组
int *p = new int[10];
这个可以查看C11文档关于new表达式的说明
The new expression allocates a memory area, initializes either single object, or an array of objects there and returns a pointer to the first constructed object.
由此可知new关键字创建动态数组时,返回首元素的指针

援引<C++ Primer(Fifth Edition)> 12.2.1的内容:

Although it is common to refer to memory allocated by new T[] as a “dynamic array,” this usage is somewhat misleading. When we use new to allocate an array, we do not get an object with an array type. Instead, we get a pointer to the element type of the array. Even if we use a type alias to define an array type, new does not allocate an object of array type. In this case, the fact that we’re allocating an array is not even visible; there is no [num]. Even so, new returns a pointer to the element type.

大意如下:
虽然我们常把new分配的T[]对象称为“动态数组”,但是这种说法有点误导人。因为当使用new来分配一个数组,我们并未得到一个数组类型的对象。相反地,我们得到的是一个指向数组元素的指针。即使我们使用一个类型别名来定义某种数组类型,new也不会分配一个数组类型的对象。在这种情况下,你看不出我们是在分配一个数组,因为数组长度[num]压根没有体现出来。所以,new返回的是一个指向数组元素的指针。


D选项事实上是值得商榷的,因为它与上文所引用的C++文档和C++ Primer的论述不符。如果A选项精确表达了数组名的语义(semantics),那么new的语义应该和A选项具有一致性。也就是说,没有什么指针能指向所谓的“动态数组”(dynamic array)。我们new T[num]时,只是分配了sizeof(T)*num大小的堆区内存而已,并没有什么数组类型被创建。返回的只是一个T类型的指针,让你可以方便通过这个指针获得这块堆内存的首地址。以后你想要访问这块地址上的元素,就可以通过这个指针迭代器,以相同的sizeof(T)步长迭代访问这块内存上的元素。
所以,new的返回值和数组名arr一样,视为int *类型

综合上述,D选项错

我的最终结论是 int *p只能
是一个指向int型值的指针

-----

2017.9.28 回访
官方已改正答案

-------------------
附加福利:
我们用汇编来看看new方法的内部实现
考虑如下示例代码:
    int *p = new int[3]();
    *p = 1;
    *(p+1) = 2;
    *(p+2) = 3;
编译为如下汇编码:
(芯片架构为X86_64,汇编语法格式为AT&T)
# eax寄存器存入12,即我们的动态数组所需空间总大小
movl    $12, %eax
# edi寄存器存入12,作为下面调用的__Znam函数的第一个参数(也是唯一一个)
movl    %eax, %edi
# 系统调用libkern中的__Znam函数,用于申请12字节的堆内存,返回内存首地址到rax寄存器
callq    __Znam
# ecx寄存器清零
xorl    %ecx, %ecx
# edx寄存器存入12,即我们的动态数组所需空间总大小,作为_memset函数的第三个参数
movl    $12, %edx
# 将__Znam函数返回的堆内存首地址存入rdi寄存器,作为_memset函数的第一个参数
movq    %rax, %rdi
# 将ecx寄存器中的值,即0,存入esi寄存器,作为_memset函数的第二个参数
movl    %ecx, %esi
# 由于下面调用memset函数后会使用rax存储返回值,所以需要在栈里保存一下rax中的动态数组首地址
movq    %rax, -16(%rbp)         ## 8-byte Spill
# 保存一下ecx中的动态数组元素默认值
movl    %ecx, -20(%rbp)         ## 4-byte Spill
# 调用memset函数初始化动态数组元素,每个字节清零
callq    _memset
# 动态数组首地址出栈,最终存入rdx寄存器
movq    -16(%rbp), %rax         ## 8-byte Reload
movq    %rax, -8(%rbp)
movq    -8(%rbp), %rdx
# 实现代码中的逻辑,在动态数组第一个元素中存入立即数1
movl    $1, (%rdx)
movq    -8(%rbp), %rdx
# 在动态数组第二个元素中存入立即数2
movl    $2, 4(%rdx)
movq    -8(%rbp), %rdx
# 在动态数组第三个元素中存入立即数3
movl    $3, 8(%rdx)
# 最终返回值寄存器rax中存储的是动态数组内存首地址
其中用到的memset函数原型为
void *memset(void *__b, int __c, size_t __len);
由汇编代码可以清晰地看到new函数的实现过程事实上就是两步:

1. 调用__Znam函数分配内存空间

2. 调用_memset函数初始化内存

第二步是可选的,因为示例代码中定义动态数组的语句为
int *p = new int[3]();
所以会有第二步
假如按照如下方式声明则不会有第二步
int *p = new int[3];
一个括号引发的血案,区别在于

前者会使用值初始化
后者使用默认初始化


回到正题

最终函数返回值为__Znam函数返回的动态内存空间首地址

也就是说就是个void *

大家最终对其进行任何强制转换都可以

当然在代码中我们定义为什么类型,返回的就是什么类型

只是大家知道 到了底层其实没所谓类型的

只有数据宽度

而指针这种东西 在X86_64架构就是8字节

无所谓类型

编辑于 2017-10-25 10:45:09 回复(9)
A.这个很明显是对的。
B.有如下程序,此时P为指向一维数组的指针
int arr[10];
int *p=arr;
C.指向二维数组
int arr[10][10];
int (*p)[10];
p=arr;
D.在函数中声明动态数组,因为在编译阶段并不知道len大小,所以只能如下面一样声明动态数组
int func(int len){
    int *p=new int[len];
}

编辑于 2016-06-07 23:12:41 回复(16)
我觉得选项B 表述的有点问题,分析如下:
intarr[10];
int*p=arr;
这里p 指向的是一维数组中的第一个元素,所以指向的是int 类型的数据。
intarr[10][10];
int(*p)[10]=arr;
这里p也是指向二维数组中的第一个元素,且元素是int [10]类型的数据,
综述所述,int(*p)[10] 才表示一个指向一维数组的指针。
发表于 2015-09-04 20:08:26 回复(9)
馹头像
int *b指向一个int值,int (*b)指向一维数组开头,int (*p)[10]指向二维数组
发表于 2022-02-22 18:32:50 回复(0)
一个数组的数组名是指向其第一个元素的指针,而不是指向数组的指针。
发表于 2016-08-01 17:44:38 回复(0)
对于定义"int *p",下列哪些说明可能是正确的?()
A p是一个指向int型值的指针
B p是一个指向一维数组的指针
C p是一个指向二维数组的指针
D p是一个动态数组
A选项正确:表达的意思是p是一个整型指针,举个例子,int a = 0;int *p = &a;
B选项错误:表达的意思是p是一个一维数组指针,举个例子,int arr[2]; int (*p)[2] = &arr;
C选项错误:表达的意思是p是一个二维数组指针,举个例子,int arr[2][3]; int (*p)[2][3] = &arr;
D选项错误:表达的意思是p是一个数组,指针是指针,数组是数组
发表于 2023-04-28 16:54:24 回复(0)
测试
发表于 2022-03-14 21:30:02 回复(0)
数组指针也指针数组的区别
发表于 2021-05-06 09:15:39 回复(0)
看完了下面解析  我认为B更对了。。。
A我以为包含了int常值的情况, 指向一个常数就不对了
发表于 2021-03-03 19:40:28 回复(0)
文字游戏,无聊
发表于 2020-11-07 10:43:55 回复(0)
指向整形值的指针;
疑惑的地方在于B选项,
数组名是指针常量,也即是存储固定的地址:相当于int* const p;

发表于 2020-05-14 08:57:23 回复(0)
这难道大家看到的题目还不一样??? int *p 有什么好解释的。。。
发表于 2017-09-29 10:02:49 回复(0)
p指向的是整型变量,并不是一个数组。
int *p=new int[10;p指向一个动态数组
发表于 2017-08-03 23:00:50 回复(0)
楼上的说的都挺好。 但从 int *a[10] ; int (*a)[10]的区别就能知道了,int (*a)[10]表示指向大小为10的整型数组的指针,数组指针,他才是指向一维数组的指针,所以B int *a就不是咯。
发表于 2017-04-01 16:27:36 回复(0)
该题涉及到指针类型问题,先说明以下指针类型:
若int ar[10];
ar 为指向数组首元素的指针(注意是数组首元素,即int类型)
&ar可理解为指向数组首地址的指针,该指针类型为i nt(*p)[10] ;即指向一个长度为10个int;

发表于 2017-03-16 23:57:30 回复(0)
A.p是一个指向int型值的指针        //int *p=&a;
B.p是一个指向一维数组的指针      //int (*p)[10];
C.p是一个指向二维数组的指针      //int arr[10][10]; int (*p)[10]; p=arr;    arr为0行首地址
D.p是一个动态数组        //int *p=new int[10];
发表于 2016-11-11 20:21:10 回复(1)
以上解释未理解,哪位大神给换个说法。谢谢。
发表于 2016-09-12 21:57:32 回复(1)