C语言数组与指针

我的最美范 2014-03-16 04:37:29
加精



看到一篇关于C语言指针的文章,正好最近在看《C和指针》就去看了一下。《一道 C 语言指针访存题目的引申》,里面的第一个题目就把我难住了。

帮助123456789 #include <stdio.h> int main() { int a[5] = {1, 2, 3, 4, 5}; int *pa = (int)(&a) + 1; printf("%x\n", *pa); return 0; }

正确的输出结果应该是 2000000.自诩对C指针还比较了解,不就是保存内存地址的变量吗?有什么难的,后来才发现我错了。我想的是&a,是对数组名字去地址,那出来的结果不就是保存a的地址,那这样给他转换成int变量之后再加1,然后再赋值给一个int*指针是会出错的,结果我编译了一下,真的出错了:
error: invalid conversion from `int' to `int*'.
无法将int值赋值给int *指针变量,我修改了一下,在(int)(&a) + 1;前面加上了一个强制类型转换 (int *),编译之后输出结果:

我以为正确了,虽然他说正确答案是 2000000。后来我又仔细看了一下源代码,发现 int *pa = (int *)(int)(&a) + 1; 这句代码是先将 &a 转换成指针再在其基础加 1。而原来的意思是先给 &a 加 1再转换成指针,结果我再修改了一下代码:int *pa = (int *)((int)(&a) + 1); 这样结果竟然正确了,输出2000000:



这时候我完全朦了,这是怎么回事?后来我将 &a 和 a作为整数输出,想看看它到底是什么,结果发现

帮助12 printf("%d\n",&a); printf("%d\n",a);

他们的输出结果是一样的,也就是说a 和 &a 的值一样,我以为问题到这里就解决了,但是我还是不能理解为什么会输出 2000000.于是我到网上去搜索了一下资料,结果搜到了 对数组名取地址是什么? 。里面说


帮助123 1 int array[100]; 3 memset(array, 0, sizeof(array)); 4 memset(&array, 0, sizeof(array));

第3行和第4行有什么不同吗?其实从效果上来说是一样的,但是这里要注意 array 和 &array 的类型是不同的。array 相当于 &array[0],而 &array 是一个指向 int[100] 的指针,类型是 int(*)[100]。”

总算知道了a和&a的差别,但是我还是不明白为什么它会输出 2000000,这到底是为什么呢?

我试着修改了一下代码:

int a[] = {1,5};

这样之后的输出结果成了 : 5000000 原来和数组a的第二个元素有关系。哈哈,有点懂了,经过我N次的试验。

首先我们的代码是:

帮助123 int a[] = {1,2}; int *pa = (int *)((int)(&a) + 1); printf("%x\n", *(pa));

我这边编译的结果 a[0]也就是a代表的地址是 0x22ff70 a[1] 的地址是 0x22ff74 。我查看了一下内存(使用printf看的),内存里的数据是这样的:

帮助12 0x22ff70 0x22ff71 ... 0x22ff74 ... 0x22ff77 01 00 ... 02 ... 00

而且我们知道访问内存中的数据是高字节的地址是高位,低字节的地址是低位。也就是说如果我的地址是 0x22ff70,以这个地址访问一个整数,得到的整数就是73,72,71,70的数据排列 即00000001(以前学过一点汇编,加上自己试验了一下,就出来的 :),也就是1。如果访问0x22ff74 也就是 00000002 是2.如果访问 0x22ff71 也就是从74开始 02000000。这不就是我们的正确答案 2000000 。
问题解决!写得比较乱,勿怪。若有错误,欢迎指正!
(全文完)
...全文
3115 87 打赏 收藏 转发到动态 举报
写回复
用AI写文章
87 条回复
切换为时间正序
请发表友善的回复…
发表回复
asdfjmjgx 2016-06-03
  • 打赏
  • 举报
回复
不看了。要吐了。。
小强100 2016-04-17
  • 打赏
  • 举报
