鱼C论坛

 找回密码
 立即注册
查看: 1165|回复: 21

[已解决]参数和指针的问题

[复制链接]
发表于 2020-4-23 19:22:41 | 显示全部楼层 |阅读模式

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

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

x
#include <stdio.h>

void func(int b[][3]);

void func(int b[][3])
{
        printf("%d\n", b[2][2]);
}

int main(void)
{
        int a[3][4] = {
                {1, 2, 3, 4},
                {5, 6, 7, 8},
                {9, 10, 11, 12}
        };

        func(a);       //这个a传的应该是数组第一个元素的地址吧吧,那应该是1??
        return 0;
}

函数里面就应该是然后b【1】【3】,这个数组应该还是去a的数,但是怎么会有b【2】【2】???不是越界么,但是越界就还是取a的值,有没有大佬解释一下
最佳答案
2020-4-23 21:52:04
#include <stdio.h>

void func(int b[][3]);

void func(int b[][3])
{
        printf("%d\n", b[2][2]);
}

int main(void)
{
        int a[3][4] = {
                        {1, 2, 3, 4},
                        {5, 6, 7, 8},
                        {9, 10, 11, 12}
        };
        /*
        
        b[4][3]={
        
        {1,2,3},
        {4,5,6},
        {7,8,9},
        {10,11,12}
        }
        
        
        */
        func((int(*)[3])a);       //
        return 0;
}
我用vs2017调试的时候,不能直接传a的,需要传确定的指针类型
总的来说
作为函数参数的数组,其实你传递进去的是数组的地址,啥意思,就是你传递的是一个指针而已
那么请问,指针如何与数组相转换?
相比你应该见过这样子的例子,b[2][2] = *(*(b+2)+2)
对于指针的偏移,你要理解它不同的含义,你可以试着sizeof(b) 和sizeof(*b),看看两个的长度
对于这个式子: *(*(b+2)+2)
我们像因式分解一样,慢慢分析
b+2 这是啥意思,是从b指针这个地址开始,偏移 sizeof(b)*2个长度
*(b+2)+2 是指 从b+2的所处的地址开始,偏移sizeof(*b)*2的长度
如果在再琢磨下,就会发现
对于一个
假设是

b[4][3]={
       
        {1,2,3},//0
        {4,5,6},//1
        {7,8,9},//2
        {10,11,12}//3
        }
       
所谓 b+2  其实就是让指针指向 大数组的{7,8,9}这个小数组的头部
所谓 *(b+2)+2   其实就是让指针从小数组的头部偏移两个单位 从7偏移两个,是多少?
请记住,此刻还是地址,那取地址上的内容,则应该是 *(*(b+2)+2  ) =9

你把这个搞明白了,问题就迎刃而解了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-4-23 19:28:55 | 显示全部楼层
c 数组越界不管的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-4-23 19:31:44 | 显示全部楼层

那他是怎么运行的呢,怎么取值输出的??
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-23 19:33:43 From FishC Mobile | 显示全部楼层
本帖最后由 倒戈卸甲 于 2020-4-23 19:35 编辑
孤世星辰 发表于 2020-4-23 19:31
那他是怎么运行的呢,怎么取值输出的??


你这a不是三行四列12个元素吗?b[2][2]才取到第9个元素怎么会越界
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-4-23 19:36:46 | 显示全部楼层
倒戈卸甲 发表于 2020-4-23 19:33
你这a不是三行四列12个元素吗?b[2][2]才取到第9个元素怎么会越界

但是你把a传过去不是传第一个元素的地址么,不是1么,然后调用函数里面就应该是int b 【1】【3】啊
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-23 19:39:58 | 显示全部楼层
孤世星辰 发表于 2020-4-23 19:31
那他是怎么运行的呢,怎么取值输出的??

内存上写着什么就输出什么
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-4-23 19:42:49 | 显示全部楼层
永恒的蓝色梦想 发表于 2020-4-23 19:39
内存上写着什么就输出什么

