(1)指针数组是一个数组,里面包含若干指针,指针数组名是指向指针的地址,可赋值给指向指针的指针。
如 char* a[]={"hello" ,"world","nihao"}; char**p=a;
(2)数组指针是一个指针,指向整个数组。
如 int v[2][3]={{1,2,3},{4,5,6}} ;
int b[3]={7,8,9};
int (*p1)[3]=v; p1==v-->v[0]-->v[0][0]==1;
int (*p2)[3]=&b; p2==&b-->b-->b[0]==7;
(3)数组名的两层含义:既是数组符号名(犹如 “int a=3;"中a是一个4字节内存的符号名一样),又是指向该数组中第一个元素的地址。比如 int a[3]={1,2,3}; 在*a中,a表示a[0]的地址;而在sizeof(a)中,a表示整个数组的符号名,代表着12字节的空间。
(4)在计算机中,访问内存中的任意单元内容皆是通过地址的!在汇编语言中,访问内存中的任何单元都是直接用地址(通常借助%ebp,%esp等指针)的,而在c语言中,为了方便引入了符号名,一个符号代表着一块区域,但要注意符号名本身是不占内存空间的,只是在c语言的层次供程序员使用。比如int a=3;告诉编译器为我分配了4字节,以后我使用这块空间时用a就行了,而事实上,经编译编译成汇编代码后,汇编里对该块区域的访问皆是通过地址访问的,汇编语言代码中没有相应的符号a。又如,int a[3]={1,2,3}; 对应着12字节的空间,和4个符号(a[0],a[1],a[2],a),但这4个符号都是不占用内存空间的,汇编代码里也没有这4个符号。
如:
#include<stdio.h>
int main()
{
int a[3]={1,2,3};
int b=a[0]+a[1]+a[2];
return b;
}
汇编代码如下:
.file "test_a.c"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $16, %esp ;分配16字节
movl $1, -16(%ebp) ;对应着a[0]
movl $2, -12(%ebp) ;对应着a[1]
movl $3, -8(%ebp) ;对应着a[2]
movl -16(%ebp), %edx
movl -12(%ebp), %eax
addl %eax, %edx
movl -8(%ebp), %eax
leal (%edx,%eax), %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax ;对应着b
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
(5) int v[2][3]={{1,2,3},{4,5,6}} ;
对应着24字节的空间和访问该24空间的10(=6+3+1)个符号名。它们分别是:
6个整型变量名: v[0][0]; v[0][1]; v[0][2]; v[1][0]; v[1][1]; v[1][2];
3个一维数组名: v[0],v[1],v[2]
1个数组地址名: v
在c语言中,当我们定义了int v[2][3]后,我们就可以在后面的代码中使用这个10个符号以不同的方式访问这块内存空间。
(6)抓住根本:分配的实际空间+访问接口(符号名或地址)