C指针复杂申明

合集下载

c语言的知识点,难点

c语言的知识点,难点

C语言的知识点和难点总结C语言是一种基础编程语言,广泛应用于系统软件、嵌入式系统、游戏开发等领域。

在学习C语言的过程中,我们会遇到一些知识点和难点。

下面,我们将对C语言的知识点和难点进行总结。

一、知识点:1.数据类型:C语言支持多种数据类型,包括整型、浮点型、字符型等。

这些数据类型的使用是C语言编程的基础,需要熟练掌握。

2.运算符:C语言提供了丰富的运算符,如算术运算符、关系运算符、逻辑运算符等。

理解并正确使用这些运算符是编写高效代码的关键。

3.控制结构:C语言中的控制结构包括条件语句(如if-else)、循环语句(如for、while)等。

掌握这些控制结构是实现程序逻辑的关键。

4.函数:函数是C语言的基本模块,用于实现特定的功能。

了解如何定义函数、调用函数以及传递参数是十分重要的。

5.指针:指针是C语言的特色之一,它允许我们直接访问内存地址。

理解指针的概念和用法对于深入学习C语言至关重要。

6.结构体与联合:结构体和联合是C语言中处理复杂数据结构的重要工具。

通过它们,我们可以组合不同类型的数据并进行操作。

二、难点:1.指针操作:由于指针直接涉及内存地址,因此对初学者来说可能较难理解。

掌握指针的基本概念、声明、初始化和使用是C语言学习的难点之一。

2.内存管理:在C语言中,程序员需要直接管理内存。

如何正确地分配和释放内存是避免内存泄漏和段错误的关键,也是学习C语言的难点。

3.深度递归:深度递归可能导致栈溢出或性能问题,因此在实际应用中需要谨慎处理。

理解递归原理并在合适的场景下应用是C语言学习的一个难点。

4.多线程编程:多线程编程涉及线程的创建、同步和通信等复杂概念,对于初学者来说可能较难掌握。

理解多线程的原理和应用是多线程编程的难点之一。

函数指针的定义

函数指针的定义

函数指针的定义函数指针,又称为函数引用,是指向函数的指针,它可以用来引用函数,从而使用函数指针来调用函数。

它们可以指向任何返回类型的函数,包括内联函数和扩展函数。

由于函数指针可以指向任何返回类型的函数,因此可以将它们用作动态链接,即当函数指针指向给定的函数时,调用函数指针就会调用该函数。

函数指针的一个主要用途是函数的封装,可以将函数指针作为函数参数传递。

C语言中的函数指针声明是一个比较复杂的知识点,它的声明格式如下:void (*ptr) (data type);其中,ptr函数指针的名称,data type函数指针所指向的函数的参数类型。

另外,函数指针也可以声明多个参数,它的声明格式如下:void(*ptr) (data type1, data type2, ...);其中,ptr函数指针的名称,data type1,data type2,...代表函数指针指向的函数参数类型。

当有了函数指针的声明后,接下来就可以初始化函数指针,初始化函数指针的常用格式如下:ptr = &functionName;该语句意思是将函数名称 functionName地址赋值给指针 ptr。

这样就可以通过指针 ptr用函数 functionName 了。

除了使用函数指针来调用函数外,C/C++言还有一种叫做函数指针数组的东西,它是一种特殊的数组,它存储的元素是函数指针,常见的声明格式如下:void (*arrPtr[n])(data type1, data type2, ...);其中,arrPtr函数指针数组的名称,n函数指针数组的元素的个数,data type1,data type2,... 代表函数指针指向的函数的参数类型。

函数指针数组的一个优点是它可以把多个函数名称存储到一个数组中,从而一次调用数组中的所有函数指针,从而实现代码的复用。

函数指针的另一个强大特性就是它可以实现回调函数,回调函数是指由调用程序自定义的一个函数,在某些情况下,调用程序可以使用函数指针传递给另一个函数,当函数处理完成后,被调用函数会调用另一个函数,也就是传递给它的函数指针指向的函数,这样就实现了回调函数的功能。

C语言声明详解

C语言声明详解

人们常说,C语言的声明太复杂了,的确,这也是C语言饱受批评的地方之一。

不过,笔者认为,真正要受到批评的不是语言本身,而是那些传播者。

传播者们通常都有一个共识:讲述要由浅入深。

作为原则,笔者并非要反对它,毕竟笔者对C语言的学习,也经历了相同的过程。

但是,由浅入深并不意味着一切从简,以偏盖全。

计算机语言不同于数学理论(虽然它的确根植于数学,与数学密不可分),数学理论是一种循序渐进的过程,后面的理论以前面的理论为基础。

但C语言归根说底,就是一堆语言规则而已,应该让学习者一开始就全面且详细地了解它,而不是象现在某些教材所做的那样,只说一部分,不说另一部分,以为这就是由浅入深了,实际上这是以偏盖全。

语言如此,声明作为C语言的一部分更是如此。

我们最常见到的对声明的描述是这样的:存储类别类型限定词类型标识符这种说明会给人们一种暗示:C语言的声明是静止的、死板的,什么声明都能够以这个为基础,往上一套就OK了。

事实真的如此吗?说句心里话,笔者也祈祷事实真的如此,这样世界就简单多了、清静多了。

但别忘了,这个世界总是让人事与愿违的。

实际上,C的声明的组织形式是以嵌套为基础的,是用嵌套声明组织起来的,并非象上面所述那么死板,存储类说明符一定得放在限定词前面吗?类型说明符一定要紧贴标识符吗?不!C标准从来没有这样说过!下面来看一看C89对声明的形式是如何规定的:声明:声明说明符初始化声明符表opt [opt的意思是option,可选]其中声明说明符由以下三项构成:声明说明符:存储类说明符声明说明符opt类型说明符声明说明符opt类型限定符声明说明符opt在这里,一个声明说明符可以包含另一个声明说明符,这就是声明的嵌套,这种嵌套贯穿于整个声明之中,今天我们看来一个非常简单的声明,其实就是由多个声明嵌套组成的,例如:static const int i=10, j=20, k=30;变量i前面就是声明说明符部分,有三个声明说明符:static const int,static是一个存储类说明符,它属于这种形式:static 声明说明符static后面的声明说明符就是const int,const是一个类型限定符,这也是个嵌套,它是由const 声明说明符组成,最后的int是一个类型说明符,到这里已经没有嵌套了,int就是最底的一层。

C_C++指针经验总结

C_C++指针经验总结