最后答案输出是9,但是我不知道为什么,我觉得应该不是随机访问,应该是输出了a里面的9吧,不是很懂
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-23 19:43:32 From FishC Mobile | 显示全部楼层
孤世星辰 发表于 2020-4-23 19:36
但是你把a传过去不是传第一个元素的地址么,不是1么,然后调用函数里面就应该是int b 【1】【3】啊

什么b[1][3]啊,你这理解有误,b[][3]是一个定义了列数为3,但没有定义行数的二维数组。参数传值是让它拿到一个地址就行,不是要把1放进下标里面。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-23 19:45:04 | 显示全部楼层
孤世星辰 发表于 2020-4-23 19:42
最后答案输出是9,但是我不知道为什么,我觉得应该不是随机访问,应该是输出了a里面的9吧,不是很懂


这块内存在main里写入了,所以说能正确输出。
但是c不会检查越不越界,越界了写出什么来都可能
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-23 19:54:10 From FishC Mobile | 显示全部楼层
事实上,你完全可以int *p=a,然后func(p)这样调用func函数,这个总不会觉得一个p有能力给int[][3]添个数字进去吧?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-23 20:00:22 From FishC Mobile | 显示全部楼层
你对数组的本质还没建立一个认识。数组是一段连续的内存。这里的a就是12个连续的int组成的数据结构。a这个数组名只是把首元素交出去。不会交什么序号下标之类的东西给别人。一个int指针或者一个数组都能接收这个首地址。int指针接受后就按着指针的方式对这段内存进行访问。数组接收后也按自己的方式去访问这段内层。一维数组、二维数组、三维数组都能接受这个首地址,接受后就分别以自己的规则去访问后续地址。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-4-23 20:21:14 | 显示全部楼层
倒戈卸甲 发表于 2020-4-23 20:00
你对数组的本质还没建立一个认识。数组是一段连续的内存。这里的a就是12个连续的int组成的数据结构。a这个 ...

这个是小甲鱼29的课后题,他问我这个代码会输出啥,答案是9,看你的解释我知道他不会放进那个b【】【】但是这个a的值传哪里去了呢,我不知道他他是怎么运行输出这个9的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-23 20:29:51 From FishC Mobile | 显示全部楼层
本帖最后由 倒戈卸甲 于 2020-4-23 21:39 编辑
孤世星辰 发表于 2020-4-23 20:21
这个是小甲鱼29的课后题,他问我这个代码会输出啥,答案是9,看你的解释我知道他不会放进那个b【】【】但 ...


b[][]拿到a的首地址啊。这怎么还能不理解。看来要举个例子了。a数组的12个元素存放在10001到10048这段内存上,只要访问内存10001就能拿到1,访问10005就能拿到2……访问10048就能拿到12。a传值是把10001这个内存传给b,b现在是个二维数组,按自己的规则去访问这段内存,b[0][0]会找到10001,b[0][1]找到10005,b[0][2]找到10009,b[1][0]找到10013……这里b[2][2]则找到10033拿出里面的9。再说不懂我要怒了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2020-4-23 21:52:04 | 显示全部楼层    本楼为最佳答案   
#include <stdio.h>

void func(int b[][3]);

void func(int b[][3])
{
        printf("%d\n", b[2][2]);
}

int main(void)
{
        int a[3][4] = {
                        {1, 2, 3, 4},
                        {5, 6, 7, 8},
                        {9, 10, 11, 12}
        };
        /*
        
        b[4][3]={
        
        {1,2,3},
        {4,5,6},
        {7,8,9},
        {10,11,12}
        }
        
        
        */
        func((int(*)[3])a);       //
        return 0;
}
我用vs2017调试的时候,不能直接传a的,需要传确定的指针类型
总的来说
作为函数参数的数组,其实你传递进去的是数组的地址,啥意思,就是你传递的是一个指针而已
那么请问,指针如何与数组相转换?
相比你应该见过这样子的例子,b[2][2] = *(*(b+2)+2)
对于指针的偏移,你要理解它不同的含义,你可以试着sizeof(b) 和sizeof(*b),看看两个的长度
对于这个式子: *(*(b+2)+2)
我们像因式分解一样,慢慢分析
b+2 这是啥意思,是从b指针这个地址开始,偏移 sizeof(b)*2个长度
*(b+2)+2 是指 从b+2的所处的地址开始,偏移sizeof(*b)*2的长度
如果在再琢磨下,就会发现
对于一个
假设是

