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