让你不再害怕指针前言:复杂类型说明要了解指针,多多少少会出现一些比较复杂的类型,所以我先介绍一下如何完全理解一个复杂类型,要理解复杂类型其实很简单,一个类型里会出现很多运算符,他们也像普通的表达式一样,有优先级,其优先级和运算优先级一样,所以我总结了一下其原则:从变量名处起,根据运算符优先级结合,一步一步分析.下面让我们先从简单的类型开始慢慢分析吧:int p; //这是一个普通的整型变量int *p; //首先从P 处开始,先与*结合,所以说明P 是一//个指针,然后再与int 结合,说明指针所指向//的内容的类型为int 型.所以P 是一个返回整//型数据的指针int p[3]; //首先从P 处开始,先与[]结合,说明P 是一个数//组,然后与int 结合,说明数组里的元素是整//型的,所以P 是一个由整型数据组成的数组int *p[3]; //首先从P 处开始,先与[]结合,因为其优先级//比*高,所以P 是一个数组,然后再与*结合,说明//数组里的元素是指针类型,然后再与int 结合,//说明指针所指向的内容的类型是整型的,所以//P 是一个由返回整型数据的指针所组成的数组int (*p)[3]; //首先从P 处开始,先与*结合,说明P 是一个指针//然后再与[]结合(与"()"这步可以忽略,只是为//了改变优先级),说明指针所指向的内容是一个//数组,然后再与int 结合,说明数组里的元素是//整型的.所以P 是一个指向由整型数据组成的数//组的指针int **p; //首先从P 开始,先与*结合,说是P 是一个指针,然//后再与*结合,说明指针所指向的元素是指针,然//后再与int 结合,说明该指针所指向的元素是整//型数据.由于二级指针以及更高级的指针极少用//在复杂的类型中,所以后面更复杂的类型我们就//不考虑多级指针了,最多只考虑一级指针.int p(int); //从P 处起,先与()结合,说明P 是一个函数,然后进入//()里分析,说明该函数有一个整型变量的参数//然后再与外面的int 结合,说明函数的返回值是//一个整型数据Int (*p)(int); //从P 处开始,先与指针结合,说明P 是一个指针,然后与//()结合,说明指针指向的是一个函数,然后再与()里的//int 结合,说明函数有一个int 型的参数,再与最外层的//int 结合,说明函数的返回类型是整型,所以P 是一个指//向有一个整型参数且返回类型为整型的函数的指针int *(*p(int))[3]; //可以先跳过,不看这个类型,过于复杂//从P 开始,先与()结合,说明P 是一个函数,然后进//入()里面,与int 结合,说明函数有一个整型变量//参数,然后再与外面的*结合,说明函数返回的是//一个指针,,然后到最外面一层,先与[]结合,说明//返回的指针指向的是一个数组,然后再与*结合,说//明数组里的元素是指针,然后再与int 结合,说明指//针指向的内容是整型数据.所以P 是一个参数为一个//整数据且返回一个指向由整型指针变量组成的数组//的指针变量的函数.说到这里也就差不多了,我们的任务也就这么多,理解了这几个类型,其它的类型对我们来说也是小菜了,不过我们一般不会用太复杂的类型,那样会大大减小程序的可读性,请慎用,这上面的几种类型已经足够我们用了.1、细说指针指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。

c语言二级指针详解

c语言二级指针详解

c语言二级指针详解C语言中,指针是一种重要的数据类型,它可以指向另一个变量或者数据结构中的一个元素,并且可以进行不同种类的操作(如解引用、赋值、比较、运算等)。

在C语言中,指针本身也是一个变量,它具有一个内存地址,并且其值就是指向的地址。

而指针变量可以通过指定自己的类型来控制指向的变量或者数据结构元素的类型。

在C语言中,指针本身也可以被指针所指向,这样的指针就被称为“二级指针”或者“指向指针的指针”。

二级指针在一些情况下比普通指针更加灵活,比如当我们需要在函数内部进行指针变量的修改或者返回值时,就可以使用二级指针。

1、指向指针的指针需要使用两个星号(**)来声明,例如:int **p;2、在函数中传递指向指针的指针时,需要将变量的地址传递给函数,而函数需要使用指向指针的指针来访问实际的指针变量。

3、在使用二级指针时,我们需要防止指针变量指向非法内存地址,否则会导致程序出现意想不到的错误。

二级指针是C语言中非常重要的概念,尤其在函数调用和指针变量的修改或返回值时,更是非常有用。

不过,我们在使用二级指针时需要额外注意指向内存地址的合法性,否则会导致程序出现异常。

二级指针是指指向指针对象的指针,即指针的指针,它可以通过间接的方式访问一个指针变量所指向的地址,这种间接的访问方式可以增加程序的灵活性,从而使程序更加易于理解和维护。

1、动态内存管理在C语言中,动态内存分配是通过调用malloc函数来实现的,而释放动态内存则需要使用free函数。

在使用malloc函数分配内存时,它会返回一个指针,指向分配的内存空间的首地址,我们可以将这个指针赋值给一个普通的指针变量,然后通过这个普通指针变量来访问分配的内存空间。

不过,当我们使用malloc来分配一个指针数组时,我们就需要使用二级指针来存储这个指针数组的首地址。

int **p = (int **)malloc(sizeof(int *) * 10);for (int i = 0; i < 10; ++i) {p[i] = (int *)malloc(sizeof(int) * 10);}以上代码中,我们使用了二级指针来存储指向指针数组的地址,然后使用循环语句来为每一个指针分配空间。

详解C++数组和数组名问题(指针、解引用)

详解C++数组和数组名问题(指针、解引用)

详解C++数组和数组名问题(指针、解引⽤)⽬录⼀、指针1.1指针变量和普通变量的区别1.2为什么需要指针1.3指针使⽤三部曲⼆、整形、浮点型数组2.1数组名其实是特殊的指针2.2理解复杂的数组的声明2.3数组名a、数组名取地址&a、数组⾸元素地址&a[0]、指向数组⾸元素的指针*p2.4对数组名以及取值符&的理解三、字符数组数组名⼀、指针1.1 指针变量和普通变量的区别指针:指针的实质就是个变量,它跟普通变量没有任何本质区别。

指针完整的应该叫指针变量,简称为指针。

是指向的意思。

指针本⾝是⼀个对象,同时指针⽆需在定义的时候赋值。

1.2 为什么需要指针指针的出现是为了实现间接访问。

在汇编中都有间接访问,其实就是CPU的寻址⽅式中的间接上。

间接访问(CPU的间接寻址)是CPU设计时决定的,这个决定了汇编语⾔必须能够实现问接寻⼜决定了汇编之上的C语⾔也必须实现简介寻址。

1.3 指针使⽤三部曲三部曲:定义指针变量、关联指针变量、解引⽤(1)当我们int *p定义⼀个指针变量p时,因为p是局部变量,所以也道循C语⾔局部变量的⼀般规律(定义局部变量并且未初始化,则值是随机的),所以此时p变量中存储的是⼀个随机的数字。

(2)此时如果我们解引⽤p,则相当于我们访问了这个随机数字为地址的内存空间。

