鱼C论坛

 找回密码
 立即注册
查看: 1266|回复: 4

指针与二维数组的地址问题

[复制链接]
发表于 2023-9-16 18:51:23 | 显示全部楼层 |阅读模式

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

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

x
这是代码:

#include <stdio.h>

int main()
{
        int a[2][3]={1,2,3,4,5,6};
        printf("a的地址:%p\na[0]的地址:%p\na[0][0]的地址:%p\n\n",a,a[0],a[0][0]);
       
        printf("a的地址:%d\na[0]的地址:%d\na[0][0]的地址:%d\n\n",&a,&a[0],&a[0][0]);
       
        printf("a+1:\n值:%d\na+1地址:%p\na[0]+1值:%d\na[0]+1地址:%p\na[0][0]+1值:%d\na[0][0]+1地址:%p\n\n",a+1,a+1,a[0]+1,a[0]+1,a[0][0]+1,a[0][0]+1);
       
        printf("*(a+1)值:%d\na+1地址:%p\n*(a[0]+1)值:%d\na[0]+1地址:%p\na[0][0]+1值:%d\na[0][0]+1地址:%p\n\n",*(a+1),a+1,*(a[0]+1),a[0]+1,a[0][0]+1,a[0][0]+1);
       
        printf("*(*(a+1))值:%d\na+1地址:%p\n*(a[0]+1)值:%d\na[0]+1地址:%p\na[0][0]+1值:%d\na[0][0]+1地址:%p\n\n",*(*(a+1)),a+1,*(a[0]+1),a[0]+1,a[0][0]+1,a[0][0]+1);
       
    for(int i=0;i<2;i++)
    {
            for(int j=0;j<3;j++)
            printf("%p,%d\n",a[i][j],&a[i][j]);
        }
}
  
这是终端输出:

a的地址:000000000062FE00
a[0]的地址:000000000062FE00
a[0][0]的地址:0000000000000001

a的地址:6487552
a[0]的地址:6487552
a[0][0]的地址:6487552

a+1:
值:6487564
a+1地址:000000000062FE0C
a[0]+1值:6487556
a[0]+1地址:000000000062FE04
a[0][0]+1值:2
a[0][0]+1地址:0000000000000002

*(a+1)值:6487564
a+1地址:000000000062FE0C
*(a[0]+1)值:2
a[0]+1地址:000000000062FE04
a[0][0]+1值:2
a[0][0]+1地址:0000000000000002

*(*(a+1))值:4
a+1地址:000000000062FE0C
*(a[0]+1)值:2
a[0]+1地址:000000000062FE04
a[0][0]+1值:2
a[0][0]+1地址:0000000000000002

0000000000000001,6487552
0000000000000002,6487556
0000000000000003,6487560
0000000000000004,6487564
0000000000000005,6487568
0000000000000006,6487572

想问一下:
1.在第一次printf和第二次printf中为什么用%p输出a[0][0]的结果和用%d输出&a[0][0]的结果是不一样的?(这不是进制转换的问题);
2."a+1"这个指针的地址是多少,真的是000000000062FE0C,但是这个不是a[2][1]=4的十六进制地址吗?用%d输出&a+1时系统提示了错误:lvalue required as unary '&' operand,不知道该怎么弄;

谢谢大家的解答!!!


              
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-9-16 18:51:28 | 显示全部楼层
1.在第一次printf和第二次printf中,用%p输出a[0][0]的结果和用%d输出&a[0][0]的结果是不一样的,原因是%p输出的是a[0][0]的地址,是一个指针类型,%d输出的是&a[0][0]的地址,是一个整型类型。因为在32位系统中,指针类型和整型类型的长度不同,指针类型长度为4字节,整型类型长度为2字节,所以输出的结果不同。

2. "a+1"这个指针的地址是000000000062FE0C,表示的是a[1]的地址,a[2][1]=4的十六进制地址是000000000062FE0C+4=000000000062FE10。如果要输出&a+1,可以写成(int(*)[2][3])&a+1,表示将&a的地址转换为指向二维数组的指针类型,再加1。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-9-16 18:51:38 | 显示全部楼层
1. 在第一次printf和第二次printf中,输出a[0][0]的结果和&a[0][0]的结果不同的原因是格式化输出的占位符不同。%p是用来输出指针地址的占位符,它将地址值以十六进制形式输出;而%d是用来输出整数的占位符,它将整数值以十进制形式输出。

2. "a+1"这个指针的地址是000000000062FE0C,这是因为在二维数组中,a表示数组的首地址,a+1表示数组第二行的地址。根据数组的存储规则,二维数组在内存中是按行排列的,即每一行连续存储。所以a+1的地址是第二行的地址。

