理解C语言中指针的声明以及复杂声明的语法

时间:2022-06-30 22:20:41

昨天刚把《C程序设计语言》中“指针与数组”章节读完,最终把心中的疑惑彻底解开了。如今记录下我对指针声明的理解。顺便说下怎样在C语言中创建复杂声明以及读懂复杂声明

本文章中的内容參考自《C程序设计语言》

指针是什么就不具体说明了,用一句话来总结就是:“指针是一种保存变量地址的变量”。

1.声明简单的指针变量


先看看代码:

int i = 1;
int *p; //声明一个指向int类型数据的指针变量 p
p = &i; //&为取地址符,把变量i的地址赋值给指针 p
*p = 2; //此时 i 的值变成2了

这段代码声明了一个指针变量p。并把它指向变量i,通过*p能够訪问到变量i,并对i的值进行改动。如今对星号 * 的作用进行具体的解说。* 是一元运算符,它用在不同的地方将具有不同的作用。

1.1 星号 * 用于声明语句时的作用


上面的代码片段中的第2行代码“int *p;”就是星号 * 用于声明语句时的情况。对于指针的声明。我们首先要从 p 这里開始看起,这是C语言中“声明”的语法。以下会介绍到。

第一步:先看p的右边有没有其他符号(分号不算)。能够看到p的右边并没有符号。

第二步:看p的左边,在p的左边有一个星号 * 。关键的时候到了!在这里能够看到星号 * 作用于p上面。其产生的效果是:“声明变量 p 是一个指针 ”。

眼下为止。我们已经知道 p 是一个指针了,但还不知道该指针是指向什么类型数据的。

第三步:看星号 * 右边的类型说明符 int,在这里int的作用就是声明 p 指向的数据类型是int。至此。“int *p;”这句代码就全然解释完了。

注意。上面的 int 、* 这两个符号发挥作用是有先后的,并非组合在一起来发挥作用的。

先是 * 发挥作用:声明p是一个指针变量。然后是int发挥作用:声明p指向的数据类型是整型数据

1.2 星号 * 用于声明语句之外时作用

以上代码片段中,最后一句“ *p = 2; ”就是星号 * 用于声明语句之外时的作用。这句语句等效于“ i = 2;”。

用专业点的说法就是:假设指针p指向整形变量 i。那么在 i 出现的不论什么上下文中都能够使用 *p ,当 * 作用于指针变量p时,就是訪问指针变量p所指向的变量 i。

至此。已经说了怎样声明简单的指针变量,是不是认为非常easy呢?接下来将会依照复杂程度递增的顺序来介绍和指针有关的复杂声明

2.复杂声明和声明语法

2.1声明指向指针的指针变量

先看代码:

int i = 1;
int *p = &i; //声明指针变量p。p指向变量i
int **pp; //声明指针变量pp
pp = &p; //pp指向变量p,p是指针变量
**pp = 2; //此时 i 的值变成 2 了
//*(*pp) = 2;这个语句等效于上面的语句

代码段中的1、2行在上面已经介绍过了。如今主要介绍第2行之后的代码。

注意,这以下这两句是等效的,这是由于相似于 * 和++这种一元运算符遵循从右至左的结合顺序。

int **pp;   //声明方式1
int *(*pp); //声明方式2

如今開始解释声明方式2(和声明方式1是一样),同上面的简单声明一样。我们再次从变量名pp開始。

第一步:先看看pp右边有没有符号,能够看到pp的右边有一个右括号,而括号仅仅是强调结合顺序,所以不用管它。

第二步:看pp的左边,能够看到,pp的左边有一个星号 * (从右数起第一个星号),该星号的作用是:“声明变量pp是一个指针。此时,我们还不知道指针pp所指向的数据类型。并且把括号里面的 * 和 pp 两个符号都解释完了。如今看看括号外面的符号。

第三步:先看括号外面的右边,能够看到,括号外面的右边并没有符号。

第四步:看括号左边,这时。我们看到括号外面的左边有一个星号 * (从右数起。第二个星号 *),这个星号 * 的作用是:“声明指针变量pp所指向的数据类型是指针类型”。此时。我们已经知道了pp指向的数据类型是指针类型(即是代码片段中 p 的类型),但还不知道所指向的指针是指向什么类型数据的。比如,pp指向指针p,但却不知道p指向的是什么类型的数据。

