鱼C论坛

 找回密码
 立即注册
查看: 1779|回复: 17

[已解决]请前辈指点,数组指针实质是不是指向指针的指针

[复制链接]
发表于 2018-6-19 20:41:12 | 显示全部楼层 |阅读模式
20鱼币
本帖最后由 wow7jiao 于 2018-6-19 21:15 编辑

#include <stdio.h>

int main()
{
        int temp[5] = {1, 2, 3, 4, 5};
        int (*p2)[5 = &temp;l]
        int i;

        for (i = 0; i < 5; i++)
        {
                printf("%d\n", *(*p2 + i));//请问这里2个星号,那就是作了2次解引用,第一次*p2取了数组首地址指针 (那就不是取得地址了),然后加i,最后*(*p2+i)取1,2 ,3 。。的地址
        }

        return 0;
}
最佳答案
2018-6-19 20:41:13
数组指针就是 数组指针;  说得简单点就是指向数组的指针

详细,看下面
数组指针和指针是两个不同的类型:
假设:int array[2][3]={{1,2,3},{4,5,6}};
1,二维数组名是数组指针 (array: 是指向int (*)[3]类型的指针)
2,二维数组名取址是二维数组指针 (&array: 是指向 int (*)[2][3]类型的指针)
3,二维数第0行的首地址是数组指针(&array[0]:是指向int (*)[3]类型的指针)
4,二维数组首元素的地址是指针类型(array[0]:是指向int *类型的指针)

参考:http://blog.csdn.net/pipinuan/article/details/53193289

最佳答案

查看完整内容

