最近在动手写一个RMI类似的库,刚刚开始,在实现一个类的时候,注意到了以前被忽略的问题。
指针和数组,绝对不是一回事。
程序的原型是这样的:
bool copy(uint8_t** data , uint32_t len);
后来我使用的时候,定义了一个uint8_t的数组,想通过&<数组名>的方式传递一个指针的指针,可耻的失败了。
调试一番后,果断发现传进去的值,居然不是我想的指针的指针,而是数组的首地址。然后把数组换成了指针,获得了期望的结果。
测试程序如下:
#include <stdio.h>
#include <stdint.h>
int main( int argc , char** argv)
{
int data[4] = {0};
char* str = "mm test";
printf("data is %d\n" , data);
printf("data addr is %d\n" , &data);
printf("str is %d\n" , str);
printf("str addr is %d\n" , &str);
return 0;
}
结果是:
从程序打印的结果就可以看出指针和数组完全是两个不同的东东。
为什么会有这样的差异,在google了一番之后,找到了满意的答案。
http://www.cnblogs.com/csyisong/archive/2010/03/18/1688877.html
以下内容为转载:
1 指针和数组的区别
指针和数组的分配
数组是开辟一块连续的内存空间,数组本身的标识符(也就是通常所说的数组名)代表整个数组,可以使用sizeof来获得数组所占据内存空间的大小(注意, 不是数组元素的个数,而是数组占据内存空间的大小,这是以字节为单位的)
。
2 空间的分配
这里又分为两种情况:
第一,如果是全局的和静态的
char *p = “hello”;
这是定义了一个指针,指向rodata section里面的“hello”,可以被编译器放到字符串池。在汇编里面的关键字为.ltorg。意思就是在字符串池里的字符串是可以共享的,这也是 编译器优化的一个措施。
char a[] = “hello”;
这是定义了一个数组,分配在可写数据块,不会被放到字符串池。
char *p = “hello”;
这是定义了一个指针,指向rodata section里面的“hello”,可以被编译器放到字符串池。在汇编里面的关键字为.ltorg。意思就是在字符串池里的字符串是可以共享的,这也是 编译器优化的一个措施。
char a[] = “hello”;
这是定义了一个数组,分配在可写数据块,不会被放到字符串池。
第二,如果是局部的
char *p = “hello”;
这是定义了一个指针,指向rodata section里面的“hello”,可以被编译器放到字符串池。在汇编里面的关键字为.ltorg。意思就是在字符串池里的字符串是可以共享的,这也是 编译器优化的一个措施。另外,在函数中可以返回它的地址,也就是说,指针是局部变量,但是它指向的内容是全局的。
char a[] = “hello”;
这是定义了一个数组,分配在堆栈上,初始化由编译器进行。(短的时候直接用指令填充,长的时候就从全局字符串表拷贝),不会被放到字符串池(同样如前,可 能会从字符串池中拷贝过来)。注意不应该返回它的地址
继续在网上看,后面看到了一个程序,可以更深刻地认识到数组和指针的区别。
以下程序的打印值是什么?
int c[5] = {1,2,3,4,5};
int *ptr = (int *)(&c +1);
printf("%d %d\n", *(c +1), *(ptr-1));
如果答案是2,1,那就错了 , 答案是2,5。为什么?关键就是(&c+1)。
上面已经说到,数组本身的标识符代表整个数组。并且数组和指针的分配根本不是一样的。可以这么理解,数组定义的时候,数组名代表一整块区域,因为没有任何指针指向数组所在的内存区域,所以&<数组名>只能返回数组的首地址。而在定义指针的时候,指针本身是占据一块4字节的内存的,这块内存的地址,就是指针的指针。
(&c+1)实际得到的是(&c+sizeof(c))。看到这里是不是想起了什么?假设我们有个int*的指针ptr , ptr+1不就是指向下一个int的指针吗?原来对于数组我们应该把它当做类型,这才是正确的。是的,它和指针不是一回事,它其实应该是像int char short这样的类型。