回复
学习受用了!~~
laosizhender 2015-12-12
  • 打赏
  • 举报
回复
回帖赚积分。。
  • 打赏
  • 举报
回复
引用 39 楼 lming_08 的回复:
楼主写了这么多,我来总结下吧。 数组a存储的内容,按20个字节(小端模式)分别为: 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 其中a指向01开始处
int *pa = (int *)((int)(&a) + 1);
这里pa相比a地址,增加一个字节,指向01后面的00,所以int *pa表示的内容为00 00 00 02,printf出来就是2000000
int *pc = a + 1;
这里pc指向02开始处,int *pc表示的内容为02 00 00 00,printf出来就是00 00 00 02
int *pb = (int *)&a + 1;
这里pb指向数组a越界的地方a[5],int *pb表示的内容为内存未初始化的值。
正解!
蓝兔先生 2014-10-09
  • 打赏
  • 举报
回复
真是苦口婆心阿
黑帽子和猫 2014-10-04
  • 打赏
  • 举报
回复
回帖,受用了
你妹的特盗不 2014-06-26
  • 打赏
  • 举报
回复
引用 79 楼 lfs09 的回复:
最簡單的理解, 指針+1,其實地址值加的不是1而是加的指針類型大小 數字+1,就是數字+1 int iBuf[2]={1,2}; int *iP=iBuf; iP+1 -->指向的地址應該是 &iBuf[2] 上面這句也等於 (int*)(int(iP)+4) int(iP)+1就不是&iBuf[2]了.
表述有點錯誤 指針+1,其實地址值加的不是1而是加的指針類型大小 應該為 指針+1,其實地址值加的不是1而是加的指針所對應的數據類型大小
你妹的特盗不 2014-06-26
  • 打赏
  • 举报
回复
最簡單的理解, 指針+1,其實地址值加的不是1而是加的指針類型大小 數字+1,就是數字+1 int iBuf[2]={1,2}; int *iP=iBuf; iP+1 -->指向的地址應該是 &iBuf[2] 上面這句也等於 (int*)(int(iP)+4) int(iP)+1就不是&iBuf[2]了.
tdma 2014-06-24
  • 打赏
  • 举报
回复
看一遍懂一遍,下次看到又得懵一会,书上很多代码都是这样额。
zhouljsh 2014-06-23
  • 打赏
  • 举报
回复
牛角尖有的时候还是挺关键的
信阳毛尖 2014-06-23
  • 打赏
  • 举报
回复
赵4老师 2014-06-23
  • 打赏
  • 举报
回复
//char (*(*x[3])())[5];//x是什么类型的变量?
//
//分析C语言声明,关键是搞清楚这个变量是个什么东西(函数、指针、数组),
//是函数那么剩下的就是他的参数和返回值,
//是指针那剩下部分是说明他指向什么,
//是数组剩下的部分就是说明数组的成员是什么类型。
//解析C语言声明规则:
//从左侧第一个标识符开始,按照优先级进行结合。*表示是..的指针,const表示只读的,volatile表示可变的,[]表示是数组,()表示是函数。
//
//x和[3]结合说明是一个大小为3的数组,该数组指向了一个指针,该指针指向一个函数,该函数的无参数,返回一个指针,该指针指向一个大小为5的char型数组
#include <stdio.h>
#include <typeinfo.h>
char num[5];
char (*x00())[5] {
    return #
}
int main() {
    char (*x000)[5];//返回值
    char (*(x00)())[5];//函数原型,参数为空,返回值为指针
    char (*(*x0)())[5];//数组的元素,是个函数指针
    char (*(*x[3])())[5];//是个数组,大小为3

    x0 = x00;
    x[0] = x0;
    x[1] = x0;
    x[2] = x0;
    printf("typeid(x).name() is %s\n",typeid(x).name());
    return 0;
}
//typeid(x).name() is char (* (__cdecl**)(void))[5]
图灵转世 2014-06-22
  • 打赏
  • 举报
