C语言学习之七——指针_4_函数

!!!注意:因为简书的显示格式缘故,所以“ * ”显示会出现问题,可能有些星号由于疏忽未改动格式,造成没有显示,请多多包含,如有错误,请留言或联系本人更正,谢谢!

  1. 指向函数的指针简介
    函数指针变量:指的是存储一个指向函数的指针的变量。因为函数在编译时会被分配一个入口地址,而这个入口地址即为函数的指针。见例1.

//例1
/#include<stdio.h>
int max(int x, int y)
{
int z;
if( x > y )
{
z = x;
}
else
{
z = y;
}

return z;
}
void main()
{
int max(int, int);
int (p)();
int a, b, c;
p = max;
scanf("%d %d", &a, &b);
c = (
p)(a, b);
printf("a = %d, b = %d, max = %d\n\n", a, b, c);
}
//输入:55 66
//输出:a = 55, b = 66, max = 66

  1. 用函数指针作函数参数
    函数指针变量常用的用途之一是把指针作为参数传递到其他函数。(这里指针的作用就是作为一个实参被传递到其他函数中使用,其实质就是实现函数的嵌套作用,当然传递的只是函数的地址,然后通过地址再调用该函数。)
    例题1:设一个函数process,在调用它的时候,每次实现不同的功能。输入a和b两个数,第一次调用process时找出a和b中大者,第二次找出其中小者,第三次求a与b之和。

//例题1,方法1
/#include <stdio.h>
void main()
{
int max(int, int); /* 函数声明 /
int min(int, int); /
函数声明 /
int add(int, int); /
函数声明 */

void process( int, int, int(fun)() ); / 函数声明 */

int a, b;
printf("Endter a and b: ");
scanf("%d %d", &a, &b);

printf("max = ");
process(a, b, max);

printf("min = ");
process(a, b, min);

printf("sum = ");
process(a, b, add);
}

int max(int x, int y) /* 函数定义 */
{
return x > y ? x : y;
}

int min(int x, int y) /* 函数定义 */
{
return x < y ? x : y;
}

int add(int x, int y)
{
return x + y;
}

void process( int x, int y, int(fun)() ) / 函数定义 /
{
int result;
result = (
fun)(x, y);
printf("%d\n", result);
}
//Endter a and b: 6 9
//max = 9
min = 6
sum = 15
(这里实现了两层嵌套,主函数3次调用process函数,再process函数分别调用max,min,add函数)

//例题1,方法2
/#include<stdio.h>
void main()
{
int a, b, ma, mi, su;
int (p1)(), (p2)(), (p3)();
int max(int, int), min(int, int), sum(int, int);
p1 = max, p2 = min, p3 = sum;
printf("Please input two numbers: \n");
scanf("%d%d", &a, &b);
ma = (
p1)(a, b), mi = (p2)(a, b), su = (p3)(a, b);
printf("The maximum number is: %d\n", ma);
printf("The minimum number is: %d\n", mi);
printf("The sum is: %d\n", su);
}

int max(int x, int y)
{
return x > y ? x : y;
}

int min(int x, int y)
{
return x < y ? x : y;
}

int sum(int x, int y)
{
return x + y;
}
//Please input two numbers: 6 9
The maximum number is: 9
The minimum number is: 6
The sum is: 15
(这里实现一层嵌套,即主函数分别调用max,min,sum函数进行计算)

  1. 返回指针值的函数
    函数可以返回指针型的数据,即指针(地址)。
    返回指针值的函数的一般定义形式:类型名 *函数名(参数列表); (例 int *function(int x, int y);)
    例题2:有若干个学生的成绩(每个学生有4门课程),要求在用户输入学生序号以后,能输出该学生的全部成绩。

//例题2
/#include<stdio.h>
void main()
{
double score[][4] = {{60.0, 70.0, 80.5, 90.5}, {56.0, 89.0, 67.0, 88.0}, {34.2, 78.5, 90.5, 66.0}}; //定义数组,并输入3个学生的成绩
double * search(double (*s)[4], int n), *p; //声明返回指针值的函数search和指针变量p
int num, i;

printf("Please input student Id: ");
scanf("%d", &num);
p = search(score, num); /* 调用函数search,并将返回的指针赋值给指针变量p,即p中存储的 是search函数的返回值。*/
for(i = 0; i < 4; i++)
{
printf("The score is: %5.2f\n", *(p + i));
}
}