那这个空间到底能不能访问不知道(也许⾏也许不⾏),所以如果直接定义指针变量未绑定有效地址就去解引⽤⼏平必死⽆疑。

(3)定义⼀个指针变量,不经绑定有效地址就去解引⽤,就好象拿⼀个上了镗的枪随意转了⼏圈然后开了枪。

(4)指针绑定的意义就在于让指针指向⼀个可以访问、应该访问的地⽅(就好象拿着枪瞄准且标的过程⼀样),指针的解引⽤是为了间接访问⽬标变量(就好象开枪是为了打中⽬标⼀样)int val = 43;int * p = &val; // &在右值为取值符cout << *p << endl;//输出43⼆、整形、浮点型数组前⾔在很多⽤到数组名字的地⽅,编译器都会⾃动地将其替换为⼀个指向该数组⾸元素的指针。

c语言指针的用法

c语言指针的用法

c语言指针的用法c语言是一种高级编程语言,它可以直接操作内存中的数据。

指针是c语言中一种特殊的变量,它可以存储另一个变量的地址,也就是内存中的位置。

通过指针,我们可以间接地访问或修改内存中的数据,从而实现更高效和灵活的编程。

本文将介绍c语言指针的基本概念、定义和初始化、运算和应用,以及一些常见的错误和注意事项。

希望本文能够帮助你掌握c语言指针的用法,提高你的编程水平。

指针的基本概念指针是一种数据类型,它可以存储一个地址值,也就是内存中某个位置的编号。

每个变量在内存中都有一个唯一的地址,我们可以用指针来记录这个地址,然后通过这个地址来访问或修改变量的值。

例如,假设有一个整型变量a,它的值为10,它在内存中的地址为1000(为了简化,我们假设地址是十进制数)。

我们可以定义一个指向整型的指针p,并把a的地址赋给p,如下所示:int a =10; // 定义一个整型变量a,赋值为10int*p; // 定义一个指向整型的指针pp =&a; // 把a的地址赋给p这里,&a表示取a的地址,也就是1000。

p = &a表示把1000赋给p,也就是让p指向a。

从图中可以看出,p和a是两个不同的变量,它们占用不同的内存空间。

p存储了a的地址,也就是1000。

我们可以通过p 来间接地访问或修改a的值。

指针的定义和初始化指针是一种数据类型,它需要在使用前进行定义和初始化。

定义指针时,需要指定它所指向的变量的类型。

初始化指针时,需要给它赋一个有效的地址值。

定义指针的一般格式为:type *pointer_name;其中,type表示指针所指向的变量的类型,如int、char、float等;pointer_name表示指针的名称,如p、q、ptr等;*表示这是一个指针类型。

例如:int*p; // 定义一个指向整型的指针pchar*q; // 定义一个指向字符型的指针qfloat*ptr; // 定义一个指向浮点型的指针ptr注意,在定义多个指针时,每个指针前都要加*号,不能省略。

函数指针typedef 模板

函数指针typedef 模板

函数指针typedef 模板1. 函数指针typedef的定义函数指针typedef可以理解为为函数指针类型起一个别名。

在C语言中,函数指针指向一个函数的位置区域,可以通过该指针调用相应的函数。

使用typedef可以使得函数指针类型的声明更加简洁、易读。

2. 函数指针typedef的语法在C语言中,函数指针typedef的语法如下所示:```ctypedef 返回类型 (*指针名称)(参数列表);```其中,返回类型表示指向函数的返回值类型,指针名称为函数指针的别名,参数列表表示函数的形参列表。

3. 函数指针typedef的使用函数指针typedef可以通过以下几个步骤来定义和使用:(1) 定义一个函数指针类型的typedef,指定返回类型和参数列表。

```ctypedef int (*FuncPtr)(int, int);```(2) 使用typedef定义的函数指针类型来声明函数指针变量。

```cFuncPtr ptr; // 声明一个名为ptr的函数指针变量```(3) 将函数的位置区域赋给函数指针变量,并通过该指针调用函数。

```cint add(int a, int b) {return a + b;}ptr = add; // 将add函数的位置区域赋给ptrint result = ptr(3, 5); // 通过ptr调用add函数,得到结果8```4. 函数指针typedef的优点使用函数指针typedef的好处在于可以提高代码的可读性和可维护性。

通过为函数指针类型起一个别名,可以使得函数指针的声明和使用变得更加清晰明了,减少了代码中函数指针类型的重复出现,同时也提高了代码的可维护性。

5. 函数指针typedef的应用场景函数指针typedef广泛应用于各种复杂的系统和框架中,特别适用于回调函数的定义和使用。

回调函数通常作为参数传递给其他函数,通过函数指针回调来实现特定的功能。

c语言指针教案

c语言指针教案

c语言指针教案以下是一个简单的C语言指针教案,供您参考:一、教学目标1. 理解指针的概念和作用。

2. 掌握指针的基本操作。

3. 了解指针在数组、函数中的应用。

二、教学内容1. 指针的概念和作用指针是一种变量,它存储了另一个变量的地址。

通过指针可以访问和修改变量的值。

指针在C语言中具有非常重要的作用,可以用于优化代码、实现复杂的数据结构等。

2. 指针的基本操作指针的基本操作包括指针的声明、赋值、解引用等。

指针的声明需要指定指针的类型,例如int p表示一个指向整数的指针。

指针的赋值即将变量的地址赋值给指针,例如p = &x表示将变量x的地址赋值给指针p。

指针的解引用即通过指针访问其所指向的值,例如p表示访问指针p所指向的值。

3. 指针在数组中的应用数组是一种特殊的数据结构,可以通过指针来访问和操作数组中的元素。

通过指针可以方便地实现数组的遍历、查找等操作。

4. 指针在函数中的应用函数是C语言中的基本单位,可以通过指针将参数传递给函数,从而实现更加灵活的函数调用方式。

同时,函数也可以返回指针,从而实现更加复杂的数据结构。

三、教学步骤1. 引入指针的概念和作用,通过示例演示指针的基本操作。

2. 讲解数组和函数中指针的应用,通过示例演示如何使用指针访问和操作数组中的元素、如何通过指针传递参数给函数等。

3. 总结指针的重要性和应用场景,强调指针操作的注意事项和安全问题。

4. 布置练习题,让学生自己动手编写程序来练习指针的使用。

5. 进行课堂互动和讨论,引导学生深入思考和理解指针的相关问题。

C语言指针知识点总结

C语言指针知识点总结

C语⾔指针知识点总结1.指针的使⽤和本质分析(1)初学指针使⽤注意事项1)指针⼀定要初始化,否则容易产⽣野指针(后⾯会详细说明);2)指针只保存同类型变量的地址,不同类型指针也不要相互赋值;3)只有当两个指针指向同⼀个数组中的元素时,才能进⾏指针间的运算和⽐较操作;4)指针只能进⾏减法运算,结果为同⼀个数组中所指元素的下表差值。

