前言:指针是 C语言一个重要概念,也是C 语言的一个重要特色。使程序简洁、紧凑、高效。指针乃是C之精华。
数据在内存中的存储及读取:在程序中定义的变量,在对程序进行编译时,系统会给变量分配内存单元。编译系统根据程序定义的变量类型,分配一定长度的空间。内存区的每一个字节有一个编号,这就是“地址”,它相当于旅馆中的房间号。在地址所标志的内存单元中存放的数据则相当于旅馆房间中居住的旅客。
由于通过地址能找到需要的变量单元,因此,地址指向该变量单元。将地址形象地称为“指针”。通过指针能找到以它为地址的内存单元。
区分:存储单元的地址 和 存储单元的内容
eg:
int i ,j,k;
printf(”%d”,i)
在程序中,一般通过变量名引用变量的值、实际上,是通过变量名 i 找到存储单元的地址,从而对存储单元进行操作。
scanf(“%d”,&j)
程序运行时,把键盘输入的值送入到某一地址开始的整形存储单元中。if k = i + j;按变量名进行的运算存储的这种方式,直接按变量名进行的访问 ,称为 :直接访问
另外:将变量 i 的地址存放到另一变量中,然后通过该变量来找到变量i 的地址的方式是间接访问。
i_pointer = & i; (变量i 所占用单元的起始地址)
一个变量的地址称为该变量的 “指针”:变量 存放 另一个变量的地址 .-> 变量称为:指针变量 地址变量 指针变量的值 是 地址(即地址 指针是一个地址 指针变量 是一个存放地址的变量)。
指针变量: 存放地址的变量是指针变量 ,用来指向 另一个 对象(变量、数组、函数等)通过访问指针变量 可以找到它所指向的变量,从而得到这些变量的值。
定义:
# include
int main( )
{
int a =100,b =10;
int *p1,*p2;
p1 = &a,p2 = &b;
printf(“a = %d,b = %d”,a,b);
printf(“ *p1 = %d,*p2 = %d”,*p1,*p2); //输出 a b 的值
}
其中的“*” ,表示 “指向”。*p1 表示 指针变量p1 指向的变量a.
定义时: *p1 和 *p2 表示定义两个指针变量。前面的“*” 表示该变量为指针变量。无定义时,表示的是 指针变量指向的 变量。
类型名 * 指针变量名;可定义时 初始化;
int * p1 = &a;
注:指针变量的“*”表示该变量的类型为指针型变量。
定义时,必须制定基类型。不同数据类型在内存中占据不同的存储单元。
一个变量的指针的含义:以存储单元编号表示的地址(如2000开始的字节),指向的存储单元的数据类型。float char .
指针变量只能存放地址。
2.引用指针变量
(1)、给指针变量赋值。
p = &a; //把 a的地址付给 指针变量 p;
指针变亮 p 的值 是 变量a 的地址。p 指向 a .p 是指向 整形数据的指针变量。
(2)、引用指针变量 指向的 变量。
如果执行了1 操作、即p 是指向 整形数据的指针变量。
则printf(“%d”,*p); 其作用是以整数形式输出 指针变量p 所指向的 变量的值。即变量 a 的值。
如果有赋值语句:
*p = 1; // 表示 将 整数 1 赋给 p当前 所指向的变量。 即 a = 1;
(3)、引用指针变量的值
printf(“ %o”,p); // 以八进制的形式输出指针变量的 p的值,即 a 的值。
注:1.& 取地址符 。* 指针运算符(或 间接访问 运算符)*p 代表指针变量 p 指向的对象。
eg :输入 a and b 两个整数,按大小顺序 输出 a 和 b;
# include
int main( )
{
int *p1,*p2,*p,a,b;
printf(“enter two number:”);
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”,a,b);
printf(“max = %d,min = %d”,*p1,*p2);
}
return 0;
}
3、指针变量 作为 函数 参数
函数的参数不仅可以使 整形 浮点型 字符~,指针类型。其作用是将一个 变量的地址 传送到 另一个函数中。
上列:定义一个函数 将指向 两个整形变量 的 指针变量 作为实参 传递给 函数的形参指针变量,在函数中 通过指针 实现交换两个变量的 值。
# include
int main ( )
{
void swap(int *p1,int * p2);
{
int a,b;
int *pointer_1,*pointer_2;
printf(“enter a and b:”);
scanf(“%d,%d”,&a,&b);
pointer_1 = &a;
pointer_2 = &b;
if(a < b) swap(pointer_1,pointer_2);
printf(“max = %d,min = %d”,a,b);
}
return 0;
}
void swap(int *p1,int *p2)
{
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;( 指针前面有赋值符号 表示值 无,表示 指向的对象)
}
注:在函数传递时,将实际参数的值传递给形式参数变量,采取的是“值传递”的方式。传递后 p1 的值 为 &a.这时 ,p1 and pointer_1都指向 变量 a。调用结束后,形参 p1 p2 释放。 这改变了变量的值 、行参的值的改变不能改变实际参的值。而应该用指针变量作为函数参数,在函数执行过程中使指针变量 所指向的变量发生变化,函数调用结束后,变量值的变化 保留;
注:不能通过改变指针形参的值而使指针实参 的值 改变。
不能通过执行调用函数来改变实参指针变量的值,但是可以通过改变实参指针变量所指向的值;
eg:
# include
int main( )
{
void exchange(int *q1,int *q2,int *q3);
int a,b,c,*p1,*p2,*p3;
printf(“enter three number:”);
scanf(“%d,%d,%d”,&a,&b,&c);
p1 = &a;p2 = &b;p3 = &c;
exchange(p1,p2,p3);
printf(“the order is:%d,%d,%d\n”,a,b,c);
}
void exchange(int *q1,int *q2,int *q3 )
{
void swap(int *p1,int *p2);
if(*q1 < *q2 ) swap(q1,q2);
if(*q1 < *q3) swap(q1,q3);
if(*q2 < *q3) swap(q2.q3);
}
void swap(int *p1,int *p2)
{
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp; // 实现 交换 两个变量 的值的 函数
}
(4).通过指针引用数组
一个变量有地址,一个数组由若干个元素,每个数组元素在内存中 占用 存储单元,有相应的地址。可指变量,也可指数组(把某一元素的地址放到 一个指针变量中)。数组元素的指针 就是 数组 元素的 地址。
int a[3] = {1,2,3};
int *p;
p = &a[0];p = a//p 是数组a首元素的地址。将数组元素的首地址赋给指针变量 P。
5、引用数组元素时 指针的运算
1、在引用数组元素时,可以对指针进行如下的运算:
加一个整数,P+1;
自加运算,++P,P++;
自减运算,--P,P--;
两个指针相减,P1- P2;
(1),如果指针变量指向一个元素,P+1 指向同一数组中的下一个元素(同P-1)。+ 的是字节数哦 (~v~)
(2) P+ i 和 a +i 代表同一个地址a[ i ]. P 指向 &a[0]
(3)指针加法无意义哦
6、通过指针引用数组元素
1>下标法 如 a[i]形式。
2>指针法 如*(a+i) 或者 *(p+i).
有一个整形数组a,有十个元素,输出数组中的全部元素。
int main( )
{
int a[10];
int i;
printf(“enter ten integer number:")
for(i = 0;i < 10;i++)scanf(“%d”,&a[i]);
for(i = 0;I < 10;i++) printf(“%d”,a[i]);
printf(“\n”);
return 0;
}
// =========================================
int main( )
{
int a[10];
int i;
printf(“enter ten integer number:")
for(i = 0;i < 10;i++)scanf(“%d”,&a[i]);
for(i = 0;I < 10;i++) printf(“%d”,*(a+i);
printf(“\n”);
return 0;
}
用指针变量指向数组元素
~
~
int a[10];
int *p,i;
printf(“enter ten integer number:”);
for(i = 0;i < 10;i++) scanf(“%d”,&a[i]); // for(p = a;p < (a+10);p++) scanf(“%d”,p); 用指针变量表示 当前元素的地址
for(p = a ; p < (a +10);p++) printf(“%d”,*p);
int main( )
{
int a[10];
int i;
printf(“enter ten integer number:")
for(i = 0;i < 10;i++)scanf(“%d”,&a[i]);
for(i = 0;I < 10;i++) printf(“%d”,*(a+i);
printf(“\n”);
return 0;
}
for 循环中 P 的值要重新赋值 。
# include
int main( )
{
int i,a[10],*p = a;
printf(“enter ten integer numbers:”);
for(i = 0; i < 10 ;i++) scanf(“%d”,p++);
p = a;
for(“i = 0;i < 10;i++,p++”) printf(“%d”,*p);
printf(“\n”);
return 0;
}
在编译时,对下标的处理是转化为地址的: 对P[i] 处理成 *(p+i), 如果P 是指向一个数组元素 a[0], 则 p[i] 代表 a[i];
//==================
*p++ :++ 和* 同优先级 结合方向自右向左,等价于*(p++),先引用 P的值,实现*P 运算 ,然后 再使P 自加 1.
用数组名做函数参数
1、当用数组名做参数时,如果形参数组中 各元素 的值 发生改变,实参数组元素 的值 随之发生变化。cause:
void swap (int x,int y); swap (a[1],a[2]);
当调用函数改变两个值的交换时,a[1] a[2] 的值 并不改变。实参和形参的值传递。
fun(int arr[],int n);fun(int *p,int n);只有指针变量存放地址。
、通过这种方法改变实参数组 中的值。
用函数将数组中的元素调换顺序。
行参数组名可以用数组名,也可用指针变量名。
# include
int main()
{
void inv (int x[ ],int n);
int i,a[10] = {3,1,22,88,8,0,10,20,77,89};
printf(“the original array is:”);
for (i = 0 ;i < 10; i++) printf(“%d”,a[i]);
printf(“\n”);
inv(a,10);
printf(“the array has been inverted:\n”);
for(i = 0;i < 10;i++) printf(“%d”,a[i]);
printf(“\0”);
return 0;
}
void inv(int x[ ],int n)
{
int temp,i,j,m = (n -1)/2;
for(i = 0;i <= m;i++)
{
j = n - 1 -i;
temp = x[i];x[i] = x[j];x[j] = temp;
}
return 0;
}
//====================
# include
int main( )
{
void sort(int x[ ],int n);
int i,*p,a[10];
p = a;
printf(“enter ten integer numbers:”);
for(i = 0;i < 10;i++) scanf(“%d”,p++);
p = a; / 重新指向a[0];
sort(p,10);
for(p = a,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++)
{
k = i;
for(j = i +1;j
{
if(x[ j ] > x[ k ]) k = j;
if(k != i)
{
t = x[ i ];x[ i ] = x[k]; x[k] = t;
}
}
}
}
/*
void sort(int *x,int n)
{
int j,i,k,t;
for(i = 0;i < n -1;i++ )
{
k = i;
for(j = i+1,j < n;j++)
if(*(x+j) > *(x+k)) k = j;
if(k != i))
{
t = *(x+i);*(x+i) = *x(x+k);*(x+k) = t;
}
}
}
*/
2.通过指针引用多维数组
int a[3][4] = {{1,2,3,4},{2,3,5,6}};
表示形式 含义 地址
a |二维数组名 指向一维数组a[0], 即0行首地址| 200 0
a[0] *(a+0) *a 0行0列 元素地址 2000
a[1] +2 *(a+1) +2 &[1][2] 1 行2列的地址 2024
a[1] *(a +1) 1行0 列的地址 2016
a + 1 代表一行中全部元素占用字节数。16
a[0] + 1 中的 1 代表一个a 元素占用的字节数。4
、输出二维数组中任一行,任一列元素的值
# include
int main ( )
{
int a[3][4] = {1,3,5,7,9,11,13,15,17,19,21,23};
int (*p)[4] ,i,j;
p = a;
printf(“enter row andcolum:”);
scanf(“%d,%d”,&i,&j);
printf(“a[%d][%d] = %d\n”,i,j,*(*(p +i)+ j));
}
//========================================
# include
int main ( )
{
void search (float (*p)[4],int n);
float score[3][4] = {{65,57,70,60},{58,87,90,81},{90,99,100,98}};
search(score,3);
return 0;
}
// 定义一个函数
void search (float (*p)[4],int n)
{
int i,j,flag;
for(j = 0;j < n;j++)
{
flag = 0;
for(i = 0;i < 4;i++)if(*(*(p +j) + i ) < 60) flag = 1;
if(flag == 1)
{
printf(“No.%d fails,his score are:\n”,j+1);
for(i = 0;i < 4;i++)printf(“%5.1f”,*(*(p + j) + i);
printf(“\n”);
}
}
}