数组指针就是 数组指针; 说得简单点就是指向数组的指针 详细,看下面 数组指针和指针是两个不同的类型: 假设:int array[2][3]={{1,2,3},{4,5,6}}; 1,二维数组名是数组指针 (array: 是指向int (*)[3]类型的指针) 2,二维数组名取址是二维数组指针 (&array: 是指向 int (*)[2][3]类型的指针) 3,二维数第0行的首地址是数组指针(&array[0]:是指向int (*)[3]类型的指针) 4,二维数组首元素的地址是指针类型(array[ ...
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-6-19 20:41:13 | 显示全部楼层    本楼为最佳答案   
数组指针就是 数组指针;  说得简单点就是指向数组的指针

详细,看下面
数组指针和指针是两个不同的类型:
假设:int array[2][3]={{1,2,3},{4,5,6}};
1,二维数组名是数组指针 (array: 是指向int (*)[3]类型的指针)
2,二维数组名取址是二维数组指针 (&array: 是指向 int (*)[2][3]类型的指针)
3,二维数第0行的首地址是数组指针(&array[0]:是指向int (*)[3]类型的指针)
4,二维数组首元素的地址是指针类型(array[0]:是指向int *类型的指针)

参考:http://blog.csdn.net/pipinuan/article/details/53193289
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-6-19 20:54:50 | 显示全部楼层
本帖最后由 wow7jiao 于 2018-6-19 20:57 编辑
ba21 发表于 2018-6-19 20:52
数组指针就是 数组指针;  说得简单点就是指向数组的指针

详细,看下面


我已经把c语言的看21课,22课,23课,24课看了很多遍,现在*, **的解引用迷糊了

ps:今天好像插入不了图片
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-6-19 21:03:24 | 显示全部楼层
本帖最后由 wow7jiao 于 2018-6-19 21:05 编辑

c语言23课指针和数组 这里有2个星号相当2此解引用
QQ截图20180619203831.png
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-6-19 21:09:20 | 显示全部楼层
c语言22课指针和数组,这里解引用只有一个‘*’我的理解,这里是解引用p取得p指向的地址。
QQ截图20180619210800.png
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-6-19 21:12:19 | 显示全部楼层
c语言第21课,这里也只有一个‘*’,我理解也是解引用*pa是取得pa指向的地址。
QQ截图20180619211020.png
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-6-19 23:03:10 | 显示全部楼层
本帖最后由 xjy99 于 2018-6-19 23:25 编辑

语法糖:  在C语言里用a表示*(a+i),用a[j]表示*(*(a+i)+j),这种写法简洁明了,容易被人理解。

指针变量是存放地址的变量

数组指针是 指针, 是用来存放地址的, 这个地址是数组的 地址
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-6-19 23:19:07 | 显示全部楼层
xjy99 发表于 2018-6-19 23:03
语法糖:  在C语言里用a表示*(a+i),用a[j]表示*(*(a+i)+j),这种写法简洁明了,容易被人理解。

我不太确定数组指针是不是指向指针的指针,有2次解引用 都发生 数组指针里。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-6-20 00:34:47 From FishC Mobile | 显示全部楼层
本帖最后由 xjy99 于 2018-6-20 06:37 编辑
wow7jiao 发表于 2018-6-19 23:19
我不太确定数组指针是不是指向指针的指针,有2次解引用 都发生 数组指针里。


注意我用了 int (*p)[4]  ,用了这个"4"会怎么样

类比二维数组
如果我现在int array[3][4]
array   array[0]    array[0][0]   以及
array[1]    arary[1][0] 并不完全相同


然后我可以int (*p)[4] = array
p+i是跳了i行
*p+i是跳了i列


然后结合我给的代码
我定义了一个一维数组然后编译器警告了。。。。我没理这个警告,结果输出了第五个元素的值
Screenshot_20180620-003201.png
Screenshot_20180620-003309.png
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-6-20 06:52:33 From FishC Mobile | 显示全部楼层
再用char举个例子
char s[10];与char *p;
char s2[10][8];与char **p2;

s与p的关系,s2与p2的关系,两者相同吗?


s等价于&s[0], 类型为pointer to char, 与p相同
s2等价于&s2[0], 类型为pointer to array of 8 chars, 与p2不同
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-6-20 10:06:49 | 显示全部楼层
本帖最后由 wow7jiao 于 2018-6-20 10:08 编辑

我其实就想问一下数组指针是不是这个结构,指向指针的指针才能对应双‘*’解引用。
无标题.png
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-6-20 11:55:49 | 显示全部楼层
本帖最后由 wow7jiao 于 2018-6-20 11:56 编辑

数组名和数组名取地址的区别
https://blog.csdn.net/daniel_ice/article/details/6857019
以下代码会打印出什么样的日志呢?



[cpp] view plain copy
1.#include <stdio.h>  
2.  
3.int a[2] = {1,2};  
4.int main(){  
5.        printf("a = %p\n", a); // I  
6.        printf("&a = %p\n", &a); // II  
7.        printf("a + 1 = %p\n", a + 1);// III  
8.        printf("&a + 1 = %p\n", &a + 1);// IV  
9.  
10.        return 0;  
11.}  

本机(linux)结果输出:
a = 0x804a014
&a = 0x804a014
a + 1 = 0x804a018
&a + 1 = 0x804a01c

没错,上面I 和 II打印出来的地址是一样的,IV 要比 III 大4个字节的地址空间。下面是我对这一现象的解释,如有不妥的地方请各位大虾一定给于指出:

首先引用《C和指针》p141中的理论:
在C中, 在几乎所有使用数组的表达式中,数组名的值是个指针常量,也就是数组第一个元素的地址。 它的类型取决于数组元素的类型: 如果它们是int类型,那么数组名的类型就是“指向int的常量指针“。
看到这里我想应该就知道为什么 会有I 和 III式的结果了。

对于II 和 IV 则是特殊情况,在《C和指针》p142中说到,在以下两中场合下,数组名并不是用指针常量来表示,就是当数组名作为sizeof操作符和单目操作符&的操作数时。 sizeof返回整个数组的长度,而不是指向数组的指针的长度。 取一个数组名的地址所产生的是一个指向数组的指针,而不是一个指向某个指针常量的指针。
所以&a后返回的指针便是指向数组的指针,跟a(一个指向a[0]的指针)在指针的类型上是有区别的。

然后我们用符号表和汇编代码来看看编译器到底是怎样区分&a 和 a, 并将其转换为汇编代码的:

通过 nm a.out 得到符号表如下:



[plain] view plain copy
1.。。。。。。。// 省略了一些与本主题无关的变量  
2.0804a01c A _edata  
3.0804a024 A _end  
4.080484ec T _fini  
5.08048508 R _fp_hw  
6.080482bc T _init  
7.08048330 T _start  
8.0804a014 D a // a 变量保存在虚拟地址0x0804a014 中  
9.0804a01c b completed.7021  
10.0804a00c W data_start  
11.0804a020 b dtor_idx.7023  
12.080483c0 t frame_dummy  
13.080483e4 T main // main函数的地址  
14.         U printf@@GLIBC_2.0  


调用gcc -S xx.c得到汇编代码:  



[cpp] view plain copy
1.    .file   "name_of_array.c"  
2..globl a  
3.    .data  
4.    .align 4  
5.    .type   a, @object  
6.    .size   a, 8 // 从这里我们便知道sizeof(a) 等于8  
7.a:  
8.    .long   1 // 从这里可以看出,编译器直接把 .c文件中的int 转化为long型  
9.    .long   2  
10.    .section    .rodata  
11..LC0:  
12.    .string "a = %p\n"  
13..LC1:  
14.    .string "&a = %p\n"  
15..LC2:  
16.    .string "a + 1 = %p\n"  
17..LC3:  
18.    .string "&a + 1 = %p\n"  
19.    .text  
20..globl main  
21.    .type   main, @function  
22.main:  
23.    pushl   %ebp  
24.    movl    %esp, %ebp  
25.    andl    $-16, %esp  
26.    subl    $16, %esp  
27.    movl    $.LC0, %eax // I 所对应的汇编代码  
28.    movl    $a, 4(%esp)  
29.    movl    %eax, (%esp)  
30.    call    printf  
31.    movl    $.LC1, %eax // II 所对应的汇编代码  
32.    movl    $a, 4(%esp)  
33.    movl    %eax, (%esp)  
34.    call    printf  
35.    movl    $.LC2, %eax // III 所对应的汇编代码  
36.    movl    $a+4, 4(%esp)  
37.    movl    %eax, (%esp)  
38.    call    printf  
39.    movl    $a+8, %edx // IV 所对应的汇编代码  
40.    movl    $.LC3, %eax  
41.    movl    %edx, 4(%esp)  
42.    movl    %eax, (%esp)  
43.    call    printf  
44.    movl    $0, %eax  
45.    leave  
46.    ret  
47.    .size   main, .-main  
48.    .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"  
49.    .section    .note.GNU-stack,"",@progbits  

I所对应的汇编代码 movl $a, 4(%esp)
$表示取地址,通过符号表我们知道a对应地址为0x0804a014, 所以这段代码将会打印0x0804a014。但是我们明明在代码里写的是printf("a = %p\n", a), (如果a不为数组名而是一般意义的int变量,相应的汇编码应为movl a, 4(%esp) 怎么编译后的汇编代码会是对a取地址呢? 本人猜测为编译器自动给a 加了一个取值符,从而翻译为$a。
结论: 对于用户没有明确给出&的编码,编译器翻译自动给变量a加上取值符$, 其中取a的地址得到的指针类型由数组元素决定。
II 略过
III movl $a+4, 4(%esp)
对a加上取值符得到$a,因为数组元素类型为int,所以指针每次需要移动四个字节的地址空间。 所以c代码 a + 1 翻译为汇编 $a + 4

IV  movl $a+8, %edx
所对应用户代码为printf("a = %p\n", &a + 1), 根据《C和指针》中的理论,当a前面有&操作符时,编译器将会把a对应符号表中的地址看作指向数组的指针,sizeof(a) 为8,
从而&a + 1 将会翻译为$a + 8
结论: 对于用户明确给出&的编码,编译器将会把取a的地址得到的指针类型看作指向数组的指针。

总结:编译器通过用户是否给出&,来决定指针变量的类型,进而翻译为相应的汇编码。 或者换句话说,&符只是用来表明变量a取地址后得到的值,被看作什么类型的指针,而不是用来表示对a进行取地址操作。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-6-25 10:20:49 From FishC Mobile | 显示全部楼层
你这代码能运行?真正写代码不会这样用指针,这是自己找虐用的,C语言是门很灵活的计算机语言,天高任你飞。照我这样写:int *p = temp; *(p+0) == temp[0];  *(p+n) == temp[n];指针和内存分配领悟了,C就学的差不多了,等到3级指针你更晕,慢慢悟吧,师傅领进门,修行靠个人。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-6-25 10:52:21 | 显示全部楼层
ba21 发表于 2018-6-19 20:41
数组指针就是 数组指针;  说得简单点就是指向数组的指针

详细,看下面

这个部分很重要,普通指针一维数组和二位数组取址不一样
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-6-25 11:56:05 | 显示全部楼层
二维数组是个嵌套数组,指针数组是内嵌套,数组指针是外嵌套。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-6-25 12:03:39 | 显示全部楼层
wow7jiao 发表于 2018-6-25 11:56
二维数组是个嵌套数组,指针数组是内嵌套,数组指针是外嵌套。

在我看来都是地址,所有的符号都是地址
不管是数组名还是函数名,又或是普通变量名,用于 goto 跳转的标签
或是其他(暂时我想不到还有什么)
在我看来这些都是地址
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-6-25 12:07:26 | 显示全部楼层
要站在汇编语言的角度看C语言的指针
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-6-25 12:09:35 | 显示全部楼层
https://blog.csdn.net/pipinuan/article/details/53193289

二维数组及多维数组的指针总结
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-3-29 00:09

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表