在我们的C程序中,每一个定义的变量,在内存中都占有一个内存单元,比如int类型占四个字节,char类型占一个字节等等,每个字节都在0~4,294,967,295之间都有一个对应的编号,C语言允许在程序中使用变量的地址,并可以通过地址运算符"&"得到变量的地址。
#include<stdio.h>
int main()
{
int i;
int a[10]={1,2,3,4,5,6,7,8,9,0};
char b[10]={'c','l','a','n','g','u','a','g','e'};
for(i=0;i<10;i++)
{
printf("int Address:0x%x,Value:%d\n",&a[i],a[i]);
}
printf("\n");
for(i=0;i<10;i++)
{
printf("char Address:0x%x,Value :%c\n",&b[i],b[i]);
}
return 0;
}
在32位linux系统下运行参考结果:(注意地址的变化)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
C 指针是一个用数值表示的地址。因此,您可以对指针执行算术运算。可以对指针进行四种算术运算:++、--、+、-。
递增一个指针
我们喜欢在程序中使用指针代替数组,因为变量指针可以递增,而数组不能递增,数组可以看成一个指针常量。下面的程序递增变量指针,以便顺序访问数组中的每一个元素:
#include <stdio.h>
const int MAX = 3;
int main ()
{
int var[] = {10, 100, 200};
int i, *ptr;
/* 指针中的数组地址 */
ptr = var;
for ( i = 0; i < MAX; i++)
{
printf("存储地址:var[%d] = %p\n", i, ptr );
printf("存储值:var[%d] = %d\n", i, *ptr );
/* 指向下一个位置 */
ptr++;
}
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
存储地址:var[0] = e4a298cc
存储值:var[0] = 10
存储地址:var[1] = e4a298d0
存储值:var[1] = 100
存储地址:var[2] = e4a298d4
存储值:var[2] = 200
注意地址的变化
递减一个指针
同样地,对指针进行递减运算,即把值减去其数据类型的字节数,如下所示:
#include <stdio.h>
const int MAX = 3;
int main ()
{
int var[] = {10, 100, 200};
int i, *ptr;
/* 指针中的数组地址 */
ptr = var;
for ( i = 0; i < MAX; i++)
{
printf("存储地址:var[%d] = %p\n", i, ptr );
printf("存储值:var[%d] = %d\n", i, *ptr );
/* 指向下一个位置 */
ptr++;
}
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
存储地址:var[2] = 518a0ae4
存储值:var[2] = 200
存储地址:var[1] = 518a0ae0
存储值:var[1] = 100
存储地址:var[0] = 518a0adc
存储值:var[0] = 10
指针的比较
指针可以用关系运算符进行比较,如 ==、< 和 >。如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则可对 p1 和 p2 进行大小比较。
下面的程序修改了上面的实例,只要变量指针所指向的地址小于或等于数组的最后一个元素的地址 &var[MAX - 1],则把变量指针进行递增:
#include <stdio.h>
const int MAX = 3;
int main ()
{
int var[] = {10, 100, 200};
int i, *ptr;
/* 指针中第一个元素的地址 */
ptr = var;
i = 0;
while ( ptr <= &var[MAX - 1] )
{
printf("存储地址:var[%d] = %p\n", i, ptr );
printf("存储值:var[%d] = %d\n", i, *ptr );
/* 指向上一个位置 */
ptr++; i++;
}
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
存储地址:var[0] = 0x7ffeee2368cc
存储值:var[0] = 10
存储地址:var[1] = 0x7ffeee2368d0
存储值:var[1] = 100
存储地址:var[2] = 0x7ffeee2368d4
存储值:var[2] = 200
C 指针数组
在我们讲解指针数组的概念之前,先让我们来看一个实例,它用到了一个由 3 个整数组成的数组:
#include <stdio.h>
const int MAX = 3;
int main ()
{
int var[] = {10, 100, 200};
int i;
for (i = 0; i < MAX; i++)
{
printf("Value of var[%d] = %d\n", i, var[i] );
}
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
假如想要让数组存储指向 int 或 char 或其他数据类型的指针。下面是一个指向整数的指针数组的声明:
int *ptr[MAX];
在这里,把 ptr 声明为一个数组,由 MAX 个整数指针组成。因此,ptr 中的每个元素,都是一个指向 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]; /* 把数组复制给了指针 */
}
for ( i = 0; i < MAX; i++)
{
printf("Value of var[%d] = %d\n", i, *ptr[i] );//打印变量
printf("Value of var[%d] = %p\n", i, ptr[i] );//打印地址 }
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
Value of var[0] = 10
Value of var[0] = 0x7ffc8ef159c4
Value of var[1] = 100
Value of var[1] = 0x7ffc8ef159c8
Value of var[2] = 200
Value of var[2] = 0x7ffc8ef159cc
C语言数组与指针的区别与联系
前面我们已经知道,通过数组下标可以确定数组元素在数组中的顺序和存储地址。由于每个数组元素 相当于一个变量,因此指针变量可以指向数组中的元素,也就是说可以用指针方式访问数组中的元素。 对一个指向数组元素的指针变量的定义和赋值方法,与指针变量相同。例如:
int a[10]; /*定义 a 为包含 10 个整型数据的数组*/
int *p; /*定义 p 为指向整型变量的指针*/
p=&a[0]; /*把 a[0]元素的地址赋给指针变量 p*/
C 语言规定,数组名代表数组的首地址,也就是第 0 号元素的地址。因此:
1 2 | p=a; /*等价于 p=&a[0]; */ int *p=a; /*等价于 int *p=&a[0]; */ |
对于指向首地址的指针 p,p+i(或a+i)就是数组元素 a[i]的地址,*(p+i)( 或*(a+i) )就是 a[i]的值。
如果指针变量 p 已指向数组中的某一个元素,则 p+1 指向同一数组中的下一个元素。
引入指针变量后,就可以用以下两种方法来访问数组元素:
(1)下标法:即用 a[i]形式访问数组元素,在前面介绍数组时都是采用这种方法。
(2)指针法:即采用*(a+i)或*(p+i)形式,用间接访问的方法来访问数组元素,其中 a 是数组名,p 是 指向数组的指针变量,其初值 p=a。
#include<stdio.h>
int main()
{
int i;
int a[10]={1,2,3,4,5,6,7,8,9,0};
int *p=a; //数组 a 赋值给了指针 P
for(i=0;i<10;i++)
{
printf("P Value:%d a Value :%d\n",*(p++),*(a+i));
}
printf("\n");
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
P Value:1 a Value :1
P Value:2 a Value :2
P Value:3 a Value :3
P Value:4 a Value :4
P Value:5 a Value :5
P Value:6 a Value :6
P Value:7 a Value :7
P Value:8 a Value :8
P Value:9 a Value :9
P Value:0 a Value :0
注意输出的两种方式,指针可以通过++或--并修改自身值的方式移动,然而数组名本身值不可以被更改。