指针数组和数组指针

1.指针数组

(1)定义

  •  指针数组,就是说首先是一个数组,而数组的元素是指针
  •  指针数组中的元素都必须具有相同的存储类型、指向相同数据类型的指针变量。
  • 指针数组比较适合用来指向若干个字符串,使字符串处理更加方便、灵活。
  •  一维指针数组的定义形式为:“类型名 *数组标识符[数组长度]”。

       例如:int *ptr[N];      //一个指向整数的指针数组,数组由N个int类型指针组成。


#include <stdio.h>
 
const int MAX = 3;
 
int main ()
{
   int  var[] = {10, 100, 200};
   int i, *ptr[MAX];
 
   for ( i = 0; i < MAX; i++)
   {
      ptr[i] = &var[i]; //var[i]为第i个元素值;&var[i]为第i个元素的地址,将地址给指针数组
   }
   for ( i = 0; i < MAX; i++)
   {
      printf("Value of var[%d] = %d\n", i, *ptr[i] );//ptr[i]为第i个元素地址,*用于取值
   }
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

Value of var[0] = 10

Value of var[1] = 100

Value of var[2] = 200

(2)用来存储字符串

#include <stdio.h>

int main ()
{
   const char *names[] = {
                   "Zara Ali",
                   "Hina Ali",
                   "Nuha Ali",
                   "Sara Ali",
   };
   int i = 0;
 
   for ( i = 0; i < 4; i++)
   {
      printf("Value of names[%d] = %s\n", i, names[i] );
   }
   return 0;
}
  • 字符串的定义

字符串实际上是使用 null 字符 \0 终止的一维字符数组;char site[7] = {'R', 'U', 'N', 'O', 'O', 'B', '\0'};   可以写成    char site[] = "RUNOOB";

  • 字符串数组和字符指针

字符指针也可以指向一个字符串,可以用字符串常量对字符指针进行初始化。例如: char *str = "www.dotcpp.com" ;此时,字符指针指向一个字符串常量的首地址。

还可以用字符数组来存放字符串,例如: char string[ ] = "Welcome to dotcpp.com";

在这个语句中,string 是数组名,代表字符数组的首地址。因此可以通过数组名 string 来访问字符串。 
字符串指针和字符串数组两种方式都可以访问字符串,但它们有着本质的区别:字符指针 str 是个变量,可以改变 str 使它指向不同的字符串, 但不能改变 str 所指向的字符串常量的值。 而string 是一个数组,可以改变数组中保存的内容。

(3)指针数组与指向指针的指针

如果一个指针指向的是另外一个指针,我们就称它为二级指针,或者指向指针的指针

假设有一个 int 类型的变量 a,p1是指向 a 的指针变量,p2 又是指向 p1 的指针变量,它们的关系如下图所示:

指针变量也是一种变量,也会占用存储空间,也可以使用&获取它的地址。C语言不限制指针的级数,每增加一级指针,在定义指针变量时就得增加一个星号*。p1 是一级指针,指向普通类型的数据,定义时有一个*;p2 是二级指针,指向一级指针 p1,定义时有两个*。

举例:

main()
{
    char *name[]={"Follow me","BASIC","Great Wall","FORTRAN","Computer desighn"};//指针数组
    char **p;    //定义指向指针的指针
    int i;
    for(i=0;i<5;i++)
    {
        p=name+i;         //指针数组的地址 给 指向指针的指针
        printf("%s\n",*p);//读取指向指针的指针 指定的地址上面的值
    }
}

指针数组的元素只能存放地址。

对于什么时候用**p,什么时候用*p:

就是当指针数组里面的元素存放地址的时候,就使用**p;

当指针数组里面的元素是字符串等一些值的时候,就使用*p。

main()
{
    static int a[5]={1,3,5,7,9};
    int *num[5]={&a[0],&a[1],&a[2],&a[3],&a[4]};//指针数组存放数组a内容的地址
    int **p,i;
    p=num;                              //数组a的地址存放在指向指针的指针变量p的地址上
    for(i=0;i<5;i++)
    {
        printf("%d\t",**p);//**p要双重解引用,才能读取最上面的值
        p++;           
    }
}

2.数组指针

    (1)定义

        数组指针是指向数组地址的指针,其本质为指针。

        例如:int (*ptr)[N];      //一个指向数组的指针,数组由N个int类型元素组成。

int main()
{
	
	int a[5] = { 1, 2, 3, 4, 5 };//一维数组
	int (*p)[5];                 //长度为5的数组指针,即数组里有5个元素
	p = &a;                      //把整个数组a的地址赋给p,则p为整个数组a的地址,则*p表示数组a本身 
        //如果是p=a,就是把数组a的第一个元素地址赋给p
 
	//%p输出地址, %d输出十进制
	//\n回车
	//在C中,在几乎所有使用数组的表达式中,数组名是个指针常量,也就是数组第一个元素的地址,它的类型取决于数组元素的类型。
	printf("%p\n", a); //输出数组名,一般用数组的首元素地址来标识一个数组,则输出数组首元素地址
	printf("%p\n", p); //根据上面,p为整个数组a的地址,输出数组a的地址
	printf("%p\n", *p); //*p表示整个数组a本身,一般用数组的首元素地址来标识一个数组
	printf("%p\n", &a[0]); //a[0]的地址
	printf("%p\n", &a[1]); //a[1]的地址
	printf("%p\n", p[0]); //数组首元素的地址
	printf("%d\n", **p); //*p为数组a本身,即为数组a首元素地址,则*(*p)为值,当*p为数组首元素地址时,**p表示首元素的值1
	printf("%d\n", *p[0]); //根据优先级,p[0] 表示首元素地址,则*p[0]表示首元素本身,即首元素的值1
	printf("%d\n", *p[1]); //为一个绝对值很大的负数,不表示a[1]...表示什么我还不知道
 	
}

 

结果:

(2)补充:

int arr[5]={1,2,3,4,5};

int (*p1)[5] = &arr;

/*下面是错误的*/

int (*p2)[5] = arr;

不难看出,在上面的示例代码中,&arr 是指整个数组的首地址,而 arr 是指数组首元素的首地址,虽然所表示的意义不同,但二者之间的值却是相同的。那么问题出来了,既然值是相同的,为什么语句“int(*p1)[5]=&arr”是正确的,而语句“int(*p2)[5]=arr”却在有些编译器下运行时会提示错误信息呢(如在 Microsoft Visual Studio 2010 中提示的错误信息为“a value of type"int*"cannot be used to initialize an entity of type"int(*)[5]"”)?

其实原因很简单,在 C 语言中,赋值符号“=”号两边的数据类型必须是相同的,如果不同,则需要显示或隐式类型转换。在这里,p1 和 p2 都是数组指针,指向的是整个数组。p1 这个定义的“=”号两边的数据类型完全一致,而 p2 这个定义的“=”号两边的数据类型就不一致了(左边的类型是指向整个数组的指针,而右边的数据类型是指向单个字符的指针),因此会提示错误信息。

(3)二维数组与数组指针

参考链接:

http://c.biancheng.net/view/2022.html

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值