鱼C论坛

 找回密码
 立即注册
查看: 1460|回复: 14

[已解决]关于指针....

[复制链接]
发表于 2018-9-16 11:41:24 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
#include <stdio.h>

int main()
{
                int temp[5] = {1, 2, 3, 4, 5};
                int (*p2)[5] = &temp;
                int i;
               
                for (i = 0; i < 5; i++)
                {
                                printf("%d\n", *(*p2 + i));
                }
               
                return 0;
}

整个程序表示看的不太明白,temp本身代表的就是一个地址,再加一个取地址运算符是什么意思呢?

而且下面这个 *(*p2 + i)这里也看的不太懂,搞不明白是怎么实现最后的结果的。

望大神赐教!!!
最佳答案
2018-9-16 20:24:22
啊涂涂 发表于 2018-9-16 19:12
首先非常感谢大家前来帮忙,感激不尽,感谢每位鱼油的热心帮忙!!!但是本小白真的还是有点一头 ...

步长可以这样理解,不同类型的指针在跳转时要移动的位置长度不一样。既然指针本质都是存放地址的,那为什么还要指定int,float之类的类型呢?其实就是为了在实现指针跳转时明确移动多少位置,因为不同类型变量的存储方式和所占字节是不同的。例如,int *p ,那么p+1就意味着让地址值增加4个字节,而如果是float *p的话,p+1意味着让地址值增加8个字节,如果是 int (*p)[5]的话,p+1就要增加这个5个int元素的数组所占的字节长度,所以跳一步确实是要跳完整个数组的,即数组的末尾后面了。搂主其实可以先理解二维数组,再回过头来看这个。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-9-16 12:14:12 | 显示全部楼层
本帖最后由 moc 于 2018-9-16 12:18 编辑

int temp[5] = {1, 2,3,4, 5};    这句话的意思是定义一个数组,temp是数组的首地址,也就是一个指针,他的类型是数组元素的类型,也就是说temp可以理解为指向整型类型的指针;它的步长是4个字节(int);
&temp 表示的含义是它是一个指向该数组类型(int[5])的指针,它的步长是数组元素个数乘sizeof(int);
int (*p2)[5]的意思是定义了一个指向int[5]数组类型的指针,那么自然可以让他指向上面的数组类型即&temp;
*(*p2+i)就是p2 [ i ][ 0 ]也即temp[ i ][ 0 ],也就是temp[ i ]
不知道明白了么?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2018-9-16 12:21:28 | 显示全部楼层
作为数组,temp的值确实是一个地址,加上取址运算符是为了程序的可读性,让人一看就知道,这里用的是变量temp的地址,无论temp本身的类型是什么。

*(*p2+i),这里,假设i=1,也就是*(*p2+1)
*p2是取值,p2的值是数组第一个元素的地址,所以这里取的是数组的第一个元素的值1,加一呢,就是2,*2,就是取内存地址为2的值。
这样说,可能比较绕,但仔细理一下逻辑。
然后,大概会说,取内存地址2的值,不是可能报错么?是有可能的,这里应该是为了和 *(*(p2+1)) 区分,后者就是取数组第2个元素的值,因为后者是对指针的值,也就是元素的地址进行操作,会按照定义的数组类型进行加减,换句话说,假设int占2个字节,那么指针加1以后,就是到了数组指针的第二个元素,就是取数组第二个元素的值了.

很绕……
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2018-9-16 12:36:58 From FishC Mobile | 显示全部楼层
本帖最后由 claws0n 于 2018-9-16 16:57 编辑

用手机果然不方便......
取址对于非常量 non scalar(就是不是单一个数据的【量】)来说是可以省略的,添加可读性而已。

至于下面的用法是因为跨度的问题。指针解引用你了解?就是说 int *p = &a; 那么放在等号右边时*p == a 的值。

如果这样写int *p1 = temp; *(p1 + i);
int *p2[5] = *(*p2 + i);
p1 的跨度为 1,加一时,就是第二个元素了,然后解引用。
p2 的跨度为 5,如果直接加一,会指向第六个元素,已经越界。所以先解引用,成为指向第一个元素的指针,再选择偏移量。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2018-9-16 13:01:13 From FishC Mobile | 显示全部楼层
我是这么理解的(*p2)[5]数组,所以*p2可以看做是数组名,所以*p2=temp,所以p2=&temp,*(*p2+i)...*p2=temp所以*p2指向数组第一个元素+i偏移到第i个元素的地址,在解引用得出第i个元素的值
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2018-9-16 13:22:10 From FishC Mobile | 显示全部楼层
wjp 发表于 2018-9-16 13:01
我是这么理解的(*p2)[5]数组,所以*p2可以看做是数组名,所以*p2=temp,所以p2=&temp,*(*p2+i)...*p2= ...