回复
最后一个有问题int *pb = (int *)&a + 1;这个指向的是a[1], (int*)(&a+1)这个才是越界 这个值得再讨论一下。我觉得应该没有越界。电脑上刚重做系统,不然就实验一下。
JasonLeaster 2014-05-12
  • 打赏
  • 举报
回复
引用 70 楼 lis2012 的回复:
[quote=引用 63 楼 u011368821 的回复:]
[quote=引用 62 楼 lming_08 的回复:]
[quote=引用 61 楼 u011368821 的回复:]
GCC segmentation fault..............
test code:

#include<stdio.h>
#include<stdlib.h>

int main()
{
int *p;
int array[5] = {1,2,3,4,5};

*p = (int*)((int)(&array)+1);

printf("%x",*p);

return 0;
}



这种变量都不初始化,乱用指针秀技巧的东西有什么用。。。。
规范编码就是了
反正我这里报错,根本就不允许上面代码的情况出现
测试环境:
linux
编译器:
gcc

你都抄错了代码。。。[/quote]
楼主写的int *pa = (int *)((int)(&a) + 1);
我没明白我哪儿copy错了。我只是改了一下变量名而已[/quote]
*p = (int*)((int)(&array)+1);//你把int* 赋值给你int 你觉得呢?[/quote]




我觉得你开始看过楼主的帖子再回复比较好,我只是照着LZ给出的代码debug
lis2012 2014-05-12
  • 打赏
  • 举报
回复
引用 63 楼 u011368821 的回复:
[quote=引用 62 楼 lming_08 的回复:] [quote=引用 61 楼 u011368821 的回复:] GCC segmentation fault.............. test code:

#include<stdio.h>
#include<stdlib.h>

int main()
{
        int *p;
        int array[5] = {1,2,3,4,5};

        *p = (int*)((int)(&array)+1);

        printf("%x",*p);

        return 0;
}

这种变量都不初始化,乱用指针秀技巧的东西有什么用。。。。 规范编码就是了 反正我这里报错,根本就不允许上面代码的情况出现 测试环境: linux 编译器: gcc
你都抄错了代码。。。[/quote] 楼主写的int *pa = (int *)((int)(&a) + 1); 我没明白我哪儿copy错了。我只是改了一下变量名而已[/quote] *p = (int*)((int)(&array)+1);//你把int* 赋值给你int 你觉得呢?
forever_lovefwb 2014-05-12
  • 打赏
  • 举报
回复
0乖宝贝不哭0 2014-04-08
  • 打赏
  • 举报
回复
落单的毛毛虫 2014-03-28
  • 打赏
  • 举报
回复
引用 66 楼 u014251353 的回复:
[quote=引用 59 楼 mmc1206x 的回复:] [quote=引用 53 楼 u014251353 的回复:] int *pa = (int *)((int)(&a) + 1); (int)(&a)这个表示什么意思呢?
把a的地址转换成了int, 此时在+1 不过是int + 1, 不是int *更不是 int *[5];[/quote] 这个我知道。一个二进制的地址转换成int型,然后是Int+1,然后再把这个Int转换成指向Int的一个指针(地址),结果为什么会指向下一个数组元素呢?这才是问题的关键。[/quote] int一次移动4字节,这里只移动了1字节。
ITSmallSmallBird 2014-03-25
  • 打赏
  • 举报
回复
引用 59 楼 mmc1206x 的回复:
[quote=引用 53 楼 u014251353 的回复:] int *pa = (int *)((int)(&a) + 1); (int)(&a)这个表示什么意思呢?
把a的地址转换成了int, 此时在+1 不过是int + 1, 不是int *更不是 int *[5];[/quote] 这个我知道。一个二进制的地址转换成int型,然后是Int+1,然后再把这个Int转换成指向Int的一个指针(地址),结果为什么会指向下一个数组元素呢?这才是问题的关键。
Black0Star 2014-03-24
  • 打赏
  • 举报
回复
本人也是刚学的,学习学习
加载更多回复(63)

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