double * search(double (*s)[4], int n) //定义返回指针值的函数search
{
double *p;
p = *(s + n);
return p;
}
//Please input student Id: 1
The score is: 56.00
The score is: 89.00
The score is: 67.00
The score is: 88.00

  1. 指针函数和函数指针的区别
    指针函数:指针函数是指带指针的函数,即本质是一个函数。
    函数指针:函数指针是指向函数的指针变量,因而函数指针本身首先应是指针变量,只不过该指针变量指向函数。

  2. 指针数组和指向指针的指针
    指针数组的概念:一个数组,若其元素均为指针类型数据,称为指针数组,也就是说,指针数组中的每一个元素都相当于一个指针变量。
    一维指针数组的定义形式为:类型名 *数组名[数组长度]; (例:int *name[4];) 见例2,例3.

//例2
/#include <stdio.h>

void main()
{
int a[5] = {1, 3, 5, 7, 9};
int name[5] = {&a[0], &a[1], &a[2], &a[3], &a[4]}; / 定义指针数组name,并将数组a 的各个元素的地址赋给指针数组 name,即name其实也是一个数组, 只不过其数组元素存储的数值是其 他数组元素的地址。*/
int i;
for( i=0; i < 5; i++ )
{
printf("%d ", *name[i]);
}
printf("\n");
}
//输出:1 3 5 7 9

//例3
/#include<stdio.h>
void main()
{
char name[]={"This is the first semester.", "I studied in UNSW.","C language.","I dno't know!","Thank you!"}; //定义一个指针数组name,里面存储的是5个字符串的首地址
int i;
for (i = 0; i < 5; i++)
{
printf("%s\n", name[i]); /
通过找出指针数组name中各元素存储的字符串地址来,输出 字符串*/
}
}

  1. 指向指针的指针
    定义一个指向指针数据的指针变量一般形式: char * * p;
    解释:这里p的前面有两个" * "号。运算符的结合性是从右到左,因此 * * p相当于 * ( * p),显然 * p是指针变量的定义形式。如果没有最前面的" * " (即,只是“ * p”),那就是定义了一个指向字符数据的指针变量。现在它前面又有一个" * "号(即“ * p”),表示指针变量p是指向 * p的。 * p就是指向那个指向存储字符数据值的变量(i)的地址(&i)的指针。见例4,例5,例6.

//例4.
/#include<stdio.h>

void main()
{
int i = 5, j =6, k = 7;
int *p1 = &i, *p2 = &j;
int **ip;

      //p1 = &i, p2 =&j;  // 与int *p1 = &i, *p2 = &j 等价

* ip = p1;    /* *ip = &*p1;也可行,&*p1就等价于i的地址;当然也可以在定义指向指针指针的变量ip时,将p1的地址赋给**ip,即“int **ip = &p1;”。我们可以理解为,1)*ip中存储的是p1的地址,ip中存储的是*ip的地址,由于指针的符号优先级是右结合的,所以我们先算“*ip”,变量“ip”通过“*”得到变量“*ip”的地址(由此可以说明变量“ip”中存储的是变量“*ip”的地址),然后变量“*ip”后通过“*”得到p1(即i的地址)(由此可以说明变量“*ip”中存储的是变量“i”的地址),最后变量“**ip”通过“*”得到*p1所指向的值(即i的值)。注意,这一步我们还看不出“int **ip = &p1;”与“*ip = p1;或*ip = &*p1;”的区别,这里起的作用是相同的 。不同处,请看例5*/

printf(" * p1: %o\n", * p1);
printf(" * p2: %o\n", * p2);
printf(" * * ip: %o\n", * * ip);
printf("&i: %o\n", &i);
printf("&j: %o\n", &j);
printf("p1: %o\n", p1);
printf("p2: %o\n", p2);
printf("* ip: %o\n", * ip);
printf("&* ip: %o\n", &* ip);
printf("ip: %o\n", ip);
}
//输出:p1: 5
// * p2: 6 // p1,p2指向的是i,j存储的值(“
”取值操作符)
** ip: 5 // ip指向的是i存储的值5
&i: 15744334504
&j: 15744334510 //&i,&j指代的是i,j的地址 (“
”取地址操作符)
p1: 15744334504
p2: 15744334510 //p1,p2内存单元中分别存储的是i,j的地址
// * ip: 15744334504 /
ip中存储的是i的地址,因为这里“ip = p1;”将p1赋给*ip,而p1中存储的是i的地址 /
& * ip: 15744334520
ip: 15744334520 //这个就是
ip的地址。

例4

//例5
/#include<stdio.h>

