C数组和指针相关的问题
来源:互联网 发布:t lab软件下载 编辑:程序博客网 时间:2024/05/17 10:42
blog 搬迁中 新地址 http://www.naimin.net
两个面试题
面试时发现很多公司喜欢考一些数组和指针相关的问题。比较常见的是下面这个:
/* main.c */int a[4] = {1, 2, 3, 4};extern void foo();int main(){ foo(); return 0; }/* foo.c */#include<stdio.h>extern int *a;void foo(){ printf("%d \n", a[0]);}
问题是这段代码是否可以正常运行?
最近还碰到个题目是这样的:
int a[5] = {1, 2, 3, 4, 5};int *p = &a + 1;printf("%d", *p);
这段代码的输出是什么?
在表达式中数组名字和指针的关系
要解决上面的两个问题,就要搞清数组名字和指针的关系。
在C中,大部分的表达式中数组名字的值就是数组第一个元素的地址,指针类型是和元素的类型一样,但是一个const的指针。
对于下面这种定义:
int a[10];int *const p;
a是一个整型的的const指针, 和p的类型是一样的。
作为函数参数时:
void func2( int *p );void func2( int a[] );
这两种声明也是等价的。 但绝不能认为数组名字和指针就是等价的。在表达式中有2个例外:
- sizeof: sizeof(a) 的值是数组的大小 ,不是第一个元素指针的大小。
- &操作符。 &操作符返回的是第一个元素的地址,所以下面代码中三个printf输出的地址是一样的:
int a[5];printf("%x\n", a);printf("%x\n", &a[0]);printf("%x\n", &a);
但有意思的是上面代码中&a的类型是 int (*)[5],所以下面代码的输出是这样的:
int a[5];printf("%x\n", &a);printf("%x\n", &a + 1);----------------------------------output: 2686740 2686760
可以看到地址差了20个byte, 就是int a[5]所占用的空间。
所以上面第二个题目的答案是不确定,因为p这个指针已经越界了,不在数组a的范围内了。
编译器对于数组和指针的处理是不同的
对于第一个问题
/* main.c */int a[4] = {1, 2, 3, 4};extern void foo();int main(){ foo(); return 0; }/* foo.c */extern int a[];void foo(){ int x; x = a[0];}
我们来看下这段代码的汇编的代码:
gcc -o ptr_test main.c foo.cobjdump -d ptr_test
080483c8 <foo>: 80483c8: 55 push %ebp 80483c9: 89 e5 mov %esp,%ebp 80483cb: 83 ec 10 sub $0x10,%esp 80483ce: a1 18 a0 04 08 mov 0x804a018,%eax 80483d3: 89 45 fc mov %eax,-0x4(%ebp) 80483d6: c9 leave 80483d7: c3 ret
我们修改下foo.c
/* foo.c */extern int *a;void foo(){ int x; x = a[0];}
然后看下汇编代码:
080483c8 <foo>: 80483c8: 55 push %ebp 80483c9: 89 e5 mov %esp,%ebp 80483cb: 83 ec 10 sub $0x10,%esp 80483ce: a1 18 a0 04 08 mov 0x804a018,%eax 80483d3: 8b 00 mov (%eax),%eax 80483d5: 89 45 fc mov %eax,-0x4(%ebp) 80483d8: c9 leave 80483d9: c3 ret
可以发现不同的地方就是第二段代码多了 mov (%eax),%eax。
为什么会这样呢?
1. 首先,在C语言中 数组下标 array[subscript] 等价于 *( array + ( subscript ) )。 也就是说编译器会将代码中a[0]转化为*(a + 0)也即是 *a, 所以代码中 x = a[0] 会变成 x = *a 。
2. 上面汇编代码中 0x804a018 是全局数组a的地址。 mov 0x804a018,%eax 这句代码就是把地址0x804a018的数据放到寄存器eax中,在我们的代码中地址0x804a018的整型数据就是1。所以eax中的数值就是1。
- 如果声明a为数组,*a的值就是eax中的值。 %eax,-0x4(%ebp)这就就是把*a的值赋给x。
- 如果声明a为指针,程序为了获得*a的值,就要去地址a取值。mov (%eax),%eax,这就是到eax中的值的地址去取整型数据,然后copy到eax中。 这就是一个取值的动作。因为eax中数据是1, 所以对这个地址取值是非法的,程序会终止。
所以第一个问题就是因为编译器对数组和指针的处理是不同的。
对于数组a, 只会到a的地址取值,然后这个值就是*a的值,也就是1。
0x804a018
| 1 | 2 | 3 | 4 |对于指针a, 首先要到a的地址取值,这个值是指针a的值,也就是1。对于*a, 还要有个取值的动作,就是到地址为指针a的值的地方取值,所以就是到地址1去取值。
0x804a018
| 1 | 2 | 3 | 4 |
1
| ? | ? | ? | ? |
- C数组和指针相关的问题
- 关于C语言字符数组、字符串和指针的相关问题
- C语言中与指针相关问题——论数组名和数组名取地址的关系
- 关于二维数组和二维指针的相关问题
- c指针的相关问题
- 数组指针和指针数组的问题
- 指针与数组相关问题的理解
- C++:二维数组和二级指针的传递问题
- 数组和指针相关
- C语言指针、数组指针和指针数组的区别
- 小小的C语言问题指针数组赋值----关于指针和数组。
- 数组和指针的问题
- c/c++--指针数组和数组指针的区别
- 数组相关的指针
- 【C/C++】数组和指针的区别
- C语言 复杂指针的申明问题 数组指针 指针数组 函数指针 指针函数
- C++二维指针和指针数组的相关介绍
- c语言的指针数组和数组指针
- 微信开发之ngrok内网穿透工具
- Java开发常见问题
- 剑指Offer----面试题27:二叉搜索树与双向链表
- 解决Xshell显示中文乱码的问题
- WordPress + Avada主题 安装Demo教程
- C数组和指针相关的问题
- 8255 1 方式并行接口设计
- 加密网址方法csdn.net
- 1号店11.11:从应用架构落地点谈高可用高并发高性能
- ubuntu下讲eclipse直接部署至tomcat上
- Bootstrap 栅格系统
- Google 深度学习笔记 卷积神经网络
- android APP开机自动启动
- oracle rac序列无序