一维数组是不需要的,高维数组才需要。主要是跨度问题,不然做不到直接索引。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2018-9-16 13:39:00 | 显示全部楼层
堆地址 和 栈地址  是不一样的   temp是local 本地变量

但是  temp作为一个指针指向了堆地址的空间

明白?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2018-9-16 17:39:47 | 显示全部楼层
知识依据:int(*p)[m]   p是指向由m个整型元素组成的一维数组的指针变量(谭浩强的《C程序设计》)
1、数组名temp本身数组第一个地址,(temp+i)则表示temp[i]的地址,步长为1个元素的长度(1个int)。
2、&temp虽然也是一个地址,但它指向整个数组,步长为整个数组的总长度(5个int)
3、int(*p)[5] 定义了一个指针变量p,它指向包含5个整型元素的整个一维数组(5个int),p每跳转一次,就会移动5个int的长度,因此从指针的类型上来说,&temp才与p是等价的,而不能把temp赋给p,二者的步长完全不同。
4、既然 p=&temp(这里“=”是数学中的等号,不是赋值运算),那么同时在前面加上 *号来取值则写成: *p= *(&temp),等号右边其实就是temp本身了。继续同时跳转i,*p+i =temp+i。最后在同时取值:
*(*p+i)=*(temp+i),而*(temp+i)即temp[i],因此程序输出数组元素的值。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2018-9-16 17:44:59 | 显示全部楼层
longff9009 发表于 2018-9-16 17:39
知识依据:int(*p)[m]   p是指向由m个整型元素组成的一维数组的指针变量(谭浩强的《C程序设计》)
1、数 ...

int *p[m]表示的是一个数组,每个数组元素都是一个int 型指针变量
int (*p)[m] 表示的就是一个指针,只是该指针类型有些不一样罢了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2018-9-16 17:46:04 | 显示全部楼层
wjp 发表于 2018-9-16 13:01
我是这么理解的(*p2)[5]数组,所以*p2可以看做是数组名,所以*p2=temp,所以p2=&temp,*(*p2+i)...*p2= ...

int *p[m]表示的是一个数组,每个数组元素都是一个int 型指针变量
int (*p)[m] 表示的就是一个指针,只是该指针类型有些不一样罢了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-9-16 19:12:05 | 显示全部楼层
首先非常感谢大家前来帮忙,感激不尽,感谢每位鱼油的热心帮忙!!!但是本小白真的还是有点一头雾水的感觉

如果把&array理解为取字符串第一个数字的地址这很容易理解,但在学习这课的过程中,小甲鱼一直在强调 array != &array。

后者是把一个数组当做整体来看待的,取的是一整个数组的地址。但是如果这个是以整个数组为地址进行偏移的话,岂不是会移动到下一个数组里去?

还有就是对“步长”这块的含义不是特别清楚,是不是 array和&array除了在步长方面,别的方面都一样?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-9-16 19:15:03 | 显示全部楼层
还有就是这里

#include <stdio.h>

int main()
{
        int array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        int *p = (int *)(&array + 1);

        printf("%d\n", *(p - 6));

        return 0;
}

这个&array + 1怎么就表示的是跑到数组最后一个元素的位置去了?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-9-16 19:20:30 | 显示全部楼层
int temp[5] = {1, 2, 3, 4, 5};
                int (*p2)[5] = &temp;
                int i;
               
                for (i = 0; i < 5; i++)
                {
                                printf("%d\n", *(*p2 + i));
                }

int main()
{
        int array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        int *p = (int *)(&array + 1);

        printf("%d\n", *(p - 6));

*(*p2 + 1)和 (&array + 1)为什么就因为一个*号,两者差别这么大?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-9-16 20:24:22 | 显示全部楼层    本楼为最佳答案   
啊涂涂 发表于 2018-9-16 19:12
首先非常感谢大家前来帮忙,感激不尽,感谢每位鱼油的热心帮忙!!!但是本小白真的还是有点一头 ...

步长可以这样理解,不同类型的指针在跳转时要移动的位置长度不一样。既然指针本质都是存放地址的,那为什么还要指定int,float之类的类型呢?其实就是为了在实现指针跳转时明确移动多少位置,因为不同类型变量的存储方式和所占字节是不同的。例如,int *p ,那么p+1就意味着让地址值增加4个字节,而如果是float *p的话,p+1意味着让地址值增加8个字节,如果是 int (*p)[5]的话,p+1就要增加这个5个int元素的数组所占的字节长度,所以跳一步确实是要跳完整个数组的,即数组的末尾后面了。搂主其实可以先理解二维数组,再回过头来看这个。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2018-9-16 21:04:17 | 显示全部楼层
再次感谢其他楼层热心帮助的鱼油们,楼猪选了一个我个人比较能理解的答案
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-11-30 09:57

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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