第 7章 指 针
7.1 指针的基本概念
7.2 指针变量
7.3 数组与指针
7.4 字符串与指针
7.5 指针数组与指向指针的指针
7.6 函数与指针
7.7 程序举例
7.1 指针的基本概念
( 1) 直接存取
所谓直接存取,是指在程序执行过程中需要存取变
量值时,直接存取变量所占内存单元中的内容。
( 2) 间接存取
所谓间接存取,是指为了要存取一个变量值,首先
从存放变量地址的指针变量中取得该变量的存储地址,
然后再从该地址中存取该变量值。
在 C语言中,用符号,*”表示“指向”,反映指针
变量与它所指的变量之间的联系:
( 1)在变量类型说明中,变量前加, *” 用于区别
于普通变量。
( 2)在表达式中,变量前加, *” 表示间接访问。
7.2 指针变量
7.2.1 指针变量的定义与引用
变量的指针就是变量的地址, 即指针变量用于存放变
量的地址 ( 即指向变量 ) 。
定义指针变量的一般形式为
类型标识符 *指针变量名;
下面对指针变量作几点说明:
( 1)指针变量名前的, *” 表示该变量为指针变量,而指针
变量名不包含该, *” 。
( 2)一个指针变量只能指向同一类型的变量。
( 3)指针变量中只能存放地址,而不能将数值型数据赋给
指针变量。
( 4)只有当指针变量中具有确定地址后才能被引用。
( 5)与一般的变量一样,也可以对指针变量进行初始化。
7.2.2 指针变量作为函数参数
与普通变量一样, 指针变量也可以作为函数参数 。 利
用指针变量作为函数的形参, 可以使函数通过指针变量返
回指针变量所指向的变量值, 从而实现函数调用函数与被
调用函数之间数据的双向传递 。
在用指针变量作为函数形参时, 其实参也应为指针变
量 。
例 7.2 利用指针变量实现两个变量值的互换 。
其 C程序如下:
#include "stdio.h"
swap(p1,p2)
int *p1,*p2;
{ int t;
t= *p1; *p1= *p2; *p2= t;
return;
}
main()
{ int a,b;
scanf("%d,%d",&a,&b);
printf("a= %d,b= %d\n",a,b);
swap(&a,&b);
printf("a= %d,b= %d\n",a,b);
}
7.3 数组与指针
7.3.1 数组的指针与数组元素的指针
所谓数组的指针是指数组的首地址。数组元素的指
针是指数组元素的地址。因此,同样可以用指针变量来
指向数组或数组元素。
例 7.3 下列 C程序是从键盘为数组元素输入数据:
#include "stdio.h"
main()
{ int a[10],i;
for (i= 0; i< 10; i= i+ 1)
scanf("%d",&a[i]);
printf("\n");
for (i= 0; i< 10; i= i+ 1)
printf("%5d\n",a[i]);
}
也可以直接使用数组名, 将上述程序改为
#include "stdio.h"
main()
{ int a[10],i;
for (i= 0; i< 10; i= i+ 1)
scanf("%d",a+ i);
printf("\n");
for (i= 0; i< 10; i= i+ 1)
printf("%5d\n",*(a+ i));
}
还可以使用指针变量, 将上述程序改为
#include "stdio.h"
main()
{ int a[10],*p= a,i;
for (i= 0; i< 10; i= i+ 1)
scanf("%d",p+ i);
printf("\n");
for (i= 0; i< 10; i= i+ 1)
printf("%5d\n",*(p+ i));
}
使用指针变量后, 指针变量所指向的数组元素也
可以用下标的形式, 又可以将上述程序改为
#include "stdio.h"
main()
{ int a[10],*p= a,i;
for (i= 0; i< 10; i= i+ 1)
scanf("%d",p+ i);
printf("\n");
for (i= 0; i< 10; i= i+ 1)
printf("%5d\n",p[i]);
}
以上四个程序是等价的 。
下面对数组与指针作几点说明:
( 1)指针变量可以指向数组中的任何一个元素。
( 2)用于指向数组或数组元素的指针变量类型必须与数组类
型相同。
( 3) C语言规定,当指针变量 p指向数组的某一元素时,p+ 1
将指向下一个元素。
( 4) C语言规定,数组名代表数组的首地址,但它是固定不
变的,即不能对数组名进行赋值(即赋以新的地址值)。
7.3.2 数组指针作为函数参数
一般来说, 在数组指针作函数参数时, 有以下四种情况:
( 1) 实参与形参都用数组名 。 例如,
main() f(x,n)
{ int a[10]; int x[],n;
… { …
f(a,10); …
… …
} }
( 2) 实参用数组名, 形参用指针变量 。 例如,
main() f(x,n)
{ int a[10]; int *x,n;
… { …
f (a,10); …
… …
} }
( 3)实参与形参都用指针变量。例如,
main() f(x,n)
{ int a[10],*p= a; int *x,n;
… { …
f (p,10); …
… …
} }
( 4)实参用指针变量,形参用数组名。例如,
main() f(x,n)
{ int a[10],*p= a; int x[],n;
… { …
f(p,10); …
… …
} }
7.3.3 多维数组与指针
1,对多维数组的理解
2,多维数组的指针
多维数组的指针有以下两种 。
( 1) 指向数组元素的指针变量
例 7.5 下列 C程序是将一个二维数组中的元素按矩阵方
式输出。
#include "stdio,h"
main()
{ static int a[3][4]= {1,2,3,4,5,6,7,8,9,10,11,12};
int *p;
for (p= a[0]; p< a[0]+ 12; p= p+ 1)
{ if ((p- a[0])%4== 0) printf("\n");
printf("%5d",*p);
}
printf("\n");
}
( 2) 指向数组行的指针变量
所谓指向数组行的指针变量 p,是指当 p指向数组的某一
行时, p+ 1将指向数组的下一行 。 即:如果 p= &a[i]时, 则
p+ 1= &a[i+ 1]。
定义指向数组行的指针变量的一般形式如下:
类型标识符 (*指针变量名 )[数组行元素个数 ];
7.4 字符串与指针
7.4.1 字符串指针
在 C语言中, 表示一个字符串有以下两种形式:
( 1)用字符数组存放一个字符串。
( 2)用字符指针指向一个字符串。
字符数组和字符指针变量都能实现字符串的存储与
运算。两者既有联系又有区别,主要体现在以下几个方
面:
( 1)字符数组由元素组成,每个元素中存放一个字
符;而字符指针变量中存放的是地址,也能作为函数参
数。
( 2)对数组赋初值要用 static存储类别。
( 3)只能对字符数组中的各个元素赋值,而不能用
赋值语句对整个字符数组赋值。
( 4)字符数组名虽然代表地址,但数组名的值不能
改变。
( 5)可以用下标形式引用指针变量所指向的字符
串中的字符。
( 6)可以通过输入字符串的方式为字符数组输入
字符元素;但不能通过输入函数让字符指针变量指向
一个字符串,因为由键盘输入的字符串,系统是不分
配存储空间的。
( 7)可以用指针变量指向的字符串来表示程序中
的任何字符串,如 printf函数中的格式字符串。
7.4.2 字符串指针作为函数参数
一般来说, 当需要在两个函数之间传递字符串时, 可
以采用以下四种形式:
( 1)实参与形参都用字符数组名。
( 2)实参用字符数组名,形参用字符指针变量。
( 3)实参与形参都用字符指针变量。
( 4)实参用字符指针变量,形参用字符数组名。
例 7.6 编写一个能实现字符串复制以及计算字符串长度功
能的函数 。
C程序如下 ( 包括主函数 ),
int str_copy(str1,str2)
char *str1,*str2;
{ int k;
k= 0;
while(str1[k]!= '\0')
{ str2[k]= str1[k];
k= k+ 1;
}
str2[k]= '\0';
return(k- 1);
}
#include "stdio,h"
main()
{ char str1[20],str2[20];
int k;
printf("input str1,");
scanf("%s",str1);
printf("str1= %s\n",str1);
k= str_copy(str1,str2);
printf("str2= %s\n",str2);
printf("k= %d\n",k);
}
7.5 指针数组与指向指针的指针
7.5.1 指针数组的概念
元素值均为指针类型数据的数组称为指针数组。
指针数组的定义形式如下:
类型标识 *数组名 [数组长度说明 ];
na m e 指针数组
na m e [ 0]
na m e [ 1]
na m e [ 2]
na m e [ 3]
na m e [ 4]
" B A SIC "
" FO R T R A N "
" C O B O L "
" C + + "
" J A V A "
na m e
图 7.2 数组的初始化
如图 7.2所示的指针数组:
例 7.7 指针数组作为矩阵运算函数的参数 。
在下面的 C程序中, 主函数中定义了一个 5× 4的矩阵,
然后调用函数 asd()对该矩阵赋值, 最后在主函数中按矩阵形
式输出 。 在第 6章中曾经提到, 在用二维数组作为实参时, 在
被调用函数中均定义为一维的形参数组, 根据二维数组中的元
素以行为主存储的原则, 将二维数组元素中的两个下标 ( 行标
与列标 ) 转换成一维数组元素的下标, 从而实现一维数组元素
与二维数组元素的对应 。 因此, 在本例的函数 asd()中, 也用
一维形参数组 b与主函数中的二维数组 a对应 。
#include "stdio,h"
main()
{ int i,j,a[5][4];
asd(a,5,4);
for (i= 0; i< 5; i= i+ 1)
{ for (j= 0; j< 4; j= j+ 1) printf("5d",a[i][j]);
printf("\n");
}
}
asd(b,m,n)
int m,n,b[](或 *b);
{ int k= 1,i,j;
for (i= 0; i< 5; i= i+ 1)
for (j= 0; j< 4; j= j+ 1)
{ b[i*n+ j]= k; k= k+ 1; }
return;
}
现在利用指针数组来实现二维数组的传递。在主函数
中除了定义一个二维数组 a(表示矩阵)以外,再定义一
个一维指针数组 b,并且在该指针数组的每一个元素中对
应存放二维数组 a中每一行的首地址,即让指针数组 b中
的每个元素指向二维数组 a的对应行。在调用函数 asd()时,
实参使用一维指针数组 b,即将二维数组 a中各行的首地
址传递给函数 asd()。在这种情况下,函数 asd()中的形参
也是一维指针数组,其中 b[i][j]表示 b[i]所指向的数组行中
第 j个元素,实际上就是主函数中的元素 a[i][j]。 其 C程序
如下:
#include "stdio,h"
main()
{ int i,j,a[5][4],*b[5];
for (i= 0; i< 5; i= i+ 1) b[i]= &a[i][0];
asd(b,5,4);
for (i= 0; i< 5; i= i+ 1)
{ for (j= 0; j< 4; j= j+ 1) printf("5d",a[i][j]);
printf("\n");
}
}
asd(b,m,n)
int m,n,*b[];
{ int k= 1,i,j;
for (i= 0; i< 5; i= i+ 1)
for (j= 0; j< 4; j= j+ 1)
{ b[i][j]= k; k= k+ 1; }
return;
}
利用指针数组来实现二维数组的传递还可以这样来实
现:在主函数中只定义一个一维指针数组,然后利用
malloc()函数为该指针数组中的每一个元素指向一个能存放
4个整型元素的存储空间,每一个存储空间正好可以存放整
型二维数组中一行的 4个元素。这样,一维指针数组 b中所
有元素所指向的存储空间就可以作为二维数组的存储空间。
其 C程序如下:
#include "stdio,h"
#include "stdlib,h"
main()
{ int i,j,*b[5];
for (i= 0; i< 5; i= i+ 1) b[i]= malloc(4*sizeof(int));
asd(b,5,4);
for (i= 0; i< 5; i= i+ 1)
{ for (j= 0; j< 4; j= j+ 1) printf("5d",b[i][j]);
printf("\n");
}
}
asd(b,m,n)
int m,n,*b[];
{ int k= 1,i,j;
for (i= 0; i< 5; i= i+ 1)
for (j= 0; j< 4; j= j+ 1)
{ b[i][j]= k; k= k+ 1; }
return;
}
7.5.2 指向指针的指针
指向指针的指针就是指向指针型数据的指针 。 如
char **p;
其中 **p等价于 *(*p)。
例 7.8 下列 C程序是利用指针的指针来指向数组中的各元素并
输出 。
#include "stdio,h"
main()
{ static int a[5]= {1,2,3,4,5};
static int *num[5]= {&a[0],&a[1],&a[2],&a[3],&a[4]};
int **p,k;
p= num;
for (k= 0; k< 5; k= k+ 1)
{ printf("%5d",**p); p= p+ 1; }
printf("\n");
}
7.5.3 main函数的形参
C语言中的主函数是可以有参数的 。 带参数 main函数的一
般形式如下:
main(argc,argv)
int argc;
char *argv[];
{ … }
其中 argv是一个字符型的指针数组, 每个元素可以指向一
个字符串 。 需要说明的是, 带参数 main函数中的两个参数名不
一定非要是 argc与 argv,也可以是别的名字 。
例 7.9 编写一个命令程序, 其命令符为 file,用以输出命令
行中除命令符外以空格分隔的所有字符串 ( 一行输出一个字符
串 ) 。
其 C程序如下:
/*file,c*/
#include "stdio,h"
main(int argc,char *argv[])
{ int k;
for (k= 1; k<= argc- 1; k++ )
printf("%s\n",argv[k]);
}
将上述程序以文件名 file.c存放,然后在 Turbo C系统
中进行编译连接:
tcc file<回车 >
生成可执行程序文件 file,exe。运行结果为
file new good China asdfg<回车 > (此为命令行,以下四
行为程序输出结果)
new
good
China
asdfg
7.6 函数与指针
7.6.1 用函数指针变量调用函数
在 C语言中, 指针不仅可以指向整型, 字符型, 实型等
变量, 还可以指向函数 。 一般来说, 程序中的每一个函数经
编译连接后, 其目标代码在计算机内存中是连续存放的, 该
代码的首地址就是函数执行时的入口地址 。 在 C语言中, 函
数名本身就代表该函数的入口地址 。 所谓指向函数的指针,
就是指向函数的入口地址 。
指向函数的指针变量定义形式如下:
数据类型标识符 (*指针变量名 )();
其中 ()不能省略。
定义了函数指针变量后,就可以通过它间接调用它所指
向的函数。
下面对指向函数的指针作几点说明:
( 1) 可以通过指向函数的指针变量来调用函数 。
( 2) 在给函数指针变量赋值时, 只需给出函数名, 不
必给出参数 。 如上例中的 p= ft;
( 3) 对函数指针变量运算是没有意义的 。 若 p为函数指
针变量, 则 p= p+ 1是没有意义的 。
7.6.2 函数指针变量作为函数参数
当函数指针作为某函数的参数时,可以实现将函
数指针所指向的函数入口地址传递给该函数。
7.7 程序举例
例 7.11 编写一个函数, 计算
…
直到最后一项的绝对值 x2n+ 1< 0.0001为止, 并返回
此时的 n值 。 其中 x在主函数中从键盘输入 。
???? 53 5131)( xxxxS 1212
)1( ?
?
?? nn x
n
12
1
?n
其 C程序如下:
#include "math,h"
#include "stdio,h"
double arctan(double x,int *n)
{ int k,m= 0;
double f,d,s;
f= x; s= x;
do
{ m= m+ 1;
f=- f*x*x;
d= f/(2*m+ 1);
s= s+ d;
}
while (fabs(d)>= 0,0001);
*n= m;
return(s);
}
main()
{ int n;
double x,s;
printf("input x:");
scanf("%lf",&x);
s= arctan(x,&n);
printf("n= %d\ns= %f\n",n,s);
}
7.1 指针的基本概念
7.2 指针变量
7.3 数组与指针
7.4 字符串与指针
7.5 指针数组与指向指针的指针
7.6 函数与指针
7.7 程序举例
7.1 指针的基本概念
( 1) 直接存取
所谓直接存取,是指在程序执行过程中需要存取变
量值时,直接存取变量所占内存单元中的内容。
( 2) 间接存取
所谓间接存取,是指为了要存取一个变量值,首先
从存放变量地址的指针变量中取得该变量的存储地址,
然后再从该地址中存取该变量值。
在 C语言中,用符号,*”表示“指向”,反映指针
变量与它所指的变量之间的联系:
( 1)在变量类型说明中,变量前加, *” 用于区别
于普通变量。
( 2)在表达式中,变量前加, *” 表示间接访问。
7.2 指针变量
7.2.1 指针变量的定义与引用
变量的指针就是变量的地址, 即指针变量用于存放变
量的地址 ( 即指向变量 ) 。
定义指针变量的一般形式为
类型标识符 *指针变量名;
下面对指针变量作几点说明:
( 1)指针变量名前的, *” 表示该变量为指针变量,而指针
变量名不包含该, *” 。
( 2)一个指针变量只能指向同一类型的变量。
( 3)指针变量中只能存放地址,而不能将数值型数据赋给
指针变量。
( 4)只有当指针变量中具有确定地址后才能被引用。
( 5)与一般的变量一样,也可以对指针变量进行初始化。
7.2.2 指针变量作为函数参数
与普通变量一样, 指针变量也可以作为函数参数 。 利
用指针变量作为函数的形参, 可以使函数通过指针变量返
回指针变量所指向的变量值, 从而实现函数调用函数与被
调用函数之间数据的双向传递 。
在用指针变量作为函数形参时, 其实参也应为指针变
量 。
例 7.2 利用指针变量实现两个变量值的互换 。
其 C程序如下:
#include "stdio.h"
swap(p1,p2)
int *p1,*p2;
{ int t;
t= *p1; *p1= *p2; *p2= t;
return;
}
main()
{ int a,b;
scanf("%d,%d",&a,&b);
printf("a= %d,b= %d\n",a,b);
swap(&a,&b);
printf("a= %d,b= %d\n",a,b);
}
7.3 数组与指针
7.3.1 数组的指针与数组元素的指针
所谓数组的指针是指数组的首地址。数组元素的指
针是指数组元素的地址。因此,同样可以用指针变量来
指向数组或数组元素。
例 7.3 下列 C程序是从键盘为数组元素输入数据:
#include "stdio.h"
main()
{ int a[10],i;
for (i= 0; i< 10; i= i+ 1)
scanf("%d",&a[i]);
printf("\n");
for (i= 0; i< 10; i= i+ 1)
printf("%5d\n",a[i]);
}
也可以直接使用数组名, 将上述程序改为
#include "stdio.h"
main()
{ int a[10],i;
for (i= 0; i< 10; i= i+ 1)
scanf("%d",a+ i);
printf("\n");
for (i= 0; i< 10; i= i+ 1)
printf("%5d\n",*(a+ i));
}
还可以使用指针变量, 将上述程序改为
#include "stdio.h"
main()
{ int a[10],*p= a,i;
for (i= 0; i< 10; i= i+ 1)
scanf("%d",p+ i);
printf("\n");
for (i= 0; i< 10; i= i+ 1)
printf("%5d\n",*(p+ i));
}
使用指针变量后, 指针变量所指向的数组元素也
可以用下标的形式, 又可以将上述程序改为
#include "stdio.h"
main()
{ int a[10],*p= a,i;
for (i= 0; i< 10; i= i+ 1)
scanf("%d",p+ i);
printf("\n");
for (i= 0; i< 10; i= i+ 1)
printf("%5d\n",p[i]);
}
以上四个程序是等价的 。
下面对数组与指针作几点说明:
( 1)指针变量可以指向数组中的任何一个元素。
( 2)用于指向数组或数组元素的指针变量类型必须与数组类
型相同。
( 3) C语言规定,当指针变量 p指向数组的某一元素时,p+ 1
将指向下一个元素。
( 4) C语言规定,数组名代表数组的首地址,但它是固定不
变的,即不能对数组名进行赋值(即赋以新的地址值)。
7.3.2 数组指针作为函数参数
一般来说, 在数组指针作函数参数时, 有以下四种情况:
( 1) 实参与形参都用数组名 。 例如,
main() f(x,n)
{ int a[10]; int x[],n;
… { …
f(a,10); …
… …
} }
( 2) 实参用数组名, 形参用指针变量 。 例如,
main() f(x,n)
{ int a[10]; int *x,n;
… { …
f (a,10); …
… …
} }
( 3)实参与形参都用指针变量。例如,
main() f(x,n)
{ int a[10],*p= a; int *x,n;
… { …
f (p,10); …
… …
} }
( 4)实参用指针变量,形参用数组名。例如,
main() f(x,n)
{ int a[10],*p= a; int x[],n;
… { …
f(p,10); …
… …
} }
7.3.3 多维数组与指针
1,对多维数组的理解
2,多维数组的指针
多维数组的指针有以下两种 。
( 1) 指向数组元素的指针变量
例 7.5 下列 C程序是将一个二维数组中的元素按矩阵方
式输出。
#include "stdio,h"
main()
{ static int a[3][4]= {1,2,3,4,5,6,7,8,9,10,11,12};
int *p;
for (p= a[0]; p< a[0]+ 12; p= p+ 1)
{ if ((p- a[0])%4== 0) printf("\n");
printf("%5d",*p);
}
printf("\n");
}
( 2) 指向数组行的指针变量
所谓指向数组行的指针变量 p,是指当 p指向数组的某一
行时, p+ 1将指向数组的下一行 。 即:如果 p= &a[i]时, 则
p+ 1= &a[i+ 1]。
定义指向数组行的指针变量的一般形式如下:
类型标识符 (*指针变量名 )[数组行元素个数 ];
7.4 字符串与指针
7.4.1 字符串指针
在 C语言中, 表示一个字符串有以下两种形式:
( 1)用字符数组存放一个字符串。
( 2)用字符指针指向一个字符串。
字符数组和字符指针变量都能实现字符串的存储与
运算。两者既有联系又有区别,主要体现在以下几个方
面:
( 1)字符数组由元素组成,每个元素中存放一个字
符;而字符指针变量中存放的是地址,也能作为函数参
数。
( 2)对数组赋初值要用 static存储类别。
( 3)只能对字符数组中的各个元素赋值,而不能用
赋值语句对整个字符数组赋值。
( 4)字符数组名虽然代表地址,但数组名的值不能
改变。
( 5)可以用下标形式引用指针变量所指向的字符
串中的字符。
( 6)可以通过输入字符串的方式为字符数组输入
字符元素;但不能通过输入函数让字符指针变量指向
一个字符串,因为由键盘输入的字符串,系统是不分
配存储空间的。
( 7)可以用指针变量指向的字符串来表示程序中
的任何字符串,如 printf函数中的格式字符串。
7.4.2 字符串指针作为函数参数
一般来说, 当需要在两个函数之间传递字符串时, 可
以采用以下四种形式:
( 1)实参与形参都用字符数组名。
( 2)实参用字符数组名,形参用字符指针变量。
( 3)实参与形参都用字符指针变量。
( 4)实参用字符指针变量,形参用字符数组名。
例 7.6 编写一个能实现字符串复制以及计算字符串长度功
能的函数 。
C程序如下 ( 包括主函数 ),
int str_copy(str1,str2)
char *str1,*str2;
{ int k;
k= 0;
while(str1[k]!= '\0')
{ str2[k]= str1[k];
k= k+ 1;
}
str2[k]= '\0';
return(k- 1);
}
#include "stdio,h"
main()
{ char str1[20],str2[20];
int k;
printf("input str1,");
scanf("%s",str1);
printf("str1= %s\n",str1);
k= str_copy(str1,str2);
printf("str2= %s\n",str2);
printf("k= %d\n",k);
}
7.5 指针数组与指向指针的指针
7.5.1 指针数组的概念
元素值均为指针类型数据的数组称为指针数组。
指针数组的定义形式如下:
类型标识 *数组名 [数组长度说明 ];
na m e 指针数组
na m e [ 0]
na m e [ 1]
na m e [ 2]
na m e [ 3]
na m e [ 4]
" B A SIC "
" FO R T R A N "
" C O B O L "
" C + + "
" J A V A "
na m e
图 7.2 数组的初始化
如图 7.2所示的指针数组:
例 7.7 指针数组作为矩阵运算函数的参数 。
在下面的 C程序中, 主函数中定义了一个 5× 4的矩阵,
然后调用函数 asd()对该矩阵赋值, 最后在主函数中按矩阵形
式输出 。 在第 6章中曾经提到, 在用二维数组作为实参时, 在
被调用函数中均定义为一维的形参数组, 根据二维数组中的元
素以行为主存储的原则, 将二维数组元素中的两个下标 ( 行标
与列标 ) 转换成一维数组元素的下标, 从而实现一维数组元素
与二维数组元素的对应 。 因此, 在本例的函数 asd()中, 也用
一维形参数组 b与主函数中的二维数组 a对应 。
#include "stdio,h"
main()
{ int i,j,a[5][4];
asd(a,5,4);
for (i= 0; i< 5; i= i+ 1)
{ for (j= 0; j< 4; j= j+ 1) printf("5d",a[i][j]);
printf("\n");
}
}
asd(b,m,n)
int m,n,b[](或 *b);
{ int k= 1,i,j;
for (i= 0; i< 5; i= i+ 1)
for (j= 0; j< 4; j= j+ 1)
{ b[i*n+ j]= k; k= k+ 1; }
return;
}
现在利用指针数组来实现二维数组的传递。在主函数
中除了定义一个二维数组 a(表示矩阵)以外,再定义一
个一维指针数组 b,并且在该指针数组的每一个元素中对
应存放二维数组 a中每一行的首地址,即让指针数组 b中
的每个元素指向二维数组 a的对应行。在调用函数 asd()时,
实参使用一维指针数组 b,即将二维数组 a中各行的首地
址传递给函数 asd()。在这种情况下,函数 asd()中的形参
也是一维指针数组,其中 b[i][j]表示 b[i]所指向的数组行中
第 j个元素,实际上就是主函数中的元素 a[i][j]。 其 C程序
如下:
#include "stdio,h"
main()
{ int i,j,a[5][4],*b[5];
for (i= 0; i< 5; i= i+ 1) b[i]= &a[i][0];
asd(b,5,4);
for (i= 0; i< 5; i= i+ 1)
{ for (j= 0; j< 4; j= j+ 1) printf("5d",a[i][j]);
printf("\n");
}
}
asd(b,m,n)
int m,n,*b[];
{ int k= 1,i,j;
for (i= 0; i< 5; i= i+ 1)
for (j= 0; j< 4; j= j+ 1)
{ b[i][j]= k; k= k+ 1; }
return;
}
利用指针数组来实现二维数组的传递还可以这样来实
现:在主函数中只定义一个一维指针数组,然后利用
malloc()函数为该指针数组中的每一个元素指向一个能存放
4个整型元素的存储空间,每一个存储空间正好可以存放整
型二维数组中一行的 4个元素。这样,一维指针数组 b中所
有元素所指向的存储空间就可以作为二维数组的存储空间。
其 C程序如下:
#include "stdio,h"
#include "stdlib,h"
main()
{ int i,j,*b[5];
for (i= 0; i< 5; i= i+ 1) b[i]= malloc(4*sizeof(int));
asd(b,5,4);
for (i= 0; i< 5; i= i+ 1)
{ for (j= 0; j< 4; j= j+ 1) printf("5d",b[i][j]);
printf("\n");
}
}
asd(b,m,n)
int m,n,*b[];
{ int k= 1,i,j;
for (i= 0; i< 5; i= i+ 1)
for (j= 0; j< 4; j= j+ 1)
{ b[i][j]= k; k= k+ 1; }
return;
}
7.5.2 指向指针的指针
指向指针的指针就是指向指针型数据的指针 。 如
char **p;
其中 **p等价于 *(*p)。
例 7.8 下列 C程序是利用指针的指针来指向数组中的各元素并
输出 。
#include "stdio,h"
main()
{ static int a[5]= {1,2,3,4,5};
static int *num[5]= {&a[0],&a[1],&a[2],&a[3],&a[4]};
int **p,k;
p= num;
for (k= 0; k< 5; k= k+ 1)
{ printf("%5d",**p); p= p+ 1; }
printf("\n");
}
7.5.3 main函数的形参
C语言中的主函数是可以有参数的 。 带参数 main函数的一
般形式如下:
main(argc,argv)
int argc;
char *argv[];
{ … }
其中 argv是一个字符型的指针数组, 每个元素可以指向一
个字符串 。 需要说明的是, 带参数 main函数中的两个参数名不
一定非要是 argc与 argv,也可以是别的名字 。
例 7.9 编写一个命令程序, 其命令符为 file,用以输出命令
行中除命令符外以空格分隔的所有字符串 ( 一行输出一个字符
串 ) 。
其 C程序如下:
/*file,c*/
#include "stdio,h"
main(int argc,char *argv[])
{ int k;
for (k= 1; k<= argc- 1; k++ )
printf("%s\n",argv[k]);
}
将上述程序以文件名 file.c存放,然后在 Turbo C系统
中进行编译连接:
tcc file<回车 >
生成可执行程序文件 file,exe。运行结果为
file new good China asdfg<回车 > (此为命令行,以下四
行为程序输出结果)
new
good
China
asdfg
7.6 函数与指针
7.6.1 用函数指针变量调用函数
在 C语言中, 指针不仅可以指向整型, 字符型, 实型等
变量, 还可以指向函数 。 一般来说, 程序中的每一个函数经
编译连接后, 其目标代码在计算机内存中是连续存放的, 该
代码的首地址就是函数执行时的入口地址 。 在 C语言中, 函
数名本身就代表该函数的入口地址 。 所谓指向函数的指针,
就是指向函数的入口地址 。
指向函数的指针变量定义形式如下:
数据类型标识符 (*指针变量名 )();
其中 ()不能省略。
定义了函数指针变量后,就可以通过它间接调用它所指
向的函数。
下面对指向函数的指针作几点说明:
( 1) 可以通过指向函数的指针变量来调用函数 。
( 2) 在给函数指针变量赋值时, 只需给出函数名, 不
必给出参数 。 如上例中的 p= ft;
( 3) 对函数指针变量运算是没有意义的 。 若 p为函数指
针变量, 则 p= p+ 1是没有意义的 。
7.6.2 函数指针变量作为函数参数
当函数指针作为某函数的参数时,可以实现将函
数指针所指向的函数入口地址传递给该函数。
7.7 程序举例
例 7.11 编写一个函数, 计算
…
直到最后一项的绝对值 x2n+ 1< 0.0001为止, 并返回
此时的 n值 。 其中 x在主函数中从键盘输入 。
???? 53 5131)( xxxxS 1212
)1( ?
?
?? nn x
n
12
1
?n
其 C程序如下:
#include "math,h"
#include "stdio,h"
double arctan(double x,int *n)
{ int k,m= 0;
double f,d,s;
f= x; s= x;
do
{ m= m+ 1;
f=- f*x*x;
d= f/(2*m+ 1);
s= s+ d;
}
while (fabs(d)>= 0,0001);
*n= m;
return(s);
}
main()
{ int n;
double x,s;
printf("input x:");
scanf("%lf",&x);
s= arctan(x,&n);
printf("n= %d\ns= %f\n",n,s);
}