(2)指针的本质分析①指针是变量,指针*的意义:1)在声明时,*号表⽰所声明的变量为指针。

例如:int n = 1; int* p = &n;这⾥,变量p保存着n的地址,即p<—>&n,*p<—>n2)在使⽤时,*号表⽰取指针所指向变量的地址值。

例如:int m = *p;②如果⼀个函数需要改变实参的值,则需要使⽤指针作为函数参数(传址调⽤),如果函数的参数数据类型很复杂,可使⽤指针代替。

最常见的就是交换变量函数void swap(int* a, int* b)③指针运算符*和操作运算符的优先级相同例如:int m = *p++;等价于:int m= *p; p++;2.指针和数组(1)指针、数组、数组名如果存在⼀个数组 int m[3] = {1,2,3};定义指针变量p,int *p = m(这⾥m的类型为int*,&a[0]==>int*)这⾥,其中,&m为数组的地址,m为数组0元素的地址,两者相等,但意义不同,例如:m+1 = (unsigned int)m + sizeof(*m)&m+1= (unsigned int)(&m) + sizeof(*&m)= (unsigned int)(&m) + sizeof(m)m+1表⽰数组的第1号元素,&m+1指向数组a的下⼀个地址,即数组元素“3”之后的地址。

等价操作:m[i]←→*(m+i)←→*(i+m)←→i[m]←→*(p+i)←→p[i]实例测试如下:1 #include<stdio.h>23int main()4 {5int m[3] = { 1,2,3 };6int *p = m;78 printf(" &m = %p\n", &m);9 printf(" m = %p\n", m);10 printf("\n");1112 printf(" m+1 = %p\n", m + 1);13 printf(" &m[2] = %p\n", &m[2]);14 printf(" &m+1 = %p\n", &m + 1);15 printf("\n");1617 printf(" m[1] = %d\n", m[1]);18 printf(" *(m+1) = %d\n", *(m + 1));19 printf(" *(1+m) = %d\n", *(1 + m));20 printf(" 1[m] = %d\n", 1[m]);21 printf(" *(p+1) = %d\n", *(p + 1));22 printf(" p[1] = %d\n", p[1]);2324return0;25 }输出结果为:(2)数组名注意事项1)数组名跟数组长度⽆关;2)数组名可以看作⼀个常量指针;所以表达式中数组名只能作为右值使⽤;3)在以下情况数组名不能看作常量指针:- 数组名作为sizeof操作符的参数- 数组名作为&运算符的参数(3)指针和⼆维数组⼀维数组的指针类型是 Type*,⼆维数组的类型的指针类型是Type*[n](4)数组指针和指针数组①数组指针1)数组指针是⼀个指针,⽤于指向⼀个对应类型的数组;2)数组指针的定义⽅式如下所⽰:int (*p)[3] = &m;②指针数组1)指针数组是⼀个数组,该数组⾥每⼀个元素为⼀个指针;2)指针数组的定义⽅式如下所⽰:int* p[5];3.指针和函数(1)函数指针函数的本质是⼀段内存中的代码,函数的类型有返回类型和参数列表,函数名就是函数代码的起始地址(函数⼊⼝地址),通过函数名调⽤函数,本质为指定具体地址的跳转执⾏,因此,可定义指针,保存函数⼊⼝地址,如下所⽰:int funcname(int a, int b);int(*p)(int a, int b) = funcname;上式中,函数指针p只能指向类型为int(int,int)的函数(2)函数指针参数对于函数int funcname(int a, int b);普通函数调⽤ int funcname(int, int),只能调⽤函数int func(int, int)函数指针调⽤ intname(*func)(int,int),可以调⽤任意int(int,int)类型的函数,从⽽利⽤相同代码实现不同功能,实例测试如下,假设有两个相同类型的函数func1和func2:1int func1(int a, int b, int c)2 {3return a + b + c;4 }56int func2(int a, int b, int c)7 {8return a - b - c;9 }普通函数调⽤和函数指针调⽤⽅式及结果如下所⽰1 printf("普通函数调⽤\n");2 printf("func1 = %d\n", func1(100, 10, 1));3 printf("func2 = %d\n", func2(100, 10, 1));4 printf("\n");56 printf("函数指针调⽤\n");7int(*p)(int, int, int) = NULL;8 p = func1;9 printf("p = %d\n", p(100, 10, 1));10 p = func2;11 printf("p = %d\n", p(100, 10, 1));12 printf("\n");需要注意的是,数组作为函数参数的时候,会变为函数指针参数,即:int funcname( int m[] )<——>int funcname ( int* m );调⽤函数时,传递的是数组名,即funcname(m);(3)回调函数利⽤函数指针,可以实现⼀种特殊的调⽤机制——回调函数。

理解复杂的C C++声明

理解复杂的C C++声明

void * (*a[5])(char * const, char * const);
“右左法则”[重要!!!]
The right-left rule: Start reading the declaration from the innermost parentheses, go right, and then go left. When you encounter parentheses, the direction should be reversed. Once everything in the parentheses has been parsed, jump out of it. Continue till the whole declaration has been parsed.
上的误区,比如:
int* p,q;
第一眼看去,好像是p和q都是int*类型的,但事实上,只有p是一个指针,而q是一个最简单的int型变量。
我们还是继续我们前面的话题,再来看一个指针的指针的例子:
char **argv;
理论上,对于指针的级数没有限制,你可以定义一个浮点类型变量的指针的指针的指针的指针...
更喜欢第一种声明方式,因为它更突出了const修饰符的作用。
当const与指针一起使用时,容易让人感到迷惑。例如,我们来看一下下面的p和q的声明:
const int *p;
int const *q;
他们当中哪一个代表const int类型的指针(const直接修饰int),哪一个代表int类型的const指针(const直接修饰指针)?实际上,p和q都
typedef给你一种方式来克服“*只适合于变量而不适合于类型”的弊端。你可以如下使用typedef:

C-Point

C-Point

⏹摘录的别人的:⏹C语言所有复杂的指针声明,都是由各种声明嵌套构成的。

如何解读复杂指针声明呢?右左法则是一个既著名又常用的方法。

不过,右左法则其实并不是C标准里面的内容,它是从C标准的声明规定中归纳出来的方法。

C标准的声明规则,是用来解决如何创建声明的,而右左法则是用来解决如何辩识一个声明的,两者可以说是相反的。

右左法则的英文原文是这样说的:⏹The right-left rule: Start reading the declaration from the innermost parentheses, go right,and then go left. When you encounter parentheses, the direction should be reversed. Once everything in the parentheses has been parsed, jump out of it. Continue till the whole declaration has been parsed.⏹这段英文的翻译如下:⏹右左法则:首先从最里面的圆括号看起,然后往右看,再往左看。

