数组与指针

首先说明数组,指针 ,指针数组,数组指针的定义

数组:一但定义后,编译器会为它分配一段连续的存储单元,数目开始时就会直接或间接的被固定,看起来

          虽然比较整洁,但写法比较死板,同样也比较浪费空间。
指针:指针存放的是一个地址值,指向某个单元,可以通过该指针来索引此单元,在编程和思路构建过程中
          有很大的灵活性。

指针数组:即数组元素全部为指针的数组,数组中的每个元素都是指针,本质为数组

数组指针:即指向数组首元素地址的指针,本质为指针

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值