一、指针与数组
指针是编程语言中的一个对象,利用地址,它的值直接指向存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。总的来说指针就是变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)
int main()
{
int a = 10; //在内存中开辟一块空间
int *p = &a; //这里我们对变量a,取出它的地址,可以使用&操作符
//将a的地址存放在p变量中,p就是一个指针变量
printf("%p\n",&a);
printf("%p\n",p); //打印变量a的地址
return 0;
}
数组名的值是一个指针常量,也就是数组首元素的地址。
以下两种情况中,数组名不表示首元素地址:
1、sizeof(数组名),计算整个数组的长度,单位是字节,数组名表示整个数组。
2、&数组名,所产生的是一个指向数组的指针,取出的是整个数组的地址。数组名表示整个数组。
由于数组名的值是一个指针常量,可以采用间接访问操作符 '*' 访问指针指向的内容,*arr即可访问数组首元素。
arr == &arr[0];
*arr == arr[0];
下面这条赋值语句,将arr的值,即首元素地址赋给指针变量p。
int *p = arr;
p所指向的是数组的首元素,p和arr都可以进行间接访问和下标引用操作,下列四种访问方法等价:
*(p+i) == *(arr+i) == p[i] == arr[i]
下面程序依次打印数组各个元素,其中四条打印语句表达的意思相同。
int main()
{
int arr[5] = { 1,2,3,4,5};
int *p = arr;
int i;
for (i = 0; i < 5; i++)
{
printf("%d\n", *(p+i));
printf("%d\n", *(arr+i));
printf("%d\n", p[i]);
printf("%d\n", arr[i]);
}
return 0;
}
但是!!!
请不要根据这个事实得出“数组和指针是相同的”结论!!!
现考虑以下声明:
int arr[5];
int *p ;
声明一个数组时,编译器会根据声明所指定的元素数量为数组保留内存空间,然后再创建数组名,它的值是一个常量,指向这段空间的起始位置。声明一个指针变量时,编译器只为指针本身保留内存空间,它并不为任何整型值分配内存空间。此外,指针变量未被初始化为指向任何现有的内存空间,如果它是一个自动变量,它甚至根本不会被初始化。把这两个声明用图的方法来表示,可以发现他们的显著不同。
因此,上述声明之后,表达式*arr是完全合法的,但表达式*b是非法的,*b将访问内存中某个不确定的位置,或者导致程序终止。另外,表达式b++可以通过编译,但arr++不行,因为arr的值是个指针常量,常量的值是不能被修改的。(--------指针常量所指向的是内存中数组的起始位置,如果修改这个指针常量,唯一可行的操作就是把整个数组移动到内存的其他位置。但是,在程序完成链接之后,内存中数组的位置是固定的,因此,数组名的值是一个指针常量。)
二、指针数组
指针数组是数组,是存放指针的数组。
以下声明表示:arr是一个数组,有五个元素,每个元素是一个整形指针。
int* arr[5]; //指针数组
下面这个程序依次打印三个整型数组的值。
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 2,3,4,5,6 };
int arr3[] = { 3,4,5,6,7 };
Int *parr[] = { arr1,arr2,arr3 };
int i = 0;
for ( i = 0; i < 3 ; i++)
{
int j = 0;
for ( j = 0; j < 5; j++)
{
printf("%d", *(parr[i] + j));
}
printf("\n");
}
return 0;
}
注意:指针数组以一个NULL指针结束
三、数组指针
数组指针是指针,是指向数组的指针。
以下声明表示,p是一个指针,它指向的数组有五个元素,每个元素的类型是整型。
int (*p)[5]; //数组指针
同理,以下声明表示,p是一个指针,它指向的数组有十个元素,每个元素的类型是字符指针。
char* (*p)[10];
(注意:指针数组和数组指针的声明相差只相差一个 () ,由于 [ ] 的优先级要高于 * ,arr先和 [ ] 结合,说明arr是一个数组;但加上 () 后,保证 * 与 p 先结合,则说明 p 是指针。)
数组指针的声明和初始化一般如下:
int arr[10] = { 0 };
int (*p)[10] = &arr;
数组指针是个指向数组的指针,因此也可以进行间接访问和下标引用操作。
*p 就是arr
(*p)[i] == arr[i] == *(*p+i) == *(arr+i)
下面程序任然是依次打印数组各个元素
int main()
{
int arr[5] = {1,2,3,4,5};
int (*p)[5] = &arr;
int i = 0;
for ( i = 0; i < 5; i++)
{
printf("%d\n", (*p)[i]);
printf("%d\n", arr[i]);
printf("%d\n", *(*p+i));
printf("%d\n", *(arr+i));
}
return 0;
}
对比以前的程序,这个程序明显更加复杂。
一般数组指针用在多维数组更方便。
下面程序是一个打印二维数组各个元素的程序,依旧采用四种等价写法:
void print(int (*p)[5], int x, int y) //需要用数组指针接收
{
int i = 0, j = 0;
for ( i = 0; i < x; i++)
{
for ( j = 0; j < y; j++)
{
printf("%d ",p[i][j]);
printf("%d ",*(p[i]+j));
printf("%d ",(*(p+i)[j]);
printf("%d ", *(*(p+i) + j));
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
print(arr, 3, 5); //arr的值是首元素地址, 二维数组中 ,首元素地址为第一行地址
return 0;
}