关于指针的疑惑, int **p[10], p 是数组还是指针?

2017-11-09 00:25:47 +08:00
 Lxxyx
RT.
遇到一个题目,问的是这个。

我这儿的推断是,p 是一个指向指针数组的指针,所以是指针。

因为 int *p[10]是指针数组,而第二个*号指向这个数组,所以是指针。

但是答案告诉我是数组,所以迷惑不解,希望 V 友们可以给一个答案,谢谢啦~
5160 次点击
所在节点    C
68 条回复
binux
2017-11-09 00:30:53 +08:00
那 int** p[10] 是数组还是指针?
AttufliX
2017-11-09 00:31:36 +08:00
指针,指向一个指向 10 个元素的数组的指针
congeec
2017-11-09 00:33:43 +08:00
https://cdecl.org/?q=int+**p%5B10%5D
从右往左读,不过是 p 那块内存里存了 10 个 int **
n2ex2
2017-11-09 00:35:15 +08:00
**的数组...
AttufliX
2017-11-09 00:35:38 +08:00
上面说错了,cdel 查了下是数组,指向 10 个二维指针的数组
geelaw
2017-11-09 00:36:41 +08:00
等同于 typedef int **ptr; ptr p[10];
n2ex2
2017-11-09 00:39:46 +08:00
不过数组名本身就是指针,要说它是指针也说得通...
lianz
2017-11-09 00:42:40 +08:00
数组就是指针,指针就是数组,两者本质上都是一个内存地址,可以直接换用,没任何区别。
比如 :

1:int girls[10] = {....}; 可以直接用指针访问访问:int i = *girls;
2:int *p = (int*) malloc (sizeof(int) * 10); 可以直接用数组方式访问 int i = p[0];
LeonLi
2017-11-09 00:45:00 +08:00
其实 p 的类型是 int **[]
XiaoxiaoPu
2017-11-09 00:46:19 +08:00
@lianz 数组当然不是指针,指针也不是数组,sizeof(int [10]) 跟 sizeof(int *) 能一样?

@Lxxyx 《 C 专家编程》可以彻底解决你的疑问
wsy2220
2017-11-09 00:47:28 +08:00
数组, 数组的元素是指针
LeonLi
2017-11-09 00:53:29 +08:00
@lianz 你这个看起来类似是因为数组在访问的时候,其实是走的指针的语法糖的形式,但是说不上没有任何区别,最大的区别其实是数组是有自己的类型的,并不能跟指针等价。比如:
1 数组名是不允许重复赋值的,指针可以
int arr[1];
int *p ;
arr = xxx ;//error
p = xxx://OK

2 数组是和指针还有一个很明显的区别,数组可以使用 sizeof 算出整个数组大小,而指针的 sizeof 只是计算的指针分配空间的大小,以 32 位为例:
int arr[10];
int *p = (int*)malloc(sizeof(int)*10);
size_t as = sizeof(arr);// 40
size_t ps = sizeof(p);// 4
hackpro
2017-11-09 00:59:39 +08:00
P 是一个是个元素的数组
数组中每个元素是个指针
指向另外一个 int *
wwqgtxx
2017-11-09 01:23:43 +08:00
@LeonLi
@XiaoxiaoPu
对于你们说的 sizeof 的问题插个话,这个地方完全是编译器实现的问题,在你用 int arr[10]这样定义的时候,sizeof(arr)编译器是完全能推断出来 arr 的 size 的,而如果你用动态分配的话,编译器只能知道这个指针本身多大,根本没办法知道这段内存地址的结尾在哪里,因为那个只有 malloc 的实现( glibc/msvcrt/...)才知道
sizeof 运算符本质上就是一个预处理,在最后程序编译完了之后就消失了,被直接替换成具体的值了,所以 sizeof 所能得到的大小一定是可以静态推断的,这也就是对 std 容器进行求 sizeof 基本上毫无意义的原因
FrankHB
2017-11-09 01:45:24 +08:00
连完整的声明都不是,就半坨声明符,还想啥。
p 就是个不知所云的标识符。没上下文姑且当作没声明了,没有对应的实体,无所谓指针数组。

@wwqgtxx 如果只有某几句关键的废话,那么少妖言惑众,老实重修,算是你勉强表现出你楼上都没注意到的上下文相关特(废)色(物)特性的奖赏。但是非要满嘴跑火车……那么接好问题一箩筐:

“完全是编译器实现的问题”?意思说换个编译器可以胡来了?
推断……的 size ? Deduce 还是 infer ?
内存?地址?结尾?哪个轮得到编译器管?哪个决定不能让编译器管?( C 艹 14 都钦定允许合并::operand new 了咋就没几个长眼的呢。)
解释什么叫预处理。是不是对 phase of translation 毫无概念?
“编译完了”?谁钦点要求编译的?
直接“替换”?βη等价?
“大小一定是可以静态推断的”?题主好像没说不能 VLA 吧?
解释什么叫“基本上毫无意义”。不说语病……是不是不懂啥叫 incomplete type ?
LeonLi
2017-11-09 01:56:41 +08:00
@wwqgtxx
首先说一下你说的编译器实现的问题。在 C 语言标准中,对于那些行为可以由编译器自行决定( implementation-defined behavior )和未定义行为( undefined behavior )是有严格区分的。
以 C99 版标准为例,Rule6.5.3.4 规定了 sizeof 的行为( When applied to an operand that has array type, the result is the total number of bytes in the array.),这个是编译器不能自己改变其行为的。其中,编译器可以自行决定的只有 sizeof 的返回值类型 size_t。

另外,回应一下你说的因为数组定义可以在编译器推断出来的问题。在 C99 标准之后,C 语言支持可变长数组 VLA ( variable-length array )。而 VLA 的 size 是在运行期才能确定的,此时,sizof 的结果由运行时(execution time)确定,返回的依然是整个数组的大小。所以你说的那段话是不成立的。
LeonLi
2017-11-09 01:57:41 +08:00
@FrankHB 戳帝球~
FrankHB
2017-11-09 02:26:17 +08:00
@LeonLi 要科普完的话,引用 Clause 3 和 Clause 4。

你的说法有个会引起误会的地方,实际情况是 size_t 就是法定的 sizeof 表达式求值结果的无符号整数类型(某种意义上这就是 size_t 的首要意义),C 编译器改变不了这个决定;允许实现变更的是 size_t 和其它整数类型的关系。

嘛,VLA 在 C11 算是 optional 了,不过还有-std=gnu11 之类的垫着就是了……
q397064399
2017-11-09 07:27:07 +08:00
@congeec #3 好顶赞,,c 语言的古怪 声明 确实太烧脑了
q397064399
2017-11-09 07:29:44 +08:00
@congeec #3 ** 意味着是 指针的指针, 当前指针指向了一个内存地址,,然后另一个指针里面的内容 就是当前指针的内存地址,我理解的对吗? 这样有什么 意义么?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/404784

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX