数组与指针
一、变量
变量:是一个标识符(identifier),用来指代一块内存区域,使用变量使我们操作内存以区域(area),以块(block)为单位,提高了方便性。变量是内存区域的别名,机器代码中,是不会出现变量名的;变量名是给我们程序员操作内存来使用的,机器码中将变量名替换成了相应的内存地址。
当我们定义int a时,编译器负责为程序预留4字节空间,并把我们的变量名“a”保存进符号表,并用这个符号表的索引对应实际的空间。如果下面出现b = a;那么它就会根据符号表找到变量的真正的物理位置,取得它的值,赋给b。变量名虽然不直接表示地址,但可用取地址符号&来获得它所代表的变量的存放地址。因为在定义变量的同时会分配给它相应的空间。 使用变量来对数据的访问是直接访问。
二、数组
int array[5] = {1,2,3,4,5};
a为数组名,表示数组的首地址,在计算数组中元素的值就是通过这个首地址+数据类型*偏移值而得到的。a=&a[0],因此,a是常量,不能进行a++。
printf("%d\t",*(array+1));
int *parray=(int *)(&array+1);
printf("%d\n",*(parray-1));
在array+1过程中,偏移后的地址为array+sizeof(array)*1;而parray=(int )(&array+1),偏移后的地址为array+sizeof(*&array)*1。
array与&array的值是一样的,都是该数组的首地址,但他们的含义是不一。
array表示该数组的首地址,及首元素的地址;而&array指向整个数组的内存块,每次+1时,array偏移一个类型大小,而&array偏移整个数组的内存块大小,。
三、指针
int a=5;
int *p = &a;
指针变量存储的是变量的地址,通过指针变量是对数据的间接访问。
main.c
extern char str[];
int main(void)
{
printf("%s\n",str);
return 0;
}
test.c
int *str="guidao\n";
extern char str[]欺骗了编译器,将指针类型的str当成了数组类型来进行解析,输出的是一个错误的字符串,那这个错误的字符串是怎么得到的。由于欺骗了编译器,将str当成了数组,但是str是一个指针,保存了”guidao\n”这个字符串在常量区的首地址,假如地址为0x01880000,使用printf(“%s\n”,str)时,由于编译器将str当成了数组,直接将地址0x01880000解析输出出来,因此我们看到了错误的值,如果想正确输出,则可以强制转化,改为:
printf("%s\n",(char *)(*(unsigned int *)str));
数组是直接访问,而指针是间接访问。
int array[5] = {1,2,3,4,5};
array[3]读取数值时,通过array + 3*sizeof(*array)来得到地址,从而得到值,而使用:int *parray = array +3;可以直接得到偏移量,使用指针速度会更快。
int array[5] = {1,2,3,4,5};
int *parray = array +3;
array[3]=10;
*paray = 10;
汇编代码
array[3] = 10;
00DB1411 mov eax,4
00DB1416 imul ecx,eax,3
00DB1419 mov dword ptr array[ecx],0Ah
*parray = 10;
00DB1421 mov eax,dword ptr [parray]
00DB1424 mov dword ptr [eax],0Ah
使用指针汇编代码更优化。
char str1[5]={'a','b','c','d','f'};
char *str2="guidao\n";
str1可读不可写,*str1可读可写,相当于char *const str1;
str2可读可写,*str2可读不可写,相当于const char *str2