b[4][3]={
       
        {1,2,3},//0
        {4,5,6},//1
        {7,8,9},//2
        {10,11,12}//3
        }
       
所谓 b+2  其实就是让指针指向 大数组的{7,8,9}这个小数组的头部
所谓 *(b+2)+2   其实就是让指针从小数组的头部偏移两个单位 从7偏移两个,是多少?
请记住,此刻还是地址,那取地址上的内容,则应该是 *(*(b+2)+2  ) =9

你把这个搞明白了,问题就迎刃而解了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-4-23 21:58:19 | 显示全部楼层
倒戈卸甲 发表于 2020-4-23 20:29
b[][]拿到a的首地址啊。这怎么还能不理解。看来要举个例子了。a数组的12个元素存放在10001到10048这段 ...

哦哦哦我会了我老是对着a数组找【2】【2】原来b换了一下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-23 22:20:50 | 显示全部楼层
本帖最后由 倒戈卸甲 于 2020-4-23 22:22 编辑
孤世星辰 发表于 2020-4-23 21:58
哦哦哦我会了我老是对着a数组找【2】【2】原来b换了一下


小甲鱼的课你肯定没认真听,这个知识点小甲鱼讲的很清楚,这种用内存编号来举例,小甲鱼同样讲过
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-23 22:44:16 | 显示全部楼层
4goodworld 发表于 2020-4-23 21:52
我用vs2017调试的时候,不能直接传a的,需要传确定的指针类型
总的来说
作为函数参数的数组,其实你传 ...

b指向{1,2,3}整个数组,b+2指向{7,8,9}整个数组,*(b+2)才真正指向{7,8,9}的头部,所以*(b+2)+2 能指向9.
这其中的原理在于数组的地址和数组的首地址相等,数组设计的很巧妙,假如二级指针p指向一维数组a,那*p指向a的首地址,但*p与p又是相等的。p二层解引用能访问a[0],同时还可以令一级指针q=p,q一级解引用就访问到a[0]。
不过在C99标准以前,这样的转换常常会令编译器崩溃
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2020-4-23 22:52:00 | 显示全部楼层
本帖最后由 4goodworld 于 2020-4-23 22:53 编辑
倒戈卸甲 发表于 2020-4-23 22:44
b指向{1,2,3}整个数组,b+2指向{7,8,9}整个数组,*(b+2)才真正指向{7,8,9}的头部,所以*(b+2)+2 能指向9.
...


你是认为我的解释有问题吗?
但 正如你说言 数组的地址和数组的首地址相等
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-23 22:53:34 From FishC Mobile | 显示全部楼层
4goodworld 发表于 2020-4-23 22:52
你是认为我的解释有问题吗?

解释不准确。b+2不会指向你所谓的小数组的头部
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-4-23 23:09:25 From FishC Mobile | 显示全部楼层
4goodworld 发表于 2020-4-23 22:52
你是认为我的解释有问题吗?
但 正如你说言 数组的地址和数组的首地址相等

数组地址与数组首地址相等,只能说明你的这个解释也不算错。但不够精准。
当然C11标准以后,实际使用的中也无所谓了。这里的b虽然是数组指针,但可以被普通指针接收,在必要的时候编译器还能将其自动解释为*b。
不过原理还是归原理,数组指针不会指向一个数值
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-1-14 20:14

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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