首先说明数组,指针 ,指针数组,数组指针的定义
数组:一但定义后,编译器会为它分配一段连续的存储单元,数目开始时就会直接或间接的被固定,看起来
虽然比较整洁,但写法比较死板,同样也比较浪费空间。指针:指针存放的是一个地址值,指向某个单元,可以通过该指针来索引此单元,在编程和思路构建过程中
有很大的灵活性。
指针数组:即数组元素全部为指针的数组,数组中的每个元素都是指针,本质为数组
数组指针:即指向数组首元素地址的指针,本质为指针
1) int*p1[10] 指针数组
2 ) int (*p2)[10] 数组指针
在这里我们知道“[]”的优先级比“*”高,p1先与[]结合构成一个数组,构成一个数组,再用int*来修饰,所以这个数组中
有十个int类型的指针,叫做指针数组。
对于p2就更好理解了,()的优先级高,int修饰的是数组内容,这种类型叫做数组指针。
3、下面再来讨论a和&a的区别
先看下面的一段代码;
int main()
{
char a[5]={'A','B','C','D'};
char(*P3)[5]=&a;
char(*p4)[5]=a;
return 0;
}
这里&a表示的是整个数组的首地址,a表示首元素的首地址,虽然表示的值相同,但p4左右两边的数据类型不一
样,编译器会给出警告,虽然运行并没有问题,但是要少用。
4、下面来介绍地址的强制转换
struct Test
{
int Num;
char*pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
假设p的值是0x100000,下面的表达式的值分别是多少呢?
p+0x1=0x___?
(unsigned long) p+0x1=0x___?
(unsigned int*)p+0x1=0x___?
p+0x1的值为0x100000+sizeof(Test)*0x1.至于此结构体大小为20比特位,所以p+0x1=0x100000+20=0x100014;
(unsigned long)强制转化p为无符号长整型整数,所以这里就是加上整数0x1了,
所以(unsigned long) p+0x1=0x100000+0x1=0x100001;
(unsigned int*)强制转化p为无符号整型指针,
所以它的值为0x100000+sizeof(unsigned int)*0x1=0x100000+0x4=0x100004.
二维数组和指针数组:
二维数组:如int arr[10][10]只要定义了一个二维数组,无论赋不赋值,系统都会给他分配相应空间,而且
该空间一定是连续的。其每个元素表示一个字符。我们可以通过制定下标对其元素进行修改。
指针数组如int *arr[5] 系统至少会分配5个连续的空间用来存储5个元素,表示arr是一个5个元素的
数组,每个元素是一个指向整型数据的一个指针。
如果我做这样的定义:
char a[3][8]={"gain","much","strong"};
char *n[3]{"gain","much","strong"};
他们在内存的存储方式分别如右图所示,可见,系统给数组a分配了
3×8的空间,而给指针n分配的空间则取决于具体字符串的长度。
此外,系统分配给a的空间是连续的,而给n分配的空间则不一定连续。
由此可见,相比于比二维字符数组,数组有明显的优点:一是指针数组中每个元素所指的字符串不必限制
在相同的字符长度;二是访问指针数组中的一个元素是用指针间接进行的,效率比下标方式要高。 但是二
维字符数组却可以通过下标很方便的修改某一元素的值,而指针数组却无法这么做。
二维数组和数组指针:
例如:{int a[4][5]; int (*p)[5]=a;}这里a是个二维数组的数组名,相当于一个二级指针常量;
p是一个指针变量,它指向包含5个int元素的一维数组,此时p的增量以它所指向的一维数组长度为单位;
*p+i是二维数组a[0][ i ] 的地址;
*(p+2)+3表示a[2][3]地址(第一行为0行,第一列为0列),*(*(p+2)+3)表示a[2][3]的值。
指针和数组的联系:
"char *p="abcdef";
*(p+2)----->c//通过指针形式访问c
p[2]-------->c//通过数组形式访问c
int arr[10]={1,2,3,4,5,6};
*(arr+6)=7;通过指针形式将第七个元素赋值为7
arr[6]=7;通过指针形式将第七个元素赋值为7
定义成指针,声明成数组------->可以用*(char**) 或(char*)*(int*)方式实现
用以下方式进行进一步说明:
int a=10;
int *arr[10];//指针数组----存放指针的数组
int (*ptr)[10];//数组指针----指向数组的指针
int *p=&a;//一级指针
int **q=&p;//二级指针
int (*ptr)[10]=&arr;//将指针数组首元素的地址赋值给数组指针
int *(*ptr)[10]=*arr;//将指针数组的值赋值给数组指针的解引用
求内存和长度的差异
整形数组:
int a[] = { 1, 2, 3, 4 };
printf( "%p\n",a); //a代表首元素地址
printf( "%p\n",a+1); //a+1表示第二个元素的地址
printf( "%p\n",&a); //&a代表整个数组的首地址
printf( "%p\n",&a+1); //&a代表数组的地址,&a+1则跳过整个数组
printf( "%d\n", sizeof (a)); //a在sizeof()中代表整个数组, 16
printf( "%d\n", sizeof (a + 0)); //代表&a[0],32位下所有的地址大小都为4 4
printf( "%d\n", sizeof (*a)); //表示a[0],int占4个字节 4
printf( "%d\n", sizeof (a + 1)); //表示&a[1],32位下所有的地址大小都为4 4
printf( "%d\n", sizeof (a[1])); //表示a[1],int占4个字节 4
printf( "%d\n", sizeof (&a)); //代表整个数组的地址,32位下所有的地址大小都为4 4
printf( "%d\n", sizeof (&a + 1)); //因为&a代表整个数组地址,&a+1跳过整个数组,但还是一个地址
printf( "%d\n", sizeof (&a[0])); //表示a[0]的地址 4
printf( "%d\n", sizeof (&a[0] + 1)); //表示a[1]的地址 4
printf( "%d\n", sizeof (*&a)); //&a代表整个数组,再*引用访问这块地址,就相当于求取真个数组的大小 16
字符数组:
char name[] = "abcdef" ; //这时字符串不代表首元素地址,而是字符数组的一种初始化方式,并且字符串总是默认以’\0‘结尾
printf( "%d\n", sizeof (name[0])); //表示a,32位下char大小为1 1
printf( "%d\n", sizeof (&name)); //表示整个数组的地址,32位下地址就是4 4
printf( "%d\n", sizeof (*name)); //表示 a 1
printf( "%d\n", sizeof (&name+1)); //表示指向整个数组之后的一块空间,但还是一个地址 4
printf( "%d\n", sizeof (name+1)); //表示b的地址 4
printf( "%d\n", sizeof (name)); //代表整个数组,还要加上‘\0' 7
printf( "%d\n", strlen(name)); //求取字符串长度,不包括’\0‘ 6
printf( "%d\n", strlen(&name)); //代表整个数组的地址,&name==name,strlen遇到’\0‘停下 6 printf( "%d\n", strlen(&name + 1)); //是一个随机值,表示指向整个数组之后的一个地址,从这个地址开始向后寻找'\0',因为’\0‘位置不确定所以是随机值
printf( "%d\n", strlen(name + 1)); //表示b的地址
字符指针:
char *name = "abcdef" ; //字符串放在等号右边代表首元素地址
printf( "%d\n", sizeof (name[0])); //以下标形式访问,代表 a 1
printf( "%d\n", sizeof (&name)); //表示字符指针name的地址 4
printf( "%d\n", sizeof (*name)); //通过*访问,表示a 1
printf( "%d\n", sizeof (&name+1)); //表示指针name之后的一块地址 4
printf( "%d\n", sizeof (name+1)); //表示b的地址 4
printf( "%d\n", sizeof (name)); //代表a的地址, 4
printf( "%d\n", strlen(name)); //代表字符串首元素地址 6
printf( "%d\n", strlen(&name)); //表示指针name本身地址,因为从name开始向后’\0‘的位置不确 定,所以是个随机值
printf( "%d\n", strlen(&name + 1)); //表示指针name本身地址之后的地址,因为’\0‘的位置不确定,所以 是个随机值
printf( "%d\n", strlen(name + 1)); //代表b的地址 5