第五步:看最左边的符号“int”,这个int的作用就是:声明pp所指向的指针所指向的数据类型是整型int。比如,pp指向指针p,如今我们知道了p指向的数据类型是int整型。

哈哈。是不是有点晕了,如今简单总结下:pp右边第一个星号 * 声明了pp是一个指针变量,第二个星号 * 声明了指针变量pp所指向的数据类型是指针类型,而类型说明符int则声明了pp所指向的指针指向的数据类型是int

看到这里。你可能会疑惑:一定要依照上面的步骤来解释声明吗?这是套路吗?

答:是的。

由于这是C语言中”声明“的语法,下一小节将会对该语法进行介绍。

之所以这么迟才介绍这个语法,是由于在用过后,会更easy理解它。

2.2 C语言中”声明“的语法

在这里。将会对声明的语法进行解说,为后面理解更加复杂的声明打基础。

在C语言中解释一个声明,要先从被声明的变量名開始解释。

并非从左到右,也不是从右到左解释,而是从中间開始。更准确来讲,是从被声明的变量名開始解释。

而声明总是由非常多符号和唯一的变量名相结合。这些符号和唯一的变量名结合就是声明符。

声明的形式为

”T D“的形式,当中 T代表类型,D代表声明符。

举个样例吧:

int *p;

int就是T,而*p就是D。

以下将以变量名p来对声明中用到的符号进行解释。

变量名p能够和非常多符号来结合成声明符,如[ ],(),*。

1.当p与符号 [ ] 结合时(结合在p的右边),符号 [ ]的作用就是声明变量p是一个数组类型[ ]里面的数字则决定了数组中元素的个数。如以下的声明代码:

int p[5];//声明变量p是一个整型数组。数组中有5个元素

须要注意的是,符号[ ]的优先级是比星号 * 的优先级高的。

2.当p与符号 ( )结合时(结合在p的右边)。符号( )的作用就是:声明p是一个函数。通过p()能够调用该函数,()中能够有參数列表或者无參数列表,如以下代码:

int p();//声明一个函数p,返回值由前面的int决定
int p(int a,int b); //声明一个带參数的函数p

相同。符号( )的优先级比星号 * 高。

3.当p与星号 * 相结合时(结合在左边),符号 * 的作用就是声明p是一个指针类型 。例如以下代码 :

int *p; //声明p是一个指针,该指针指向int类型数据

介绍完这三个符号后。能够继续介绍语法(套路)了。

在解释声明时,首先要决定声明的名字p是什么东西,而和p近期的符号则决定了p是什么东西。如以下声明:

int p();    //p是函数
int *p; //p是指针
int p[5]; //p是数组
int *p[5]; //p是数组。里面的5个元素为指向int类型的指针

这里的第4行代码要解释一下,由于[ ]的优先级比星号 * 高,所以[ ]先作用于p,故p是一个数组,如今我们知道p是一个数组了,但还不知道数组中的元素是什么类型,这时,就要看左边的星号 * ,星号 * 声明了数组中的元素是指针类型。

如今,我们知道了数组中的元素是指针类型,但还不知道那些指针是指向什么类型的,这时int发挥作用了。它声明了里面的指针是指向int类型数据的,所以这个声明的结果就是:声明了一个数组 ,数组有5个元素。每一个元素都是指向整型数据的指针

到这里,我们对这个语法(套路)有点头绪了!

原来解释声明就是要先从名字p開始,然后从p的右边開始看符号(由于优先级高的符号 [ ]和 ( ) 是放在右边的)。假设有符号,刚和p先结合。看完右边的符号(假设有的话)后,就决定了p是什么。这时。就到p左边的符号发挥作用了(左边要么是 * 。要么就什么都没有)。

最后发挥作用是则是类型说明符(由于它在最外面)。

总的来说。解释声明的套路就是不断问什么,然后从里往外看符号来解答什么的过程。说过无谓。再来看一段代码:

int *p();   //声明1,声明一个函数p,返回类型为指针类型
int (*p)(); //声明2,声明一个函数指针p,p指向一个函数

我们来依照套路来解释这两个声明