void main()
{
int i = 5, j =6, k = 7;
int * p1 = &i, * p2 = &j;
int * * ip = &p1; //这里直接将&p1赋给* * ip,即将p1赋给* ip(就是将i的地址赋给* ip,由此说明* ip就是p1)

printf("* p1: %o\n", * p1);
printf("* p2: %o\n", * p2);
printf("* * ip: %o\n", * * ip);
printf("&i: %o\n", &i);
printf("&j: %o\n", &j);
printf("p1: %o\n", p1);
printf("p2: %o\n", p2);
printf("* ip: %o\n", * ip);
printf("ip: %o\n", ip);
printf("&* ip: %o\n", &* ip);

printf("/////////////////////////////////////\n");

// * ip = p2; //注意这里,由定义“int ip = &p1;”可得,“ip”表示的是变量“p1”,而变量“p1”指向的是变量i”(即“p1”的内存单元中存储的是变量“i”的地址)。然而我们这里将“p2”赋给“ip”,而变量“p2”指向的是变量“j”。因此,“ip”所指向的变量改变了,即p1所指向的变量改变了,即p1指向了p2所指向的变量(然而如果后面指针变量p2所向的变量改变,p1并不随p2改变,这与Python有很大的不同,见例6)//
printf("
p1: %o\n", * p1);
printf("* p2: %o\n", * p2);
printf("* * ip: %o\n", * * ip);
printf("&i: %o\n", &i);
printf("&j: %o\n", &j);
printf("p1: %o\n", p1);
printf("p2: %o\n", p2);
printf("* ip: %o\n", * ip);
printf("ip: %o\n", ip);
printf("&* ip: %o\n", &* ip);
}
//输出:* p1: 5
*p2: 6
**ip: 5
&i: 36752415064 //地址
&j: 36752415070
p1: 36752415064
p2: 36752415070
// * ip: 36752415064
ip: 36752415100
& * ip: 36752415100
/////////////////////////////////////
*p1: 6
*p2: 6
**ip: 6
&i: 36752415064
&j: 36752415070
p1: 36752415070
p2: 36752415070
// * ip: 36752415070
ip: 36752415100
& * ip: 36752415100

例5

//例6
/#include<stdio.h>

void main()
{
int i = 5, j =6, k = 7;
int *p1, *p2;
int **ip = &p1;
p1 = &i, p2 =&j;

printf("* p1: %o\n", * p1);
printf("* p2: %o\n", * p2);
printf("* * ip: %o\n", * * ip);
printf("&i: %o\n", &i);
printf("&j: %o\n", &j);
printf("p1: %o\n", p1);
printf("p2: %o\n", p2);
printf("* ip: %o\n", * ip);
printf("ip: %o\n", ip);
printf("&* ip: %o\n", &* ip);

printf("/////////////////////////////////////\n");

// * ip = p2;
printf("* p1: %o\n", * p1);
printf("* p2: %o\n", * p2);
printf("* * ip: %o\n", * * ip);
printf("&i: %o\n", &i);
printf("&j: %o\n", &j);
printf("p1: %o\n", p1);
printf("p2: %o\n", p2);
printf("* ip: %o\n", * ip);
printf("ip: %o\n", ip);
printf("&* ip: %o\n", &* ip);

printf("///////////////////////////////////////\n");
p2 = &k;
printf("* p1: %o\n", * p1);
printf("* p2: %o\n", * p2);
printf("* * ip: %o\n", * * ip);
printf("&i: %o\n", &i);
printf("&j: %o\n", &j);
printf("&k: %o\n", &k);
printf("p1: %o\n", p1);
printf("p2: %o\n", p2);
printf("* ip: %o\n", * ip);
printf("ip: %o\n", ip);
printf("&* ip: %o\n", &* ip);
}
//输出:*p1: 5
*p2: 6
**ip: 5
&i: 733256244 //地址
&j: 733256250
p1: 733256244
p2: 733256250
// * ip: 733256244
ip: 733256260
& * ip: 733256260
/////////////////////////////////////
*p1: 6
*p2: 6
**ip: 6
&i: 733256244
&j: 733256250
p1: 733256250
p2: 733256250
// * ip: 733256250
ip: 733256260
& * ip: 733256260
///////////////////////////////////////
*p1: 6
*p2: 7
**ip: 6
&i: 733256244
&j: 733256250
&k: 733256254
p1: 733256250
p2: 733256254
// * ip: 733256250
ip: 733256260
& * ip: 733256260

  1. 指针数组作main函数的形参
    指针数组的一个重要应用是作为main函数的形参。在以往的程序中,main函数的第一行一般写成这个形式:void main(); 实际上,main函数可以有参数,如:void main(int argc, char *argv[ ])。这里argc和argv就是main函数的形参。显然不可能在程序中得到。实际上实参是和命令一起给出的。也就是在一个命令行中包括命令名和需要传给main函数的参数。见例7.

//例7
/#include <stdio.h>
/#include <stdlib.h>

void main (int argc, char *argv[])
{
int i;

printf ("the number of argc is : %d\n", argc);
argc += 1;

for(i=1; i < argc; i++)
{
printf ("the argc of %d is : %s\n", i, argv[i]);
}
}
//the number of argc is : 1
the argc of 1 is : null

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容