当你尝试使用%d输出&a+1时出现错误提示 "lvalue required as unary '&' operand",是因为&a+1是一个非法操作。&a是取数组a的地址,它是一个右值,无法再取其地址。正确的方式应该是直接输出a+1的值,即printf("%p\n", a+1)。
如果问题已经解决,请设置最佳答案
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-9-17 23:59:43 | 显示全部楼层
1.提出第一个问题是因为没有搞懂获取地址时%p与%d的用法:
%p的用法:
(1)假设a 是一个已被赋值的整型变量:
若运行printf("%p",a); 则会输出a的值(十六进制),
若运行printf("%p",&a); 则会输出a的地址(十六进制)
(2)假设a 是一个指向变量b的指针:
若运行printf("%p",a); 则会输出变量b的地址(十六进制),
若运行printf("%p",&a); 则会输出指针a的地址(十六进制)
(3)假设a是一个数组的数组名:
无论运行若运行printf("%p",a); 还是若运行printf("%p",&a)都只会输出a数组第一个元素的地址(十六进制)

验证代码:#include <stdio.h>

int main()
{
        int a[2][3]={4,5,6,7,8,9};
        printf("a的地址:%p\na[0]的地址:%p\na[0][0]的地址:%p\n\n",a,a[0],a[0][0]);
       
        printf("%p\n\n",&a);
          
    for(int i=0;i<2;i++)
    {
            for(int j=0;j<3;j++)
    {
                printf("%p\n",a[i][j]);
            printf("%p\n",&a[i][j]);
            printf("%d\n",&a[i][j]);
            printf("\n\n");
        }
}
     int a=8;
        int *p;
        int *p2;
        printf("%p\n",&a);  //变量a的地址
        p=&a;
        printf("%p\n",p);  //p指针里面的内容(即变量a的地址)
        printf("%p\n",*p);  //相当于以十六进制输出变量a
        printf("%p\n",a);  //相当于以十六进制输出变量a
        p2 = p;
        printf("%p\n",p2);  //p2指针里面的内容(即变量a的地址)
        printf("p=%p\n",&p);  //p指针的存储地址
        printf("p2=%p\n",&p2);  //p2指针的存储地址
        printf("%d\n",*p2);  //以十进制输出变量a

        return 0;
}

运行结果:

a的地址:000000000062FE00
a[0]的地址:000000000062FE00
a[0][0]的地址:0000000000000004

000000000062FE00

0000000000000004
000000000062FE00
6487552


0000000000000005
000000000062FE04
6487556


0000000000000006
000000000062FE08
6487560


0000000000000007
000000000062FE0C
6487564


0000000000000008
000000000062FE10
6487568

000000000062FE1C
000000000062FE1C
0000000000000008
0000000000000008
000000000062FE1C
p=000000000062FE10
p2=000000000062FE08
8

但是由于数组不是指针,因此在尝试printf("%p\n",&(a+1)); 时依然出现错误:lvalue required as unary '&' operand,csdn上的解释是:因为函数的返回值存储在eax寄存器中,所以不可以直接操作,需要将其mov到内存中才可以操作。所有的函数都一样,不可以直接取地址。结合数组传参的退化,大概能理解错误的产生原因,但更深层的就涉及到汇编了,很多东西我还没学,现阶段只能到这里了,这个问题还是没有能够很透彻的解决,望指正与指导。谢谢!!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-10-1 10:56:51 | 显示全部楼层
本帖最后由 xiaotubie 于 2023-10-1 11:08 编辑

楼上的这些人,一个个不知道在回答什么,楼主都说了不是进制问题!
二楼还说%p输出的是a[0][0]的地址,你看仔细,那是地址吗? 人家传进去的是a[0][0] !

1.在第一次printf和第二次printf中为什么用%p输出a[0][0]的结果和用%d输出&a[0][0]的结果是不一样的?(这不是进制转换的问题);

答:
        a[0][0]是数组的第一个元素1,&a[0][0]是第一个元素1的指针(也有人称为地址),一个是内存中的值,一个是内存所在的地址,能一样吗?


2."a+1"这个指针的地址是多少,真的是000000000062FE0C,但是这个不是a[2][1]=4的十六进制地址吗?用%d输出&a+1时系统提示了错误:lvalue required as unary '&' operand,不知道该怎么弄;

答:
        数组名a在这里会转换成首元素的指针,对于二维数组a来说这时的首元素是{1,2,3}这个一维数组,因此a+1就是指向{4,5,6}这个一维数组的指针(输出来就是一个指针或者说地址,根本不需要再&了)。
        楼主问的a[2][1]不对,这个已经超出了数组的范围,虽然你这样写,语法没问题,编译器也可能不会检查范围,但实际结果不是元素4,如果你想表示那个元素4,那就写a[1][0]。
        a+1从输出的值来看确实和元素4的地址 &a[1][0]一样,但是意义不一样,一个是{4,5,6}的指针(或者叫地址),一个是元素4的地址 。因此a+1+1 和&a[1][0]+1也不会一样。
        楼主又说&a+1会提示错误,这个应该是不会提示错误的,除非你用的很老的编译器,那就说不定了。  &a表示的是这个二维数组a的指针(地址)(a用于&符号时不会转换成首元素的指针),a此时就是一个左值(lavlue)代表了数组本身,是可以用&符号的。
        &a+1是指向下一个二维数组的指针(如果一个int类型元素占用4字节,那么结果输出是数组a的地址+24)。
        如果你写&(a+1)这样才会提示lvalue required as unary '&' operand,a+1这个表达式不是一个左值。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-10-6 01:47

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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