篇幅很长,博主呕心沥血整理o(╥﹏╥)o
- 地址和指针的概念
1)内存地址──内存中存储单元的编号
①计算机硬件系统的内存储器中,拥有大量的存储单元(容量为1字节)。
为了方便管理,必须为每一个存储单元编号,这个编号就是存储单元的“地址”。每个存储单元都有一个唯一的地址。
②在地址所标识的存储单元中存放数据。
注意:内存单元的地址与内存单元中的数据是两个完全不同的概念
2)变量地址──系统分配给变量的内存单元的起始地址
例.
int main()
{
int i,j=4,k=5;
scanf("%d",&i);
printf("i=%d j=%d k=%d\n", i,j,k);
return 0;
}
在程序运行时编译系统就为变量i按照它的类型分配了相应个存储单元的空间,
并将第一个单元的地址作为i这个变量的地址
3)变量值的存取──通过变量在内存中的地址进行
①直接访问──直接利用变量的地址进行存取
上例中scanf(“%d”,&i)的执行过程是这样的:
用变量名i作为索引值,检索符号表,找到变量i的起始地址2000;
然后将键盘输入的值(假设为3)送到内存单元2000和2001中。
此时,变量i在内存中的地址和值,如图1所示。
图 1 变量在内容从表示
2)间接访问──通过另一变量访问该变量的值
C语言规定:在程序中可以定义一种特殊的变量(称为指针变量),用来存放其它变量的地址。比如本节前面例子中的变量i_pointer,它存放了变量i的地址&i,则可以通过它来访问变量i。
3)两种访问方式的比较
两种访问方式之间的关系,可以用某人甲(系统)要找某人乙(变量)来类比。
一种情况是,甲知道乙在何处,直接去找就是(即直接访问)。
另一种情况是,甲不知道乙在哪,但丙(指针变量)知道,此时甲可以这么做:先找丙,从丙处获得乙的去向,然后再找乙(即间接访问)。
- 指针和指针变量的定义
(1)指针──即地址
一个变量的地址称为该变量的指针。通过变量的指针能够找到该变量。
(2)指针变量──专门用于存储其它变量地址的变量
指针变量i_pointer的值就是变量i的地址。指针与指针变量的区别,就是变量值与变量的区别。
(3)为表示指针变量和它指向的变量之间的关系,用指针运算符“*”表示。
- 指针变量的定义、引用和初始化
(1)指针变量的定义
指针变量与其他变量一样需要先定义后使用
定义指针变量的一般形式为
基类型 *指针变量名1,*指针变量名2,…,*指针变量名n;
例如:int *point_m; //point_m是指向int类型数据的指针变量;
double *point_a; //pont_a是执行double类型数据的指针变量
说明:
1)定义格式中指针变量前面的“*”
,表示定义的变量的类型为指针型变量,“*”
不是指针变量的一部分;
2)在定义指针变量时必须指定基类型。基类型可以是标准类型或是用户声明的类型。特别说明基类型是指针变量存放地址的变量的类型。
(2)指针的引用
指针变量定义过之后,可以通过它的名字引用,
切记指针变量的名字不应有`“*”`,
并且指针变量的值应该是它的基类型声明的变量的地址。
例:
int *point_m;
int m;
double a;
可以有point_m=&m;
不可以有:
*point_m=&m; 或 point_m=&a;
(3)指针的初始化
定义时为指针赋值的操作就是指针的初始化。例如有如下定义:
int m;
则可以在定义一个基类型为point_m的指针变量时为它赋初始值。即:
int *point_m=&m;
特别地有:
基类型 *指针变量=NULL; //NULL是一个ASCII码值为零的空指针常量。指针变量值若无NULL表示指针变量没有指向任何一个变量。
- 指针变量的基本操作
与其他变量一样指针也可以完成一些运算。
(1)赋值运算
格式:指针变量=指针表达式;
说明:
1)两侧变量与表达式的类型应该一致;
2)指针表达式可以是另一个指针变量,也可以是一个已经声明的变量的地址;
**特别注意:指针变量未赋值时不可以使用**
(2)取地址运算——&
格式:&变量
说明:式中的变量是除register类型之外的任何内存变量,其结果就是此内存变量在内存中的首地址;
来个题外话解释一下register:
函数变量的存储类型register,也叫寄存器
(不知道什么是寄存器?那见过太监没有?没有?其实我也没有。没见过不要紧,见过就麻烦大了。^_^
,大家都看过古装戏,那些皇帝们要阅读奏章的时候,大臣总是先将奏章交给皇帝旁边的小太监,小太监呢再交给皇帝同志处理。这个小太监只是个中转站,并无别的功能。
好,那我们再联想到我们的 CPU。CPU不就是我们的皇帝同志么?大臣就相当于我们的内存,数据从他这拿出来。那小太监就是我们的寄存器了(这里先不考虑 CPU的高速缓存区) 。数据从内存里拿出来先放到寄存器,然后CPU 再从寄存器里读取数据来处理,处理完后同样把数据通过寄存器存放到内存里,CPU 不直接和内存打交道。这里要说明的一点
是:小太监是主动的从大臣手里接过奏章,然后主动的交给皇帝同志,但寄存器没这么自觉,它从不主动干什么事。一个皇帝可能有好些小太监,那么一个 CPU也可以有很多寄存器,
不同型号的 CPU拥有寄存器的数量不一样。
为啥要这么麻烦啊?速度!就是因为速度。寄存器其实就是一块一块小的存储空间,只不过其存取速度要比内存快得多。进水楼台先得月嘛,它离 CPU很近,CPU一伸手就拿到数据了,比在那么大的一块内存里去寻找某个地址上的数据是不是快多了?那有人问既然它速度那么快,那我们的内存硬盘都改成寄存器得了呗。我要说的是:你真有钱!
虽然寄存器的速度非常快,但是使用 register修饰符也有些限制的:register变量必须是能被 CPU寄存器所接受的类型。意味着 register变量必须是一个单个的值,并且其长度应小于或等于整型的长度。而且 register变量可能不存放在内存中, 所以不能用取址运算符 “&”来获取 register变量的地址。
不知道你看懂没有,其实这个用的确实不是很多,除非你做单片机的编程!)
好~我们继续指针学习:
(3)取变量值运算——*
格式:*指针表达式
说明:
1)指针表达式应为有确定值了,
2)其作用是取得指针变量所存地址的变量的值。
例:int m=5;
int *point_m=&m;
则:*point_m 就是m的值5,即*point_m<=>m
(4)指针表达式与整数相加、减
格式:指针表达式+n 或 指针表达式-n
说明:
1)格式中n为有确定值的整数;
2)指针表达式+n的值是一个地址值,可以通过:
指针表达式+指针表达式指向的变量类型长度*n计算。
3)其实际意义为内存中指针表达式上面(-)或下面(+)第n个同类型的存储空间的地址。
4)此运算形式用在指针表达式为某一连续存放同类型数据时有实际意义,比如数组。
5)自增和自减运算
格式:
自加: 指针变量++ 或 ++指针变量
自减: 指针变量-- 或 --指针变量
说明:指针变量自加自减结果是使指针变量指向下一个(++)或前一个(–)同类型的内存空间,即指针变量的值为下一个或上一个同类型存储空间的首地址。此运算用在指针变量指向连续区域时有意义,特别是数组中。
(6)同类型指针变量相减运算
格式:指针表达式1-指针表达式2
说明:
1)两个指针表达式应为相同类型;
2)结果是两个指针表达式之间数据元素的个数。
(7)关系运算
格式:指针表达式1 关系运算符 指针表达式2
说明:
1)两个指针表达式类型应该相同;
2)比较结果按照两个指针表达式1的地址值以及关系运算符的作用判定,结果为成立1,不成立0.
(8)空指针
在没有为指针变量赋值之前,它存储的值是不定的。可能是操作系统程序在内存中占据的地址空间的某个地址,也可能是某一常驻内存的系统应用程序占据的地址空间中地一个地址,…,因此对没有赋值的指针变量的使用是很危险的。现在常用的C语言集成环境一般均会在遇到这种操作时强制终止程序,以保护系统安全。为了避免这种问题,通常给指针变量赋初始值0,并把值为0的指针变量称为空指针变量,它表示指针变量不指向任何地方。
格式: 指针变量=NULL ; 或 指针变量=0;或 指针变量=‘\0’;
- 指向简单变量的指针变量
指向简单变量的指针变量的用法及作用:
(1)基本概念
指向简单变量的指针变量就是存储简单变量地址的指针变量,也就是存放非连续开辟区域中的零散定义的变量的地址的指针变量。在我们前面学习中,就是存放非数组元素类变量的地址的指针表里。
(2)指向简单变量的指针变量的用法
指向简单变量的用法在上面
(3)指向简单变量的指针变量的作用
将简单变量的地址存放在指针变量中,其主要目的就是为了实现 间接访问。
指向简单变量的指针变量作为函数参数
将简单变量的地址存放在指针变量中,其主要目的就是为了实现 间接访问。这种间接访问一般通过函数调用实现。方法是将简单变量的地址作为实参,将指针变量作为形式参数来实现。具体看如下实例:
void swap(int *pa, int *pb) //调用时指针变量pa,pb分别存储main中的变量a,b的地址
{ int *p;
*p=*pa; //*pa 为pa指针变量指向的变量,即main中的a,通过这样的方式实现间接访问
*pa=*pb;
*pb=*p;
}
先看主函数:
int main()
{ int a,b; //定义的a,b为简单变量
scanf("%d,%d",&a,&b);
if(a<b)
swap(&a,&b); //a,b两个简单变量的地址作为实参
printf("\n%d,%d\n",a,b);
return 0;
}
在此例中,函数swap通过形参的指针变量pa,pb获得的main中变量a,b的地址,达到在swap中访问另一函数中变量的目的。
指向数组元素的指针变量
指向数组元素的指针变量就是将数组元素的地址赋值给指针变量,以达到通过指针变量间接访问数组元素的目的,这样的指针变量我们也称为“一级指针”变量。
由于数组元素与简单变量一样,因此定义和使用方式也相同。定义一个指向数组元素的指针变量的方法,与以前介绍的指向变量的指针变量相同。
数组占据连续的存储空间,因此可以通过指向数组元素的指针变量来快速访问批量数据中的各个元素。
1)指向一维数组元素的指针变量
一维数组名字表示数组的首地址,即数组中第一个数组元素的地址,
通常可以借助指针变量的运算达到访问全部元素的目的。
例如利用下面方式访问一维数组中的全部元素:
int i, a[10]; // (定义a为包含10个整型数据的数组)
int *p; // (定义p为指向整型变量的指针变量)
p=a; //此语句与p=&a[0]等价
for( i=1 ; p<a+10 ; p++,i++)
//p++向数组连续区域自上向下一次访问
*p=2*i-1;
// 通过间接访问方式为指针变量p指向的数组元素a[0]-a[9]赋值
应当注意,如果数组为int型,则指针变量的基类型亦应为int型 。
如下图:
2)指向二维数组元素的指针变量
二维数组的物理结构在内存中是一列纵队,与一维数组一样,通过存放二维数组元素的指针变量的赋值和移动,也可以访问到全部的所有元素,此种方法可以帮助我们理解数据在计算机中的存储。
int i,j,a[3][3] ,*p;
p=&a[0][0];
for(i=1;p<&a[0][0]+3*3;i++,p++)
*p=i;
上面这段程序也可以通过下面这段程序实现:
int i,j,a[3][3] ,*p;
p=&a[0][0];
for(i=1;i<=3;i++)
for(j=1;j<=3;j++,p++)
*p=i*j;
如果要输出数组中全部元素的值,上面两段程序都可以通过下面程序段实现,前提是下面程序段执行前,两段程序都应使指针变量再重新回归到存放数组中第一个元素的地址。即:p=&a[0](第一段)或p=&a[0][0];(第二段)
输出数组元素结果的程序段:
for(i=1;p<&a[0][0]+3*3;i++,p++)
printf("%d ",*p);
完整的二维数组赋值及输出的程序为:
指向数组元素的指针变量作为函数参数
数组名与指向数组元素的指针变量(一级指针变量)均可以作为函数的参数。
(1)一维数组数组名作函数参数,实参与形参的对应关系见下表:
说明:
1) 需要注意的是无论实参是数组名,还是指针变量,在C语言里都是“值传递”一种方式。但是因为实参的值类型不一样,传递给形参后效果也不一样。
2)因为数组名与指针变量的值本身都是地址,传递给形参时也是地址。这样的结果形参与实参是共用地址空间的,这样就可以在子函数中通过形参来完成对实参的间接访问。这样的方式可以有效提高代码编码效率,进而实现程序的有效重复利用和增加程序的可读性。为开发更大规模程序提供了条件。
(2)一级指针变量与一维数组的不同表达
若有声明:int *p ; int a[10]; 则:
1)数组名是指针(地址)常量,代表数组集合内存的首地址(第一个元素地址)
2)若有p=a; 则 p+i 是a[i]的地址&a[i];
3) 数组元素的表示方法有多种:
①下标法
若有p=a; 则 p[i] <=> a[i]
② 指针法
若有p=a; 则 *(p+i) <=> *(q+i)
4 ) 形参若为数组,实质上是指针变量,即 int p[ ] <=> int *p
5) 指针变量在与数组使用上有一些类同,但是意义不同。当 int *p;一个一级指针变量时,编译系统只为它开辟一个存储空间,大小由编译系统确定,在codeblocks 13-16中均为4个字节,且不受存储变量的类型影响。即若还有 char pc;那么pc与p均占据4个字节。但是 int a[10],系统则开辟出10个存储空间,共410个字节的存储单元.
利用一个子函数将数组中的元素颠倒。
void inverse(int *x, int n)
//x获得实参的值,得到了数组的首地址
{ int t,*ph,*pt,*pm,m=(n-1)/2;
ph=x; pt=x+n-1; pm=x+m;
for(;ph<=pm;ph++,pt--)
//指针在数组元素存储空间中移动
{ t=*i; *i=*j; *j=t; }
//此处交换值
}
int main()
{ int i,a[10],*p=a;
for(i=0;i<10;i++,p++)
scanf("%d",p);
p=a;
inverse(p,10); //存放数组首地址的指针变量作为实参
printf("The array has been reverted:\n");
for(p=a;p<a+10;p++)
printf("%d",*p);
return 0;
}
指向二维数组行指针变量
上面我们了解到二维数组是一个二级地址。二维数组名字是一个二级指针。
下面以二维数组为例说明一下多维数组的指针。
以一个具体的二维数组int a[3][4] 为例说明。
(1)对二维数组的理解
在C语言中,二维数组a可以被看作是一个只有3个元素的一维数组,即a[0]、a[1]、a[2]。而这三个元素每一个又是一个包含4个元素的一维数组。
数组在内存中是连续存储的,a是二维数组的名字,它代表整个二维数组的首地址,也就是二维数组第0行的首地址,那么a+1就是把a看作一维数组时下一个元素a[1]的地址,即二维数组第1行的首地址,有了上面的理解,那么a作为二维数组的名字,实际上是一个二级指针就容易理解了。
(2)利用指向元素的指针(即列指针)处理二维数组
因为二维数组元素是按行存放在,地址是连续的。用列指针处理二维数组,实际上,就是将二维数组按行排列,作一维数组处理。若如上面定义,二维数组中的元素a[i][j]可以表示为*(*(a+i)+j)
。有指向简单变量的指针变量p,定义为int *p;的形式,那么p可以赋值为p=a[0];或p=&a[0][0];,而不能写成p=a;
。见图1.
图1 二维数组二级指针及数组元素的关系
3)指向固定长度一维数组的指针变量
这种类型的指针就是专门应用在对二维数组的访问上,其定义格式如下:
数据类型 (*标识符)[整型常量表达式];
说明:
① 数据类型是所定义的指针所要指向的二维数组的类型;标识符代表一个指针变量的名字;整型常量表达式与所指向的二维数组的列数值相同。
② 这种定义说明指针变量不是指向单个变量的指针变量,而是指向一个长度固定为二维数组列数的数组的,即它指二维数组的行,它的移动是以二维数组的一个行为单位的,因此,本质上是二级指针变量。
例如,若有前面定义的3行4列的a数组,如定义了:int (*p)[4];,则p与数组名a是同级的,可以赋值为p=a;,p+1就是a数组第1行的首地址了
③ 需要特别注意的是,a是相当于常量,值不可更改,而二级指针变量pa是变量,其值可以根据需要而改变。
(4)二级指针举例
找出所有同学中有一门以上成绩不及格的学生
#include <stdio.h>
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; //flag作为是否有不及格科目的标志
for(i=0;i<4;i++)
if(*(*(p+j)+i)<60) flag=1;//j 不同行代表不同的学生
if(flag==1)
{ printf("No.%d fails,his scores are:\n",j+1);
//输出不及格同学的位置
for(i=0;i<4;i++)
printf(″%5.1f″,*(*(p+j)+i));
printf(″\n″);
}
}
}
- 指针与字符串
(1)字符串的表示形式
在C语言中没有字符串变量,表示字符串常用的两种表示形式。
① 字符数组。
例如 char str[]=”I am Chinese.”;
str数组按照字符串的字符个数+1开辟内存单元。
②和字符指针
例如,char *p_str=”I am Chinese.”;
指针变量p_str同其他指针变量一样开辟一个四字节存储空间。
(2)字符指针与字符数组的区别
① 字符数组是由若干个元素组成的,每个元素占用内存一个字节的存储单元,其值都是一个字符;而字符指针变量只存有字符串的首地址,并不是存储了整个字符串,其他字符的访问要通过字符指针的移动来实现;
② 定义完字符数组后,不可以将字符串赋给字符数组名,例如有char str[20]; 那么str=”student”;是不允许的。但是若有char *ps; 则ps=“student”;是允许的,它表示把字符串"student"的首地址,即’s’字符存放的地址赋值给指针变量ps。
在C语言中,字符串常量存储在内存的静态区域,而指针数组在动态区域开辟内存,因此可以通过字符数组元素的访问改变字符数组元素中存放的值,但是通过指向字符串的指针变量不能改变字符串中字符的值。即同前定义的ps,若有*(ps+1)='s';
是非法的。
③ 数组在定义和编译时分配内存单元,而指针变量定义后必须要通过初始化或赋值之后,才可以使用,否则它指向一个不确定的内存段,冒然使用会破坏程序。
④ 字符指针变量的值可以改变,但字符数组名代表的是数组的首地址,这个地址由编译系统分配,是不可改变的。
(2)指针与字符串举例子
①完成字符串拷贝函数的功能:
void main()
{ void copy_string(char *from,char *to);
char *a=″I am a teacher .″;
char *b=″you are a student .″;
printf("string a=%s\n stringb=%s\n″,a,b);
printf("copy string a to string b:\n ");
copy_string(a,b);
printf("\n string a=%s\n string b=%s\n",a,b);
}
void copy_string(char *from,char *to)
{
for(;*from!='\0',from++,to++)
*to=*from;
*to='\0';
}
② 输出字符串
#include <stdio.h>
#include <stdlib.h>
char *returnStr()
{
char *p="hello c";
//试试此处改为:char p[]="hello c";会如何?
//改为:static char p[]="hello c";呢?
return p;
}
int main()
{
char *str=NULL; //一定要初始化,好习惯
str=returnStr();
printf("%s\n", str);
return 0;
}
要求:分析题中加粗部分的原因。
- 指针数组 与 指向 指针的 指针变量
指针变量可以与其它变量一样作为数组元素,如果一个数组中的元素是由指针变量构成,那么这个数组就是指针数组。其定义格式如下:
数据类型 *数组名[ 整型常量表达式 ];
指针数组一般用于存放若干个字符串的首地址。
例如 char *p[]={"China","Russia"," Japan,"the United States of America"," France"," UK"};
上面定义了6个指针变量构成的指针数组,每一个都存放了括号中字符串的首地址。如果访问字符串,可以用指针数组元素来实现。
指向指针的指针变量:
指针变量同其它变量一样也占用内存空间,我们可以将简单变量的地址存入指针变量,也可以将指针变量的地址存入其它的指针变量,这就是指向指针的指针,它定义格式如下:
数据类型 **变量名;
指向指针的指针变量可以存放指针变量的地址,也可以存放指针数组的首地址。
例: char *p[]={"China","Russia"," Japan,"the United States of America"," France"," UK"};
char **pp=p; pp为&p[0],因为p[0]为指针,所以pp为二级指针。
指针数组作为main()函数的参数
指针数组作为main()函数的参数的形式为:
main( int argc , char *argv[] ) { }
main函数的参数是从命令行得到的。启动程序的最基本方式是在操作系统命令状态下通过键盘输入命令。操作系统根据命令名查找相应的可执行文件,把它装入内存并执行。命令行就是为启动应用程序输入的表示命令的行。虽然现在许多操作系统采用图形界面,执行命令时通过鼠标点击图标或菜单项输入,但命令行仍然存在于图标或菜单的定义中。
main函数的参数argc的值是命令行中参数的个数,字符指针数组argv中存放的是命令行中各个空格分隔的参数(字符串)的首地址。在执行程序前,main函数的两个参数被自动给值,这两个参数的名字任意给定,一般习惯上分别用argc和argv来表示。
例:main函数参数——命令行参数的使用
#include <stdio.h>
#include <stdlib.h>
char *returnStr()
{
char *p="hello c";
return p;
}
int main(int argc,char *argv[])
{
int i;
char *str=NULL; //一定要初始化,好习惯
str=returnStr();
printf("%s\n", str);
for(i=0;i<argc;i++)
printf("%s\n" ,argv[i]); //输出命令行中输入的字符。
getchar();
return 0;
}
命令行运行结果:
- 动态存储的基本概念及常用分配函数
(1)动态存储的概念
用数组可以存放批量数据,但是数组使用时首先要确定数组的长度,从而在内存中开辟连续的存储空间,而经常却用不了那么多空间,且连续存放数组元素需要大块的空间,这样常常需要占据过大内存空间。对于比较大的软件,浪费内存会使程序运行效率降低。
动态存储分配的内存是根据需要随时开辟的。运行程序时,需要多少就分配多少,且不需要连续存放结构体变量,因此不会造成内存空间的浪费。为了实现内存的动态分配,C语言提供了一些只有在程序执行后才开辟和释放内存的函数。
(2)动态存储分配的函数
malloc()函数
函数原型:void *malloc(unsigned size);
malloc(size)函数在内存的动态存储区中分配一个长度为size的连续空间。此函数的值(返回值)是一个指针,为该分配区域的起始地址。如果此函数未能成功地执行,则返回值为0。
需要注意的是malloc函数返回的指针为通用指针,void类型,在实际使用时要根据开辟空间存放数据的类型利用强制转换来确定指针类型。
例:char *ps=(char *)malloc(20);
此方法开辟出20个byte的内存空间后,把首地址赋值给一个保存字符类型的指针变量,这样可以通过p访问到开辟空间中任何一个存储单元。也可以向这个空间中利用p赋值,比如scanf("%s",ps);
calloc( )函数
函数原型:void *calloc(unsigned n ,unsigned size);
calloc(n,size)函数功能是在内存的动态区存储中分配n个长度为size的连续空间。函数返回分配区域的起始地址,如果分配不成功,则返回0。
同malloc函数一样,返回的地址类型也是void 的,使用时需要转换为相应的类型。calloc开辟出的连续多个固定大小的地址空间,与一维数组在内存的分配类似。
比如int *p=(int *)calloc(10,sizeof(int));
此方法动态开辟出10个int类型的一维数组,可以用p的移动访问不同的数组元素。
free( )函数
函数原型:void free(void *p);
free§函数的功能是:释放由p指向的内存区。p是最近一次调用calloc或malloc函数时返回的值。
常用此函数收回不需要的内存空间。
- 指针与函数
返回指针值的函数
(1)返回指针值函数的声明
函数的值可以是基本数据类型,还可以是指针类型,返回指针值的函数定义格式如下:
类型标识符 *函数名(参数表)
{
函数体
}
说明:其他与自定义函数声明相同,只是在函数名前加“*”
,表示此函数返回的是一个地址值。类型标识符要与返回地址指向的变量类型一致。
例:编写函数返回下面字符串中长度最长的字符串。
本题目求第一个最长的字符串。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * longChar(char *ps[],int n)
{
char **p,*pl;
//p是一个二级指针,遍历字符指针ps中各个字符串。
//ps是指针数组,ps是二级指针
int l=0;
for(p=ps;p<ps+n;p++)
if(l<strlen(*p)) //*p是当前行字符串的地址
{
pl=*p;
l=strlen(*p);
}
return pl;
}
int main()
{ char *pl,
*p[]={"China","Russia","Japan","U.S.A.","France","U.K."};
pl=longChar(p,6);
printf("the longest is %s\n",pl);
return 0;
}
指向函数的指针
(1)函数指针的概念及声明
1)基本概念
在电子计算机系统中,除了要存储程序中的数据,还要存储程序。数据存储在数据区,程序存储在代码区。C语言程序是由函数构成的,不同的函数占据内存中不同的存储区域。每个函数在代码区的起始位置就是函数的地址,即首地址,也称为函数的入口地址。
同数组一样,函数的名字可以代表这个函数的首地址,也一样可以把这个函数的首地址赋值给指针变量,这样可以通过这个指针变量访问函数,这样的指针被称作指向函数的指针。
2)指向函数的指针变量的定义:
类型说明符 (*指针变量名)(函数形参表);
说明:
① 类型说明符是指向函数的指针变量所要指向的函数所返回值的类型;
② 函数参数表可以只写参数的类型;
③ 指向函数的指针变量是存放函数入口地址的,即使用时可以将一个函数的名字赋值给它;
④ 指向函数的指针的加减无意义。
例有如下定义:int (*p_fun)(int ,int );
如果max是一个求两个整数中最大值的函数,则可以将p赋值为:p=max;。
(2)用指向函数的指针变量调用函数
调用格式:(*指针变量)(实参表);
(3)函数指针作为函数的参数
指向函数的指针变量同样可以作为函数的参数,这样可以实现函数地址的传递,从而提高函数的通用性。
例 函数指针的应用案例-利用函数指针变量调用不同函数。
说明:
1)main函数中三个调用函数的语句中是三个不同函数名作为实参,传给process函数的形 参fun,fun是一个函数指针变量。哪个实参传给它什么函数名字,完成对相应函数名的调用。
2)此种情况可以用作多程序的扩充上。后续添加新的功能,可以利用新编写子函数,对原有的程序不会造成大的改变和影响。
最后!!!
**
- 指针数据类型总结
**
完结撒花o(* ̄︶ ̄*)o
转载:https://blog.csdn.net/qq_45899321/article/details/105593979