声明1:首先,要确定p是什么?从p右边的符号 ( ) 能够解得,p是一个函数。新的问题又来了,那函数p的返回值是什么类型?从p左边的星号 * 能够解得,函数p的返回值类型是指针类型。新的问题又来了,返回的指针指向的数据类型是什么啊?这时。依照套路,应该继续看外一层的右边(由于看符号的顺序为p的右左右左…,并且内层优先于外层),然而符号 ( ) 的右边没有符号了。转而看向外一层的左边。

这时发现外一层的左边是类型说明符int。因此解得,返回的指针指向的数据类型是int。整个声明就是:声明p为一个函数,函数的參数为空。函数的返回值为指针,指针指向的数据类型为int。

声明2:由于这个声明中,有个括号把星号 * 和 p包住了,所以 * 和 p属于内层。而括号里p的右边没有符号。故 * 和p先结合,则声明了p是一个指针。这回答了p是什么。新的问题来了,p指向的是什么?这时。内一层的符号看完了,继续看外一层的右边,外一层的右边是符号( ) ,则解得p指向的是一个函数。然后再看外一层的左边得。该函数的返回值是int类型。整个声明就是:声明p是一个指针。这个指针指向一个函数。这个函数的返回值为int

总结一下,解释声明的套路就是:先从最内层開始看符号。先从名字p的右边開始看,再到左边。

然后跳到外一层的右边開始,再到外一层的左边開始看。不断循环。直到没符号为止。

以下把这个套路应用到更加复杂的声明中去。

如以下这个声明:

char (*(*x())[])();

有没有头晕的感觉?不用怕,依照套路来非常easy的。

首先从最里面開始,x的右边是符号 ( ) ,所以x是一个函数。

再看x的左边,x的左边是一个星号 * ,所以 函数x的返回值类型为指针类型。继续跳到外一层的右边,发现外一层的右边是符号 [ ] 。所以指针指向的是一个数组。继续看左边,发现左边是一个星号 * ,所以数组中的元素的类型为指针类型。再看外一层的右边,发现符号 ( ),所以数组中的指针指向的是函数。最后看左边的类型说明符char,所以函数的返回值类型为char类型。整个声明就是:x是一个函数。函数的返回值类型是指针类型,这个指针指向的是一个数组,这个数组是指针数组(里面的元素是指针),数组中的指针是函数指针(指针指向函数),指针指向的函数的返回值类型是char类型。

再看这个声明:

char (*(*x[3])())[5];

该声明的结果为:x是一个数组。数组有3个元素。元素的类型为指针类型。这些指针都是函数指针,所指向的函数的返回值为指针 ,返回的指针指向数组,指向的数组有5个元素,元素的类型为char类型。

到此为止。我们已经学会了复杂声明的语法(套路)。这时我们也能够利用这个语法来声明我们想要的变量。

2.3 使用复杂声明

如今我们来声明一些复杂的声明。

比方,我们来声明一个函数x。函数x的返回值为指针类型,该指针指向一个数组。数组的元素类型为char

仅仅要按套路反过来即可了:

1. 函数x:

x()
  1. 函数x的返回值为指针类型: 。
*x()

3.该指针指向一个数组:

(*x())[]

4.数组的元素类型为char:

char (*x())[];

搞定!是不是非常easy?

这篇文章到这里就结束了。这是我的第一篇博客,假设有什么错误,请在评论中回复。

希望这篇文章能帮助到大家更好地理解C语言中的声明的语法。

