地址和指针的概念:
内存区的每一个字节有一个编号,这就是地址。如果在程序中定义了一个变量,在对程序进行编译时,系统就会给这个变量分配内存单元。
在C语言中,对变量的访问有两种方式,直接访问和间接访问。
直接访问如:a=5;
系统在编译时,已经对变量分配了地址,例如,若变量a分配的地址是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为指针变量的一个特征
pointer=&i;
printf("%d\n",*pointer);//这里的*才是取值操作
打印出的结果应该是2000。
指针与指针变量:
知道了一个变量的地址,就可以通过这个地址来访问这个变量,因此又把变量的地址称为该变量的指针。
C语言中可以定义一些特殊的变量,这些变量专门用来存放变量的地址,称为指针变量。
指针变量中存放的值是指针(即地址)。
定义指针变量:
指针前面的“*”,表示该变量的类型为指针型变量。其一般形式为: 类型说明符 *变量名;
在定义指针变量时必须指定基类型。需要注意的是,只有整型变量的地址才能放到指向整型变量的指针变量中。
指针变量中只能存放地址,不要将一个整数或任何其他非地址类型的数据赋给一个指针变量,否则编译器也会把该值当成一个地址来处理。
C语言中提供了地址运算符&来表示变量的地址。其一般形式为:&变量名;变量本身必须预先声明。
例题:通过指针变量访问整形变量:
#include<stdio.h>
int main()
{
int a,b;
int *pointer_1,*pointer_2;
a=100;
b=10;
pointer_1=&a;
pointer_2=&b;
printf("%d,%d\n",a,b);
printf("%d,%d\n",*pointer_1,*pointer_2);
}
对“&”和“*”再做些说明:
如果已经执行了语句 pointer_1=&a;
1、&*pointer_1的含义是什么?
“&”和“*”两个运算符的优先级相同,但按自右向左方向结合,因此先进行*pointer_1的运算,它就是变量a,再执行&运算。因此,&*pointer_1与&a相同,即变量a的地址。
2、如果有pointer_2=&*pointer_1;
它的作用是将&a(a的地址)赋给pointer_2,pointer_2就指向了a。
*&a的含义是什么?
先进行&a运算,得a的地址,再进行*运算。即&a所指向的变量,也就是变量a。
*&a和*pointer_1的作用是一样的,它们都等价于变量a。即*&a与a等价。
(*pointer_1)++相当于a++。
注意括号是必要的,如果没有括号,++和*为同一优先级,结合方式自右向左,就变成了*(poiinter_1++)。
例题:输入a和b两个整数,按从大到小的顺序输出a和b。
代码有些多此一举,不过是要明白指针的基本用法。
#include<stdio.h>
int 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;
}
printf("a=%d,b=%d\n",a,b);
printf("max=%d,min=%d\n",*p1,*p2);
}
下面这个代码依旧是上面的题,但是是将指针变量作为函数的参数实现:
#include<stdio.h>
void swap(int *p1,int *p2);
int main()
{
int a,b;
int *pointer_1,*pointer_2;
scanf("%d%d",&a,&b);
pointer_1=&a;
pointer_2=&b;
if(a<b)
{
swap(pointer_1,pointer_2);//swap实现的是交换
}
printf("\n%d > %d\n",a,b);
}
void swap(int *p1,int *p2)
{
int temp;
temp=*p1;
*p1=*p2;
*p2=temp;
}
例题:输入a,b,c,三个数,将它们从大到小输出。
#include<stdio.h>
int 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("\n%d>%d>%d\n",a,b,c);
}
void exchange(int *q1,int *q2,int *q3)
{
void swap(int *pt1,int *pt2);
if(*q1<*q2)
{
swap(q1,q2);
}
if(*q1<*q3)
{
swap(q1,q3);
}
if(*q2<*q3)
{
swap(q2,q3);
}
}
void swap(int *pt1,int *pt2)
{
int temp;
temp=*pt1;
*pt1=*pt2;
*pt2=temp;
}
一个变量有地址,一个数组包含若干个元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。指针变量不仅可以指向变量,也可以指向数组元素(把某一元素的地址放到一个指针变量中)。所谓数组元素的指针就是数组元素的地址。
例题:假设有一个a数组,整型,有10个元素。要输出各元素的值有三种方法:
1、下标法;
2、通过数组名计算数组元素地址,找出元素的值;
3、用指针变量指向数组元素。
第一种:
#include<stdio.h>
int 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]);
}
}
第二种:
#include<stdio.h>
int 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));//这里a是首地址,i表示偏移,*表示取值
}
}
第三种:
#include<stdio.h>
int main()
{
int a[10];
int 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)相当于f(int *arr,int n)
需要说明的是:C语言调用函数时虚实结合的方法都是采用“值传递”的方式,当变量名作为函数参数时传递的是变量的值,当用数组名作为函数参数时,由于数组名代表的是数组首元素地址,因此传递的值是地址,所以要求形参为指针变量。例题:将数组a中n个整数按相反顺序存放。如图所示:
第一个版本,用数组名做参数:
#include<stdio.h>
void reverse(int x[],int n);
int main()
{
int i,a[10]={3,7,9,11,0,6,7,5,4,2};
printf("The original array:\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]);
}
printf("\n");
}
void reverse(int x[],int n)
{
int temp,i,j,m;
m=(n-1)/2;
for(i=0;i<=m;i++)
{
j=n-1-i;
temp=x[i];
x[i]=x[j];
x[j]=temp;
}
}
第二个版本,用指针做函数参数:
#include<stdio.h>
void reverse(int *x,int n);
int main()
{
int i,a[10]={3,7,9,11,0,6,7,5,4,2};
printf("The original array:\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]);
}
printf("\n");
}
void reverse(int *x,int n)
{
int *p,temp,*i,*j,m;
m=(n-1)/2;
i=x; //i指向的是数组的第一个元素
j=x+n-1; //j指向的是数组的最后一个元素
p=x+m; //p指向中间,配对
for( ;i<=p;i++,j--)
{
temp=*i;
*i=*j;
*j=temp;
}
}
例题:从10个数中找出其中的最大值和最小值。
#include<stdio.h>
int max,min;
void max_min_value(int array[],int n);
int main()
{
int i,number[10];
printf("enter 10 integer numbers:\n");
for(i=0;i<10;i++)
{
scanf("%d",&number[i]);
}
max_min_value(number,10);
printf("\nmax=%d,min=%d\n",max,min);
}
void max_min_value(int array[],int n)
{
int *p,*array_end;
array_end=array+n;
max=min=*array;
for(p=array+1;p<array_end;p++)
{
if(*p>max)
{
max= *p;
}
else if(*p<min)
{
min=*p;
}
}
}
例题:将给定的10个数从大到小输出。
#include<stdio.h>
void sort(int x[],int n);
int main()
{
int *p,i,a[10]={3,7,9,11,0,6,7,5,4,2};
printf("The original array:\n");
for(i=0;i<10;i++)
{
printf("%d ",a[i]);
}
printf("\n");
p=a;
sort(p,10);
printf("The result is:\n");
for(i=0;i<10;i++)
{
printf("%d ",*p);
p++;
}
printf("\n");
}
void sort(int x[],int n)
{
int i,j,k,t;
for(i=0;i<n-1;i++)
{
for(j=i+1;j<n;j++)
{
if(x[j]>x[i])
{
t=x[j];
x[j]=x[i];
x[i]=t;
}
}
}
}