每当遇到圆括号时,就应该掉转阅读方向。

一旦解析完圆括号里面所有的东西,就跳出圆括号。

重复这个过程直到整个声明解析完毕。

⏹笔者要对这个法则进行一个小小的修正,应该是从未定义的标识符开始阅读,而不是从括号读起,之所以是未定义的标识符,是因为一个声明里面可能有多个标识符,但未定义的标识符只会有一个。

⏹现在通过一些例子来讨论右左法则的应用,先从最简单的开始,逐步加深:⏹int (*func)(int *p);⏹首先找到那个未定义的标识符,就是func,它的外面有一对圆括号,而且左边是一个*号,这说明func是一个指针,然后跳出这个圆括号,先看右边,也是一个圆括号,这说明(*func)是一个函数,而func是一个指向这类函数的指针,就是一个函数指针,这类函数具有int*类型的形参,返回值类型是int。

解读C语言复杂声明

解读C语言复杂声明


蔚 _ — — 蔫

sz o ( + : ie f+ a) 一维数组 的大 小 : 4 X 4=
1 6l
s e f + a : 针的大 小 : I i o ( + )指 z * 4 sz o ( * + ) 字符的 大小 : 。 ie f* + a : 1 事实上 , 所有 复杂声 明都是 由各种 声 明嵌 套而 成 的 。构成 复 杂声 明的基 本 元素 是 : 类 型说 明符和 运算 符 。声 明所 包含 的类 型说 明 符 和运 算 符的 复杂程 度决 定 了理解 复 杂声 明 的难 易程度 。对于形 如 i t ( ( f n ) h r n + +u c ( a c p) 】的复杂声 明语句 , )5I 【 包含 了 c a 、it h r n 两 种 类 型说 明符 , 及( 】 以 ) 、+三种运 算符 , 令 许 多 C语 言的学 习者感 到非常难以 理解 , 更不 敢 问 津它 的使 用 。而准 确把握 复 杂指针 声 明 的关 键就 是理 清嵌 套结构 中各 种运 算 符组织 数据 的形 式 :
指针 是 C语 言中最重要 的概念之一 , 由指 针 构成 的复 杂声 明更 是高级 程 序设计 的重 要 组 成部 分 。然 而 , 在指 针 基础 上 理解 复 杂指 针 声 明 , 是 C 语 言教 学难 点 中的难 点 。我 却
们先 来看 一道 题 目 : c a ++ ) 】求 : h r (a 【J , 3l 4 sz o () ie fa szo (a ie f* ) szo (* ) i f a e * szo ( * a ie f* * ) szo ( * * ) ie f* * a 要判断括 号中变量 的长度 , 我们 首先要判 断变量的类型。其中 , a 是指 向 2 维指 针数组的指 针 ; +是 2 a 维指针数组 , 数组元素 为( X4 3 个) 指 向字符 的指针 ;

c语言结构体指针 typedef

c语言结构体指针 typedef

C语言中的结构体指针与typedef一、结构体指针的概念结构体是C语言中一种复合类型,它由若干数据成员组成,我们可以通过定义结构体变量的方式来使用结构体类型。

当我们需要在函数间传递结构体变量或在函数中动态创建结构体变量时,就需要使用结构体指针来进行操作。

二、结构体指针的定义和使用1. 定义结构体指针在C语言中,我们可以通过在结构体类型名称前加上"*"来定义结构体指针。

如果我们有一个名为Student的结构体类型,我们可以定义一个指向Student类型的指针变量ptr_stu如下所示:```struct Student {char name[20];int age;};struct Student *ptr_stu;```2. 结构体指针的初始化和使用我们可以通过使用取位置区域符""将结构体变量的位置区域赋给结构体指针,然后可以通过指针来访问结构体的成员变量。

假设我们有一个名为stu的结构体变量:```struct Student stu = {"John", 20};struct Student *ptr_stu = stu;printf("Name: s\n", ptr_stu->name);printf("Age: d\n", ptr_stu->age);```而在实际开发中,如果结构体类型名称较长或者需要频繁使用结构体指针,我们可以通过使用typedef来定义结构体指针类型,从而简化代码并提高可读性。

三、typedef关键字的介绍typedef是C语言中的关键字之一,它可以用来为一个已有的数据类型定义一个新的名称。

通过使用typedef,我们可以为复杂的数据类型定义更简洁、更易读的别名,从而提高代码的可维护性和可读性。

四、结构体指针的typedef用法1. 定义结构体指针类型我们可以通过使用typedef来定义结构体指针类型,从而可以直接使用新的类型名称来声明结构体指针变量。

C语言右左法则

C语言右左法则

C语言右左法则C语言所有复杂的指针声明,都是由各种声明嵌套构成的。

如何解读复杂指针声明呢?右左法则是一个既著名又常用的方法。

不过,右左法则其实并不是C 标准里面的内容,它是从C标准的声明规定中归纳出来的方法。

C标准的声明规则,是用来解决如何创建声明的,而右左法则是用来解决如何辩识一个声明的,两者可以说是相反的。

右左法则的英文原文是这样说的:The right-left rule: Start reading the declaration from the innermost parentheses, go right, and then go left. When you encounter parentheses, the direction should be reversed. Once everything in the parentheses has been parsed, jump out of it. Continue till the whole declaration has been parsed.这段英文的翻译如下:右左法则:首先从最里面的圆括号看起,然后往右看,再往左看。

每当遇到圆括号时,就应该掉转阅读方向。

一旦解析完圆括号里面所有的东西,就跳出圆括号。

重复这个过程直到整个声明解析完毕。

笔者要对这个法则进行一个小小的修正,应该是从未定义的标识符开始阅读,而不是从括号读起,之所以是未定义的标识符,是因为一个声明里面可能有多个标识符,但未定义的标识符只会有一个。

现在通过一些例子来讨论右左法则的应用,先从最简单的开始,逐步加深:int (*func)(int *p);首先找到那个未定义的标识符,就是func,它的外面有一对圆括号,而且左边是一个*号,这说明func是一个指针,然后跳出这个圆括号,先看右边,也是一个圆括号,这说明(*func)是一个函数,而func是一个指向这类函数的指针,就是一个函数指针,这类函数具有int*类型的形参,返回值类型是int。

C语言指针函数和函数指针详解

C语言指针函数和函数指针详解

C语言指针函数和函数指针详解C语言指针函数和函数指针详解往往,我们一提到指针函数和函数指针的时候,就有很多人弄不懂。

以下是店铺为大家带来的C语言指针函数和函数指针详解,希望能帮助到大家!一、指针函数当一个函数声明其返回值为一个指针时,实际上就是返回一个地址给调用函数,以用于需要指针或地址的表达式中。

格式:类型说明符 * 函数名(参数)当然了,由于返回的是一个地址,所以类型说明符一般都是int。

例如:int *GetDate();int * aaa(int,int);函数返回的是一个地址值,经常使用在返回数组的某一元素地址上。

int * GetDate(int wk,int dy);main(){int wk,dy;do{printf("Enter week(1-5)day(1-7) ");scanf("%d%d",&wk,&dy);}while(wk<1||wk>5||dy<1||dy>7);printf("%d ",*GetDate(wk,dy));}int * GetDate(int wk,int dy){static int calendar[5][7]={{1,2,3,4,5,6,7},{8,9,10,11,12,13,14},{15,16,17,18,19,20,21},{22,23,24,25,26,27,28},{29,30,31,-1}};return &calendar[wk-1][dy-1];}程序应该是很好理解的,子函数返回的是数组某元素的地址。

输出的是这个地址里的值。

二、函数指针指向函数的指针包含了函数的地址,可以通过它来调用函数。

声明格式如下:类型说明符 (*函数名)(参数)其实这里不能称为函数名,应该叫做指针的变量名。

这个特殊的指针指向一个返回整型值的函数。

指针的声明笔削和它指向函数的声明保持一致。

[C]C语言声明函数声明数组声明

[C]C语言声明函数声明数组声明

[C]C语⾔声明函数声明数组声明
理解复杂的C语⾔声明的⽅法是从声明中的名字开始,按照优先级顺序依次读取。

优先级规则如下:
1.声明中被括号括起来的部分
2.后缀操作符:
括号()表⽰这是⼀个函数,⽽⽅括号[]表⽰这是⼀个数组。

3.前缀操作符:
*表⽰“指向...的指针”
另外,对于有const或volatile关键字的声明,当const或volatile后⾯紧跟类型说明符(int, long等),那么它作为类型说明符。

其他情况
下,const或volatile作为⽤于它们左边紧邻的指针星号。

例,char *(* c[10])(int **p)意为,c是⼀个数组,它的元素类型是函数指针,其所指向的函数的参数为指向int指针的指针,返回值是⼀个指向char的指针。

int (*(*f)())[10]意为,f是⼀个指向函数的指针,该函数的返回值是⼀个指针,该指针指向⼀个⼤⼩为10的int数组。

Pointers on C, P258; Expert C Programming, P64.。

C语言声明语句

C语言声明语句

数量名称举例0或更多指针(pointer )*⼀个说明符(declarator)identifieridentifier[size]identifier(args)(declarator)0个或⼀个初始化器(initializer)= initial_value ⾄少⼀个类型限定符类型说明符存储类型类型修饰符void char short extern static register const volatile 0个或⼀个更多的说明符,declarator ⼀个分号;C 语⾔声明语句设计理念:C 语⾔的⼀个设计理念就是声明变量和使⽤变量的形式应该是⼀致的优点:声明变量和使⽤变量时的运算符优先级是相同的缺点:运算符的优先级是C 语⾔过度解析的部分之⼀术语:变量声明中使⽤到的符号的术语:(并不是所有的组合是合法的)关于struct 和union :类型说明符是:struct {stuff...}声明形式:struct {stuff...} s;tag :为了简写,可以在struct 后⾯加上结构体tag :struct struct_tag {stuff...},这样就声明了struct_tag 代表具体的类型集合{stuff...},之后的声明就可以使⽤struct struct_tag s;关于参数传递的两点说明:1. 某些书中会说"参数传递到调⽤函数的时候是从右到左压到栈中",这种说法是不对的。

参数传递的时候会尽可能使⽤寄存器,所以⼀个整数和⼀个只含有⼀个整数的结构体的传递⽅法是完全不同的,⼀个整数可能通过寄存器传递,结构体会通过栈传递2. 通常⼀个数组是不能直接通过赋值来传递整个数组的,或者被⼀个函数返回,但是通过把数组作为结构体的唯⼀⼀个成员就可以实现虽然union 具有和结构体类似的结构,但是它们有完全不同的存储⽅式结构体将每个成员存储到其前⼀个成员后⾯union 的所有成员都存储在相同的起始地址,所以不同的成员是相互覆盖的,同时只能有⼀个成员可以被存储union 的⼀个明显的问题就是存储了⼀种类型但是⽤另⼀种类型取的类型安全问题,Ada 语⾔主张在记录中存储说明字段来解决这个问题,但是C 语⾔依赖于程序员能够记住存了什么⽽不采取任何措施union 有两个⽤途:1. 节约空间2. 所有的成员有相同的存储空间⼤⼩的时候,就可以⽤不同的⽅式解析相同的⼆进制数据⽽不⽤显式的进⾏类型转换声明语句的解析:C 语⾔可以有⾮常复杂的声明语句⽽让⼈⽆法轻易的搞清楚到底定义了什么东西有两种解析⽅式:⽅式⼀:优先级法则1. 声明的解析从名称开始,然后按照优先级规则继续执⾏2. 优先级从⾼到低:1. 将声明的各个部分组合在⼀起的括号2. 后缀操作符:指明⼀个函数的"()"和指明数组的"[]"3. 前缀操作符:指明是"指向..."的星号3. 如果"const"或"volatile"关键字和⼀个类型说明符相邻,就应⽤到这个类型说明符;否则,如果应⽤到左边紧邻的"*"⽅式⼆:状态机规则1. 从最左侧的标识符开始,"identifier是" "identifier is"2. 如果右侧是"[]"就获取,"⼀个...的数组" "array of"3. 如果右侧是"()"就获取,"参数为...返回值为...的函数" "function returning"4. 如果左侧是"("就获取整个括号中的内容,这个括号包含的是已经处理过的声明,回到步骤25. 如果左侧是"const""volatile""*"就获取,持续读取左侧的符号直到不再是这三个之中的,之后返回步骤41. "const":"只读的" "read only"2. "volatile":"volatile" "volatile"3. "*":"指向..." "pointer to"6. 余下的就是基本数据类型举例:char *(*c[10])(int **p);1. 按照优先级规则解析:1. c是⼀个...数组---c[10]2. c是⼀个指向...的指针的数组---*c[10]3. c是⼀个指向参数为...的返回值为...函数的指针的数组---(*c[10])()4. c是⼀个指向参数为整数的指针的指针的返回值为...函数的指针的数组---(*c[10])(int **p)5. c是⼀个指向参数为整数的指针的指针的返回值为指向...的指针函数的指针的数组---*(*c[10])(int **p)6. c是⼀个指向参数为整数的指针的指针的返回值为指向char的指针函数的指针的数组---char *(*c[10])(int **p) 2. 按照状态机规则解析:1. c是...---c---1->22. c是⼀个...的数组---c[10]---2->33. c是⼀个指向...的指针的数组---*c[10]---3,4,5->44. c是⼀个指向...的指针的数组---(*c[10])---4->25. c是⼀个指向参数为int的指针的指针返回值为...的函数的指针的数组---(*c[10])(int **p)---2,3->46. c是⼀个指向参数为int的指针的指针返回值为...的函数的指针的数组---(*c[10])(int **p)---4->57. c是⼀个指向参数为int的指针的指针返回值为指向...的指针的函数的指针的数组---*(*c[10])(int **p)---5->68. c是⼀个指向参数为int的指针的指针返回值为指向char的指针的函数的指针的数组---*(*c[10])(int **p)---5->6实现程序:状态机可以实现为⾃动翻译程序:typedef和#define:1.宏定义的类型名和其他类型说明符⼀起执⾏定义,但是typedef只能使⽤它本⾝#define peach intunsigned peach i; /* works fine */typedef int banana;unsigned banana i; /* Bzzzt! illegal */2.typedef的类型会实施到每个说明符,但是宏定义不会#define int_ptr int *int_ptr chalk, cheese;// 结果为:int * chalk, cheese;导致chalk是int的指针类型,⽽cheese是int类型typedef char * char_ptr;char_ptr Bentley, Rolls_Royce;Bentley和Rolls_Royce都是char指针类型命名空间:C语⾔的命名空间1. 标签名,所有的标签名的命名空间2. tags,对于所有的结构体、枚举类和联合体的tag具有的命名空间3. 成员名称,对每个结构体、枚举类或联合体都有⾃⼰的成员命名空间4. 其他,其他名称的命名空间所以对声明:typedef struct baz {int baz;} baz;这样的定义是合法的:struct baz variable_1; /*这⾥baz是定义的类型名*/baz variable_2; /*这⾥baz是tag*/对于这样的定义:struct foo {int foo;int foo2;} foo;第⼀个foo是这个结构体的tag,第⼆个foo是⼀个结构体变量sizeof(foo)的结果是变量foo的⼤⼩,所以如果声明时这样的:struct foo {int foo;int foo2;} *foo;sizeof(foo)返回的就是4⽽不是8,如果想要⽤tag获取结构体的⼤⼩:sizeof(struct foo)——tag只有和struct关键字⼀起才起作⽤⽽如果这样定义:typedef struct foo {int foo;int foo2;} foo;那么就不能再⽤foo作为变量名,因为此时foo不再是tag⽽和变量有相同的命名空间参考:《expert C programming:deep C secrets》Chapter 3. Unscrambling Declarations in C。

悬浮指针c语言

悬浮指针c语言

悬浮指针c语言悬浮指针(Floating Pointers)是C语言中一种特殊的指针类型,它的概念和使用方法相对较为复杂,但却非常有用。

悬浮指针可以被用来处理一些特殊的数据结构,例如树、图等。

本文将介绍悬浮指针的基本概念、使用方法以及一些常见的应用场景。

悬浮指针是一种指向指针的指针,也就是说,它存储的是另一个指针的地址。

通过悬浮指针,我们可以间接地访问指针所指向的内容,而不必直接使用指针本身。

这种间接访问的方式使得悬浮指针在处理复杂数据结构时非常方便。

在C语言中,我们可以使用两个星号(**)来声明一个悬浮指针变量。

例如:```cint** floatPtr;```在上面的例子中,`floatPtr`是一个悬浮指针变量,它可以指向一个`int`类型的指针。

我们可以通过多级间接访问来获取到最终指向的值。

接下来,我们将通过一个简单的例子来演示悬浮指针的使用方法。

假设我们有一个存储学生成绩的二维数组,我们可以使用悬浮指针来对这个数组进行操作。

首先,我们需要声明一个二维数组和一个悬浮指针变量:```cint scores[3][4] = {{78, 89, 90, 87},{92, 88, 76, 81},{85, 79, 94, 90}};int** floatPtr;```接下来,我们可以将二维数组的第一行的地址赋值给悬浮指针变量`floatPtr`:```cfloatPtr = scores;```现在,我们可以通过悬浮指针来访问二维数组的元素。

例如,要访问第二行第三列的元素,我们可以使用以下语句:```cint element = *(*(floatPtr + 1) + 2);```在上面的语句中,`floatPtr + 1`表示指向二维数组的第二行,`*(floatPtr + 1) + 2`表示指向第二行第三列的元素,最后的`*(*(floatPtr + 1) + 2)`表示获取该元素的值。

除了上述的基本用法,悬浮指针还可以用于动态内存分配和链表等数据结构的处理。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

如何理解和应用C语言中的复杂声明曹定成(华中科技大学计算机科学与技术学院, 湖北武汉430074)摘要:讨论了正确理解复杂声明的含义以及正确使用复杂声明所说明的对象的方法。

讨论了各种基本类型指针,构成复杂声明的基本元素,以及类型说明符和数据类型名的优先级和结合性。

并以复杂声明char *(*(*f(char *(*para)(char *)))[2])();为例讨论了解释复杂声明的步骤和方法,给出了解释结果,并且给出了使用复杂声明的应用实例。

关键词:复杂声明;C语言;指针中图法分类号:TP312 文献表示码:AHow to Understanding and Using the ComplicatedDeclarations in CDingcheng Cao(College of Computer Sci. & Tech. Huazhong University of Science and Technology, Wuhan 430074, China) Abstract: In this paper, a method of correctly understanding the meaning of a complicated declaration and using the object in a complicated declaration are discussed. Various primary pointers, the basic elements in complicated declaration, and the precedence and the left-associativity of the operators and the type specifiers are also discussed. According to the complicated declaration char *(*(*f(char *(*para)(char *)))[2])(); the approach and the method of interpreting complicated declaration are introduced. Meanwhile, the application example of using complicated declaration is put forward.Key words: complicated declarations; C; pointer1 引言指针是C语言中的一个重要概念,也是C 语言的一个重要特色[1]。

以指针为基础的复杂声明是C 语言中的重要组成部分。

对于形如char *(*(*f(char *(*para)(char *)))[2])();的复杂声明语句,许多C语言的学习者都感到f的含义非常难以理解,更不敢问津f的使用。

的确,复杂声明是学习C语言的难点。

但是,准确理解复杂声明的含义也是提高C程序员素质的重要途径。

B.W.Kernighan 和D.M.Ritchie曾经说过:“毫无疑问,复杂声明的确产生于实践,但知道如何去理解它们以及在必要时知道如何去创建它们却是非常重要的[2]。

”可以这样说:对复杂声明的精确理解,以及创建、使用和驾驭复杂声明的熟练程度是衡量一个C 程序员C语言素质高低的重要指标之一。

如何才能正确理解复杂声明的含义?如何在理解复杂声明含义的基础上正确使用复杂声明所说明的对象?其方法是:首先,要对基本类型指针的理解打下扎实的基础;其次,在复杂声明的解释过程中要严格按照优先级和结合性来进行;然后才是在理解的基础上使用复杂声明。

2 基本类型指针在C语言中,称存储某个变量a的地址值的变量p为指针变量。

当指针变量p存储变量a的地址时,称p指向a。

在不产生二义情况下,往往称指针变量为指针。

指针类型是派生类型。

根据指针所指变量是字符型、整型、或浮点型变量,将指针称为字符指针、整型指针、或浮点指针。

如:int x=1,*pi=&x;就说明了pi是指向整型变量x的整型指针。

数组也可以用指针表示。

如:int a[5],*pa=a;它使指针pa指向一维数组元素a[0],pa是指向数组元素的指针。

如果用指针表示多维数组,则需要用到指向数组的指针。

如:int b[2][3],(*pb)[3]=b;此时pb是指向有三个元素的一维数组的指针,它指向b数组中行下标为0的行。

那么,pa++和pb++有什么区别呢?pa++使pa指向a[1],pa的值增加sizeof(int);而pb++使pb指向b数组中行下标为1的行,pb的值增加3*sizeof(int)。

由同类型指针可以构成指针数组。

如:int *p[3];说明p是有三个元素的整型指针数组。

即:指针数组p中的每个元素都是一个整型指针。

因此,如果有声明语句:int x=2,y=2,z=3;则:p[0]=&x; p[1]=&y; p[2]=&z;就使指针数组p中的元素分别指向整型变量x、y、z。

如果一个指针以某个函数的入口地址为其值,则该指针称为指向函数的指针,简称为函数指针。

如:int (*pf)(char *,int *);说明pf是一个函数指针,它所指向的函数有一个字符指针和一个整型指针为形参,且返回值为整型值。

如果有声明语句:int fun(char *a,int *b);并且fun有定义,则pf=fun就使函数指针pf指向了函数fun。

设pc,pi是已赋值的字符指针和整型指针,则通过(*pf)(pc,pi)或pf(pc,pi)就可以调用函数fun。

如果函数的返回值是指针类型的值,该函数就称为指针函数[3]。

所以,指针函数是返回值为指针值的函数。

如:int *fp(int a);就说明fp是一个整型指针函数,它返回一个整型指针值。

通过指针函数,可以使函数间接返回可以被调用函数处理的多个值。

字符指针、整型指针、浮点指针、指向数组元素的指针、指向数组的指针、指针数组、函数指针和指针函数都被称为基本类型的指针。

3理解复杂类型的关键构成复杂声明的基本元素是类型说明符和数据类型名。

理解复杂类型的关键是理解并正确运用类型说明符和数据类型名在解释过程中的优先级和结合性。

复杂声明中的类型说明符有:()、[]、*三种。

其中()用于说明函数类型以及改变说明的先后顺序;[]用于说明数组类型;*则用于说明指针类型。

数据类型名可以是int、char、float、double、void等基本类型名,也可以是用户自定义的构造类型。

在解释复杂声明时,要按照()、[]优先级最高,*次之,而数据类型名的优先级最低的顺序来解释。

当()和[]同时在复杂声明中出现时,就需要考虑类型说明符的结合性。

C语言规定,类型说明符()和[]的结合性是左结合,即按从左至右的顺序进行解释。

在具体的解释过程中,对复杂声明要按照优先级和结合性进行解释顺序的分解,确定解释的先后顺序,然后进行逐步分析,在每一步分析过程中要运用基本类型指针涉及的知识进行解释,最后归纳综合出复杂声明的含义。

以复杂声明char *(*(*f(char *(*para)(char *)))[2])();为例。

首先按照类型说明符和数据类型名的优先级和结合性对其进行分解得到:f → (char * (*)(char * para)) → * → [2] → * → () → * → char①②③④⑤⑥⑦① f与(char * (*para)(char *))作用后可以得出:f是一个函数。

char * (*para)(char *)是f函数的形参说明。

它的解释顺序是:para → * → (char *) → * → char。

即f 函数的形参para是一个函数指针,所指向的函数有一个字符指针的形参,并且返回值是字符指针值。

②与*作用后得出:f是一个指针函数。

即f函数的返回值是一个指针值。

③与[3]作用后得出:f是一个指针函数,其返回值是指向有两个元素数组的指针。

④与*作用后得出:f是一个指针函数,其返回值是指向有两个元素的指针数组的指针。

⑤与()作用后得出:f是一个指针函数,其返回值是指向有两个元素的函数指针数组的指针,函数指针数组中的指针元素所指函数无参。

⑥ 与*作用后得出:f 是一个指针函数,其返回值是指向有两个元素的函数指针数组的指针,函数指针数组中的指针元素所指函数无参,其返回值为指针值。

⑦ 与char 作用后得出:f 是一个指针函数,其返回值是指向有两个元素的函数指针数组的指针,函数指针数组中的指针元素所指函数无参,其返回值为字符指针值。

所以,上面的复杂说明说明f 是一个指针函数;其形参para 是一个函数指针,para 所指向的函数有一个字符指针的形参,返回值是字符指针值;并且,f 函数的返回值是指向有两个元素的函数指针数组的指针,函数指针数组中的指针元素所指函数无参,其返回值为字符指针值。

其物理含义可以由图1表示。

图1复杂声明char *(*(*f(char *(*para)(char *)))[2])();物理含义的图示4 复杂类型的应用要掌握复杂声明,就需要在理解复杂声明的基础上进一步使用复杂声明。

它可以进一步反过来强化对复杂声明的理解。

仍以char *(*(*f(char *(*para)(char *)))[2])();为例,讨论如何使用f 。

首先要构造f 函数的形参,其次要构造f 函数的返回值。

f 函数的形参是一个指向有字符指针形参的字符指针函数的函数指针。

因此在 main 函数中通过char *(*pf)(char *);声明了pf 为函数指针;同时,通过声明char * fun(char *s);和pf=fun;使函数指针pf 指向函数fun 。

这样,通过f(pf)就可以调用f 函数。

由于f 函数的返回值是指向有两个元素的函数指针数组的指针,因此需要声明一个二维函数指针数组a,在f 函数中通过char *(*(*pa)[2])();声明pa 是指向有两个元素的函数指针数组的指针,通过pa=a 就使pa 指向了二维函数指针数组a 。

同时,在f 函数中通过pa 向二维函数指针数组a 的各个元素进行赋值。

从a[0][0]开始,到a[2][1]为止,各个元素依次指向函数f00到f21。

通过return pa;将指向二维函数指针数组a 的指针值返回。

与此同时,在main 函数中通过p=f(pf);使p 指向二维函数指针数组a 。

在双重循环中通过(*p[i][j])()依次调用函数f00、f01、…、f20、f21。

也可以用p[i][j]()的形式来进行调用。

相关文档
最新文档