理解C语言中指针的声明以及复杂声明的语法的更多相关文章

  1. 这样子来理解C语言中指针的指针

    友情提示:阅读本文前,请先参考我的之前的文章<从四个属性的角度来理解C语言的指针也许会更好理解>,若已阅读,请继续往下看. 我从4个属性的角度来总结了C语言中的指针概念.对于C语言的一个指 ...

  2. C语言中指针和数组

    C语言数组与指针的那些事儿 在C语言中,要说到哪一部分最难搞,首当其冲就是指针,指针永远是个让人又爱又恨的东西,用好了可以事半功倍,用不好,就会有改不完的bug和通不完的宵.但是程序员一般都有一种迷之 ...

  3. 【转载】理解C语言中的关键字extern

    原文:理解C语言中的关键字extern 最近写了一段C程序,编译时出现变量重复定义的错误,自己查看没发现错误.使用Google发现,自己对extern理解不透彻,我搜到了这篇文章,写得不错.我拙劣的翻 ...

  4. C语言中指针占据内存空间问题

    以前一直有个疑问,指向不同类型的指针到底占用的内存空间是多大呢? 这个问题我多次问过老师,老师的答案是"指向不同类型的指针占据的内存空间大小不同",我一直很之一这个答案,今天我就做 ...

  5. 理解C语言中几个常见修饰符

    写在前面 今天下午一个同事问「register」关键字是什么作用?噢,你说的是「register」啊,它的作用是……脑袋突然断片儿,我擦,啥意思来着,这么熟悉的陌生感.做C语言开发时间也不短了,不过好 ...

  6. C语言中指针和多维数组

    指针和多维数组 数组名是特殊的指针 数组是一个特殊的指针,多维数组也是更为复杂的数组,它们的关系是什么样的呢? 我们通过一个简单的例子来比较形象的了解指针和多维数组: int a[2][3]; 这是一 ...

  7. C语言中指针&ast;p&lbrack;N&rsqb;&comma; &lpar;&ast;P&rpar;&lbrack;N&rsqb;&comma;及&ast;&ast;p的区别

    在C语言编程中指针经常困扰着我们,但是若能灵活运用指针的话,将会使得我们编程变得更加轻松与高效.这里讲下*p[N], (*P)[N],及**p的区别,这也是之前经常困扰我的地方. 这三者的定义分别为: ...

  8. C语言中指针是什么?

    学习交流可加 微信读者交流①群 (添加微信:coderAllen) 程序员技术QQ交流①群:736386324 --- ==恶名昭著的指针究竟是什么== " 指针是一种保存变量地址的变量,在 ...

  9. 编程基础-c语言中指针、sizeof用法总结

    1.指针 学习 C 语言的指针既简单又有趣.通过指针,可以简化一些 C 编程任务的执行,还有一些任务,如动态内存分配,没有指针是无法执行的.所以,想要成为一名优秀的 C 程序员,学习指针是很有必要的. ...

随机推荐

  1. &lbrack;转&rsqb;Unicode utf8等编码类型的原理

    FROM:http://www.cnblogs.com/daxiong2014/p/4768681.html 1.ASCII码          我们知道,在计算机内部,所有的信息最终都表示为一个二进 ...

  2. 7&period; Swift 基于Xmpp和openfire实现一个简单的登录注册

    1. 基本步骤:首先导入Xmpp框架,配置环境 ->由于我们使用的是OC的Xmpp框架,再进行Swift开发时需要进行桥接. 具体方法就是创建一个基于c的.h的头文件,然后将我们需要编译OC的语 ...

  3. postsharp初体验

    首先,有必要先介绍下,什么叫做AOP(Aspect-Oriented Programming,面向切面编程).下图是百度的词条解释 用图来解释可能更直接了当些: ps:图片来自http://www.c ...

  4. C&num;实现在CAD图纸中插入另一个DWG图块的代码

    C#实现在CAD图纸中插入另一个DWG图块的代码 PromptPointResult ppr = ed.GetPoint("请选择插入点:"); Point3d pt = ppr. ...

  5. 原生js 实现的瀑布流

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  6. 基础算法-查找:线性索引查找(I)

    前面介绍的几种查找的算法都是基于数据有序的基础上进行的.但是在实际的应用中,很多数据集可能有惊人的数据量,面对这些海量的数据,要保证记录全部按照当中的某个关键字有序,其时间代价是非常昂贵的,所以这种数 ...

  7. ubuntu下php不能显示中文的问题的解决过程。

    在阿里的ECS上的ubuntu平台上成功的安装了apache2和php5与mysql,并进行了测试. 如图所示:

  8. leetcode之旅(9)-Reverse Linked List

    题目描述: Reverse a singly linked list. click to show more hints. Hint: A linked list can be reversed ei ...

  9. MySQL存储过程定义中的特性(characteristic)的含义

    MySQL的存储过程蛮啰嗦的,与MSSQL或者Oracle的存储过程相比,如果没有显式指定,他会隐含地指定一系列特性(characteristic)的默认值来创建存储过程 通常在使用图形界面工具进行存 ...

  10. 我的Java之旅 第四课 JAVA 语言语法 基础

    1  整型           int num = 1_000_000; //从java 7开始支持的语法 ,只是让人更易读,java编绎器会去除   2  字符串        一定不能使用==运算 ...