指针是C语言中一个重要的概念,也是C语言的一个重要特色。 正确而灵活地运用它,可以有效地表示复杂的数据结构; 能动态分配内存;能方便地使用字符串;有效而方便地使用数组。 掌握指针的应用,可以使程序简介,紧凑,高效。可以说,不掌握指针就是没有掌握C语言的精华。
什么是指针,数据在内存中如何存储,又是如何读取的
地址和内存的概念
内存区的每一个字节有一个编号,这就是“地址”。如果在程序中定义了一个变量,在对程序进行编译时,系统就会给这个变量分配内存单元。
直接访问和间接访问
打开一个A抽屉,有两种办法: 一种方法是 : 将A钥匙放在身上,需要时找到钥匙打开抽屉,取出东西 另一种方法: 将A钥匙放在抽屉B中锁起来。想要打开A钥匙则需要找到B钥匙打开B抽屉,拿出A钥匙,打开A抽屉。
直接访问: a = 5; 系统在编译的时候,已经对变量分配了地址,例如,若变量的地址为2000, 则该语句的作用就是把常数 5 保存到地址为 2000 的单元。 间接访问如: scanf(“%d”,&a); 调用函数时,把变量a的地址传递给函数scanf,函数首先把该地址保存到一个单元中,然后把从键盘的数据通过所存储的地址保存到a变量中。
初始指针
在C语言中,指针是一种特殊的变量,他是存放地址的。假设我们定义了一个变量 int *i_pointer用来存放整型变量 i 的地址。可以通过语句: i_pointer = &i ;
将 i 的地址(2000)存放到 i_pointer中,这时 i_pointer的值就是(2000),即变量 i 所占用单元的起始地址。 要存取变量 i 的值,可以采用间接方式:先找到存放 “i 的地址”的变量 i_pointer,从中取出 i 的地址(2000),然后取出 i 的值3。
*:取值操作符 &:取地址操作符
如:
int i = 2000;
int *pointer;
pointer = &I;
printf(“%d\n”,*pointer);
知道了一个变量的地址,就可以通过这个地址来访问这个变量,因此,又把这个变量的地址称为该变量的“指针”。 C语言中可以定义一类特殊的变量,这些变量专门用来存放变量的地址,称为指针变量。 注意: 指针变量的值(即指针变量中存放的值是地址(指针),请区分“指针”和“指针变量”这两个概念。
下面都是合法的定义: float *point_3 ; //point_3 是指向float型变量的指针变量 char *point_4 ; // point_4 是指向字符型变量的指针变量 可以用赋值语句使一个指针变量得到另一个变量的地址,从而使它指向一个该变量。
1.指针变量前面的 “ * ”,表示该变量的类型为指针型变量,一般表示为: 类型说明符 * 变量名 ; 其中, * 表示这是一个指针变量,变量名即为定义的指针变量名,类型说明符表示本指针变量所指向的变量的数据类型。 例如: float *point_1; 指针变量名 是 point_1 ,而不是 *point_1 ;
2.在定义指针变量时必须指定基类型。 特别需要注意的是,只有整型变量的地址才能放到指向整型变量的指针变量中,下面的赋值是错位的: float a; int *point_1; point_1 = &a ; 将 float 型变量的地址放到指向整型变量的指针变量中,错误。
请牢记,指针变量中只能存放地址(指针),不要将一个整数赋给一个指针变量,否则编译器也会把该值当成一个地址来处理。 C语言中提供了地址运算符 & 来表示变量的地址,一般形式为: & 变量名; 如 & a 表示变量a的地址,&b 表示变量b的地址。当然,变量本身必须预先声明
Void main()
{
int a,b;
int *point_1, *point_2 ;
a = 100; b = 10;
point_1 = & a;
point_2 = & b;
printf(“%d,%d\n”,a,b);
printf(“%d,%d\n”,*point_1,*point_2);
}
如果有: point_2 = & * point_1 ; 它的作用是将 &a(a的地址赋)赋给 point_2,如果 point_2 原来指向 b,经过重新赋值后它不再指向 b 了,而指向了a ;
. * & a 的含义是什么? 先进行 &a运算,得 a的地址,再进行 * 运算。即 &a 所指向的变量,也就是变量a. * & a 和 * point_1 的作用是一样的,它们都等价于变量 a,即 * & a 与 a 等价。
Void main()
{
int *p1,*p2, *p ,a,b;
scanf(“%d %d”,&a,&b);
p1 = &a;
p2 = &b;
if(a < b)
{
p = p1; p1 = p2; p2 = p; //此后, p1 指向 b,p2 指向 a
} printf(“a = %d,b = %d \n”,a,b);
printf(“max = %d, min = %d\n”,*p1, * p2);
}
题目: 输入 a,b,c 三个整数,按大小 顺序输出,几次比较 ?
Void main()
{
void exchange(int *q1,int *q2,int *q3);
int a,b,c,*p1,*p2,*p3;
scanf(“%d,%d,%d”,&a,&b,&c);
p1 = &a;p2 =&b;p3=&c;
exchange(p1,p2,p3);
printf(“%d %d %d \n”,a,b,c);
}
Void exchange(int *p1,int*p2,int *p3)
{
void swap(int *p1,int *p2);
if(*p1 < *p2)
{ swap(p1,p2); }
if(*p1< *p3)
{ swap(p1,p3); }
if(*p2<*p3)
{ swap(p2,p3); }
}
一个变量有地址,一个数组包含若干个元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。 指针变量既然可以指向变量,当然也可以指向数组元素(把某一元素的地址放到一个指针变量中) 所谓数组元素的指针就是数组元素的地址。
定义一个指向数组元素的指针变量的方法,与之前介绍的指向变量的指针变量相同。 例如: int a[10]; (定义a 为包含 10 个整型数据的数组) Int *p; ( 定义p为指向整型变量的指针变量) 应当注意, 如果数组为 int 型,则指针变量的基类型亦应为 int 型
P = & a[0]; 把 a[0]元素的地址赋给指针变量 p。 也就是使 p 指向 a 数组的第0 号元素
引用一个数组元素,可以用: 1.下标法, 如 a[i] 形式; 2.指针法, 如 *(a+i) 或 *(p+i)。 其中的 a是数组名, p是指向数组元素的指针变量,其初值 p = a; 注意: 数组名 即翻译成数组的第一个元素的地址。
输出数组中的全部元素,三种方法: 1.下标法,a[1],a[2],a[3]….. 2.通过数组名计算数组元素地址,找到元素的值 3.用指针变量指向数组元素
输出数组中的全部元素,第一种:下标法
Void main()
{
int a[10];
int I;
for(i=0;i<10;i++)
{ scanf(“%d”,&a[i]) ; }
printf(“\n”);
for(i=0;i<10;i++)
{ printf(“%d “,a[i]) }
}
输出数组中的全部元素,第二种: 数组名
Void main()
{
int a[10];
int I;
for(i=0;i<10;i++)
{ scanf(“%d”,&a[i]) ; }
printf(“\n”);
for(i=0;i<10;i++)
{ printf(“%d \n“, *(a+i) ) }
}
输出数组中的全部元素,第三种: 指针变量
Void main()
{
int a[10], i ;
int *p;
for(i=0;i<10;i++)
{ scanf(“%d”,&a[i]) ; }
printf(“\n”);
for(p=a; p < (a+10) ; p++)
{ printf(“%d ”, *p ); }
}
用数组名作函数参数
f (int arr[] , int n) 但在编译时是将 arr 按指针变量处理的,相当于将函数 f 的首部写成 f (int *arr, int n) 以上两种写法等价。 C语言调用函数时虚实结合的方法都是采用 “值传递”方式,当用变量名作为函数参数时传递的都是变量的值 , 当用数组名作为函数参数时, 由于数组名代表的是数组首元素地址, 因此传递的值是 地址,所以要求形参为指针变量。
题: 将数组 a 中 n 个整数按相反顺序存放。(数组名版本)
Void reverse(int x[],int n);
Void main()
{
int I,a[10]= {0,5,9,8,5,4,7,4,6,5,1};
printf(“the original arry: \n”);
for(i=0;i<10;i++)
{ printf(“%d ”,a[i]); }
printf(“\n”);
reverse(a,10);
printf(“the array has been inverted :\n ”);
for(i=0;i<10;i++)
{ printf (“%d ”,a[i]) ; }
}
Void reverse(int x[].int n)
{
int temp , i,jm;
m = (n- 1) / 2 ;
for(i = 0 ;i<= m ;i++)
{
j = n-1-i; //j 指向 对应的元素
temp = x[i];
x[i] = x[j];
x[j] = temp;
}
}
题: 将数组 a 中 n 个整数按相反顺序存放。(指针版本)
Void reverse(int *x,int n);
Void main()
{
int I,a[10]= {0,5,9,8,5,4,7,4,6,5};
printf(“the original arry: \n”);
for(i=0;i<10;i++)
{ printf(“%d ”,a[i]); }
printf(“\n”);
reverse(a,10);
printf(“the array has been inverted :\n ”);
for(i=0;i<10;i++)
{ printf (“%d ”,a[i]) ; }
Void reverse(int *x,int n)
{
int *p,temp, *i,*j,m;
m = (n-1)/2;
i= x; j = x+n -1; p = x + m;
for(i=x;i<= p ;i++, j--)
{
temp = * i;
*i=*j;
*j=temp;
}
}