`
bencode
  • 浏览: 109236 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

C/C++中复杂的申明

    博客分类:
  • C++
阅读更多
昨天一朋友(估计要考二级了)问我:  int * a[];  这玩意儿到底是指针还是数组.  我告诉他, 这是数组, 里

面放的是 指针. 不过我怕他又问相似的, 所以就告诉他"读"的方法


我想可能会对C,或者C++的初学者有用, 所以就发在这里了. 高手请不要笑哦!


先来几个简单的


int a;      // 一个整形

int * a;    // 一个指针, 批向一个整形 (整形指针)

int * a();  // 一个函数, 反回一个整形指针

int * a[10];  // 一个数组, 里面存放着整形指针

int (*a)();  // 一个指针, 指向一个函数, 该函数返回整形

int (*a)[];   // 一个指针, 指向一个数组, 数组里放着整形


上面的问题不大哦, 下面先给出读的方法

从左向右看, 找到第一个标识符, 上例中就是 a
  1.先往右看, 如果是 [..] 那么 读作"a 是一个数组", 接下来的东西,就是数组元素的类型,和大小了 
    如果是 "(...)"  那么就是一个函数, 剩下的就是描述函数的参数和返回值了
  2.再往左看..., 如果前缀是 * 那么读作 "a 是一个指针", 接下来分析指向什么.


一个一个来, 有点幼稚哦


int * a();  // 从左向右看, 找到a, 再向右看, 是(), 那么"a是一个函数", 
            // 参数? 无, 返回值? int *, 哦, 是一个整形指针

int * a[10];  // 从左向右看, 找到 a, 再向右看, 是 [], 那么 "a 是一个数组"
              // 大小? 10, 类型? int *, 还是整形指针

int (*a)();  // 找到a, 被括号括住, 只能向左看, 是 *, 那么 "a 是一个指针"
            // 指向什么? 去掉分析过的部分, int XXX(), 哦, 是一个函数

int (*a)[10];  // 同样, "a 是一个指针", 
               // 指向什么? 去掉分析过的部分是? int XXX[10], 指向一个数组



来几个复杂一点的.

int * * (*a)();


从左向右看, 找到第一个标识符, a , 被括号括住了, 往左看, 是 *, 读作"a 是一个指针"

指向什么? int ** XXX(); 哦, 是一个函数

参数是? 空

返回值: int **, 哦~~

合起来就是: a 是一个指针, 该指针指向一个函数, 这个函数返回一个指针(返回的这个指针指向一个整形指

针)


再来一个:

char *(*c[10])(int **p);             // 这个例子来自于Expert C Programming


一眼看过去想晕

没事.

从左到右找到了第一个标识符, c, 再往右看, 是[], 读作 "c 是一个数组" 

数组的元素是什么

先去掉分析过的部分是 char *(*XXX)(int **p)

哦, XXX处开始, 往右看不下去, 往左看, 是*,  那么 "数组的元素是一个指针", 指向什么呢?

再去掉分析过的部分, char *XXX(int **p);  到这一步基本上一眼就能看出了, 就不多废话了

原来是指向一个函数: 这个函数的参数是 int **p, 返回值是 char *


合起来就是: c是一个数组, 这个数组大小是 10, 这个数组里面存放着 指针, 是一个函数指针, 这个函数

指针的参数是 int **p, 返回值是 char *

呵呵。 很容易吧!


等等, 加入const 好像更晕

"const在指针左边修饰类型, 在指会右边,修饰指针"

const int * a;  // 指针指向的整形是 const的
int * const a;  // 指针a 是 const的



声明中还可以加typedef哦

一般是

typedef xxxxxxxxxxxxx;

xxxx 的读取方法和上面的一模一样, 但仅仅引入一个新的名字,而不是为变量分配空间

要读的话, 可以读作“a 表示一个...”, 而不是 "a 是一个...."


用 typedef 可以让我们轻松好多, 可以让我们一眼看出申明,或定义的东西

上面看过的这个复杂的东西:char *(*c[10])(int **p);

可以变成这样

typedef char * (*fun_ptr)(int **p);   //fun_ptr 表示一个函数指针, 用上述规则看

那么上面的东东就是:
fun_ptr c[10];      // 一眼就能看出来了,里面是 fun_ptr


最后一个例子:

void (*signal(int sig, void(*func)(int)))(int);   // 这个例子来自于Expert C Programming


从左往右看, 找到 signal, 再往右看, 是(...)   "signal 是一个函数"


参数是什么? 看括号里面的 ( int sig, void(*func)(int) )

             有两个参数, 第一个是 int, 第二个是  void (*func)(int), 是一个函数指针

返回值是什么? 先去掉分析过的部分, 变成 void (*XXXX)(int)

            返回值是一个函数指针, 看,上面的第二个参数一样


合起来就是: signal是一个函数, 参数有两个, 一个是int ,还有一个是 函数指针
                                返回值是一个函数指针



当然。typedef 后会比较直观



typedef void (*func_ptr)(int);    //给函数指针一个名字

func_ptr signal(int, func_ptr);   // 现在一看就明白了









分享到:
评论
4 楼 justshare 2009-07-01  
不过,仔细想了想数组与指针的区别,觉得前面的回答还是不严谨
数组与指针的主要区别在于:数组在声明的时候就要分配存储空间,但指针不用。
补充:
如果int *a[size]它确实是数组;
但如果int *a[],那么它即是数组又是指针;
==================================================
3 楼 justshare 2009-07-01  
看了这遍文章之后,觉得里面有些写得不够严密,随便举个例子吧

int * a[10];  // 一个数组, 里面存放着整形指针 
按照你的理解,a是一个数组,但我认为它即是数组,又是指针
void writelines(char *str[], int n) {
  int i;
  for (i = 0; i < n; i++) {
       printf("%s\n", str[i]);  //这是数组的写法,编译器把它作为数组来处理
  }
  for(i=0; i<n; i++) {
       printf("%s\n", *str++);  //这是指针的写法,如果它仅仅是数组的话,这样写明显是错误的,但在这里编译器把它作为指针来处理
  }
}

2 楼 raof01 2008-09-17  
http://blog.chinaunix.net/u/12783/showart_378340.html
1 楼 luolonghao 2008-09-04  
呵呵,不错

相关推荐

    复杂函数申明解析

    在C或C++编程语言中,函数声明的解析尤其是复杂声明的解析对于初学者和经验丰富的程序员都可能是个挑战。本文将带领读者逐步解析C/C++中的复杂函数声明,包括使用typedef、const关键字以及函数指针的高级用法,并...

    C_与C++中的异常处理.pdf

    ### C与C++中的异常处理 #### 一、异常和标准C对它的支持 ##### 1.1 异常分类与定义 异常处理是程序设计中处理错误和非预期行为的一种重要机制。根据作者Robert Schmidt的观点,异常可以分为多种类型,包括但不...

    C++函数手册+(LibraryFunctions)

    C++函数手册+(LibraryFunctions) 是一份详细的编程资源,主要关注C++标准库中的函数以及相关的算法和C库。这份手册对于深入理解C++编程语言,特别是如何有效地使用标准模板库(STL)和C库功能,具有重要的参考价值。...

    c++笔试面试宝典2009

    与之相对,malloc和free属于C/C++标准库函数,仅负责内存的分配与释放,无法自动调用构造和析构函数,这使得它们在处理非内部数据类型对象时显得力不从心。 二、数组与指针的精细管理:delete与delete[]的微妙差别 ...

    摩托罗拉C++面试题

    13.C也可以通过精心封装某些函数功能实现重用,那C++的类有什么优点吗,难道仅仅是为实现重用。 并不仅仅是这样的。 OOD,OOP从根本上改变了程序设计模式和设计思想,具备重大和深远的意义。 类的三大最基本的特征:...

    本人转载 在此申明 语法树 c 实现 四则运算语法树

    在C++中实现这样的语法树,我们需要理解几个关键概念:解析、抽象语法树(AST)以及如何用C++编程语言来表示和操作这个树。 首先,解析是将输入的字符序列(例如,一个四则运算表达式)转换成有意义的结构,如语法...

    plsqldev803(内含注册码)

    PL/SQL(Procedural Language/SQL)是一种过程化语言,属于第三代语言,它与C、C++、Java等语言一样关注于处理细节,可以用来实现比较复杂的业务逻辑。它允许SQL的数据操纵语言和查询语句包含在块结构(block_...

    PLSQL Developer v7.rar

    PL/SQL(Procedural Language/SQL)是一种过程化语言,属于第三代语言,它与C、C++、Java等语言一样关注于处理细节,可以用来实现比较复杂的业务逻辑。它允许SQL的数据操纵语言和查询语句包含在块结构(block_...

    PLSQL+Developer+v8.0.2+附注册机.part2.rar

    PL/SQL(Procedural Language/SQL)是一种过程化语言,属于第三代语言,它与C、C++、Java等语言一样关注于处理细节,可以用来实现比较复杂的业务逻辑。它允许SQL的数据操纵语言和查询语句包含在块结构(block_...

    PLSQL+Developer+v8.0.2+附注册机.part1

    PL/SQL(Procedural Language/SQL)是一种过程化语言,属于第三代语言,它与C、C++、Java等语言一样关注于处理细节,可以用来实现比较复杂的业务逻辑。它允许SQL的数据操纵语言和查询语句包含在块结构(block_...

    VisualC++基础入门教程-第1课:程序框架.pdf

    《Visual C++基础入门教程-第1课:...通过Visual C++,我们可以利用这些基础知识构建更复杂、功能丰富的桌面应用。继续深入学习,你将掌握更多的Windows API函数和MFC框架,从而能够开发出更具交互性和实用性的软件。

    C语言FAQ 常见问题列表

    o 3.5 在 C 中是否有模拟继承等面向对象程序设计特性的好方法? o 3.6 我遇到这样声明结构的代码: struct name { int namelen; char namestr[1];}; 然后又使用一些内存分配技巧使 namestr 数组用起来好像有多个...

    extern用法详解

    在C++环境下使用C函数的时候,常常会出现编译器无法找到obj模块中的C函数定义,从而导致链接失败的情况,应该如何解决这种情况呢?答案是C++语言在编译的时候为了解决函数的多态问题,会将函数名和参数联合起来生成...

Global site tag (gtag.js) - Google Analytics