参数和指针的问题
#include <stdio.h>void func(int b[]);
void func(int b[])
{
printf("%d\n", b);
}
int main(void)
{
int a = {
{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的值,有没有大佬解释一下 c 数组越界不管的 永恒的蓝色梦想 发表于 2020-4-23 19:28
c 数组越界不管的
那他是怎么运行的呢,怎么取值输出的?? 本帖最后由 倒戈卸甲 于 2020-4-23 19:35 编辑
孤世星辰 发表于 2020-4-23 19:31
那他是怎么运行的呢,怎么取值输出的??
你这a不是三行四列12个元素吗?b才取到第9个元素怎么会越界
倒戈卸甲 发表于 2020-4-23 19:33
你这a不是三行四列12个元素吗?b才取到第9个元素怎么会越界
但是你把a传过去不是传第一个元素的地址么,不是1么,然后调用函数里面就应该是int b 【1】【3】啊 孤世星辰 发表于 2020-4-23 19:31
那他是怎么运行的呢,怎么取值输出的??
内存上写着什么就输出什么 永恒的蓝色梦想 发表于 2020-4-23 19:39
内存上写着什么就输出什么
最后答案输出是9,但是我不知道为什么,我觉得应该不是随机访问,应该是输出了a里面的9吧,不是很懂 孤世星辰 发表于 2020-4-23 19:36
但是你把a传过去不是传第一个元素的地址么,不是1么,然后调用函数里面就应该是int b 【1】【3】啊
什么b啊,你这理解有误,b[]是一个定义了列数为3,但没有定义行数的二维数组。参数传值是让它拿到一个地址就行,不是要把1放进下标里面。 孤世星辰 发表于 2020-4-23 19:42
最后答案输出是9,但是我不知道为什么,我觉得应该不是随机访问,应该是输出了a里面的9吧,不是很懂
这块内存在main里写入了,所以说能正确输出。
但是c不会检查越不越界,越界了写出什么来都可能 事实上,你完全可以int *p=a,然后func(p)这样调用func函数,这个总不会觉得一个p有能力给int[]添个数字进去吧? 你对数组的本质还没建立一个认识。数组是一段连续的内存。这里的a就是12个连续的int组成的数据结构。a这个数组名只是把首元素交出去。不会交什么序号下标之类的东西给别人。一个int指针或者一个数组都能接收这个首地址。int指针接受后就按着指针的方式对这段内存进行访问。数组接收后也按自己的方式去访问这段内层。一维数组、二维数组、三维数组都能接受这个首地址,接受后就分别以自己的规则去访问后续地址。 倒戈卸甲 发表于 2020-4-23 20:00
你对数组的本质还没建立一个认识。数组是一段连续的内存。这里的a就是12个连续的int组成的数据结构。a这个 ...
这个是小甲鱼29的课后题,他问我这个代码会输出啥,答案是9,看你的解释我知道他不会放进那个b【】【】但是这个a的值传哪里去了呢,我不知道他他是怎么运行输出这个9的 本帖最后由 倒戈卸甲 于 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会找到10001,b找到10005,b找到10009,b找到10013……这里b则找到10033拿出里面的9。再说不懂我要怒了{:10_247:} #include <stdio.h>
void func(int b[]);
void func(int b[])
{
printf("%d\n", b);
}
int main(void)
{
int a = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
/*
b={
{1,2,3},
{4,5,6},
{7,8,9},
{10,11,12}
}
*/
func((int(*))a); //
return 0;
}
我用vs2017调试的时候,不能直接传a的,需要传确定的指针类型
总的来说
作为函数参数的数组,其实你传递进去的是数组的地址,啥意思,就是你传递的是一个指针而已
那么请问,指针如何与数组相转换?
相比你应该见过这样子的例子,b = *(*(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={
{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
你把这个搞明白了,问题就迎刃而解了。
倒戈卸甲 发表于 2020-4-23 20:29
b[][]拿到a的首地址啊。这怎么还能不理解。看来要举个例子了。a数组的12个元素存放在10001到10048这段 ...
哦哦哦我会了我老是对着a数组找【2】【2】原来b换了一下 本帖最后由 倒戈卸甲 于 2020-4-23 22:22 编辑
孤世星辰 发表于 2020-4-23 21:58
哦哦哦我会了我老是对着a数组找【2】【2】原来b换了一下
小甲鱼的课你肯定没认真听,这个知识点小甲鱼讲的很清楚,这种用内存编号来举例,小甲鱼同样讲过 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,同时还可以令一级指针q=p,q一级解引用就访问到a。
不过在C99标准以前,这样的转换常常会令编译器崩溃 本帖最后由 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.
...
你是认为我的解释有问题吗?
但 正如你说言 数组的地址和数组的首地址相等
4goodworld 发表于 2020-4-23 22:52
你是认为我的解释有问题吗?
解释不准确。b+2不会指向你所谓的小数组的头部 4goodworld 发表于 2020-4-23 22:52
你是认为我的解释有问题吗?
但 正如你说言 数组的地址和数组的首地址相等
数组地址与数组首地址相等,只能说明你的这个解释也不算错。但不够精准。
当然C11标准以后,实际使用的中也无所谓了。这里的b虽然是数组指针,但可以被普通指针接收,在必要的时候编译器还能将其自动解释为*b。
不过原理还是归原理,数组指针不会指向一个数值
页:
[1]
2