c语言求余数解读啊

我学习C语言的时候,遇到的一个问题就是EOF。
它是end of file的缩写,表示"文字流"(stream)的结尾。这里的"文字流",可以是文件(file),也可以是标准输入(stdin)。
比如,下面这段代码就表示,如果不是文件结尾,就把文件的内容复制到屏幕上。
  while ((c = fgetc(fp)) != EOF) {
    putchar (c);
很自然地,我就以为,每个文件的结尾处,有一个叫做EOF的特殊字符,读取到这个字符,操作系统就认为文件结束了。
但是,后来我发现,EOF不是特殊字符,而是一个定义在头文件stdio.h的常量,一般等于-1。
  #define EOF (-1)
于是,我就困惑了。
如果EOF是一个特殊字符,那么假定每个文本文件的结尾都有一个EOF(也就是-1),还是可以做到的,因为文本对应的ASCII码都是正值,不可能有负值。但是,二进制文件怎么办呢?怎么处理文件内部包含的-1呢?
这个问题让我想了很久,后来查了资料才知道,在Linux系统之中,EOF根本不是一个字符,而是当系统读取到文件结尾,所返回的一个信号值(也就是-1)。至于系统怎么知道文件的结尾,资料上说是通过比较文件的长度。
所以,处理文件可以写成下面这样:
  while ((c = fgetc(fp)) != EOF) {
    do something
这样写有一个问题。fgetc()不仅是遇到文件结尾时返回EOF,而且当发生错误时,也会返回EOF。因此,C语言又提供了feof()函数,用来保证确实是到了文件结尾。上面的代码feof()版本的写法就是:
  while (!feof(fp)) {
    c = fgetc(fp);
但是,这样写也有问题。fgetc()读取文件的最后一个字符以后,C语言的feof()函数依然返回0,表明没有到达文件结尾;只有当fgetc()向后再读取一个字符(即越过最后一个字符),feof()才会返回一个非零值,表示到达文件结尾。
所以,按照上面这样写法,如果一个文件含有n个字符,那么while循环的内部操作会运行n+1次。所以,最保险的写法是像下面这样:
  int c = fgetc(fp);
  while (c != EOF) {
    c = fgetc(fp);
  if (feof(fp)) {
    printf("\n End of file reached.");
  } else {
    printf("\n Something went wrong.");
除了表示文件结尾,EOF还可以表示标准输入的结尾。
  while ((c = getchar()) != EOF) {
    putchar(c);
但是,标准输入与文件不一样,无法事先知道输入的长度,必须手动输入一个字符,表示到达EOF。
Linux中,在新的一行的开头,按下Ctrl-D,就代表EOF(如果在一行的中间按下Ctrl-D,则表示输出"标准输入"的缓存区,所以这时必须按两次Ctrl-D);Windows中,Ctrl-Z表示EOF。(顺便提一句,Linux中按下Ctrl-Z,表示将该进程中断,在后台挂起,用fg命令可以重新切回到前台;按下Ctrl-C表示终止该进程。)
那么,如果真的想输入Ctrl-D怎么办?这时必须先按下Ctrl-V,然后就可以输入Ctrl-D,系统就不会认为这是EOF信号。Ctrl-V表示按"字面含义"解读下一个输入,要是想按"字面含义"输入Ctrl-V,连续输入两次就行了。
C语言学习随笔记之EOF用法
C语言中的EOF笔记
对于EOF是指文件的结束符,是一个宏定义.
对于键盘输入来说,getchar()只有在遇到文本结束标记(ASCII编码为26)时才会返回EOF,其它情况都会返回一个输...
C语言中EOF是什么意思?
C语言中EOF是什么意思?
C语言怎么使用EOF
在命令行中输入多行数据,最后以EOF结束时,如何输入EOF呢?
首先在最后一行结束后输入ENTER键,再输入ctrl+z,再输入时ENTER键即可。...
C语言中EOF的应用
C语言中EOF的应用
日 星期四 13:58
1.5.1. 文件复制
借助于getchar 与putchar 函数,可以在不了解其它输入/输出知识...
EOF是end of file的缩写,表示&文字流&(stream)的结尾。这里的&文字流&,可以是文件(file),也可以是标准输入(stdin)。
EOF不是特殊字符,而是一个定义在头文...
C语言中的EOF
EOF是指文件的结束符,是一个宏定义
借助于getchar 与putchar 函数,可以在不了解其它输入/输出知识的情况下编写出数量惊人的有用的代码。最简单的例子就是把输入一次一个字符地复制到输...
C语言中EOF的意思
EOF 是一个宏 ,一般定义为-1。
1.EOF用来判断文件结束的标记(end of file) 用在文件操作中,可以查下msdn 看它的定义:EOF is returned by an I/O r...
EOF的含义与scanf的返回值
我学习C语言的时候,遇到的一个问题就是EOF。
它是end of file的缩写,表示&文字流&(stream)的结尾。这里的&文字流&,可以是文件(file),也可以是标准输入(stdin)。
关于c语言中EOF用法的理解
作者:zhangxinlin
转载请注明,原文链接:http://blog.csdn.net/zhang/article/details/8760636
首先看一下EOF...
希望本文可以对初学C的朋友提供一点帮助,也希望能和其他朋友进行交流。其中理解不对的地方若能得到指正和建议,本人将不胜感激
大师级经典的著作,要字斟句酌的去读,去理解。以前在看K&R的Th...
没有更多推荐了,c语言的程序解读_百度知道
c语言的程序解读
#include&stdio.h&main(){inta,b,k=4,m=6,*p=&k,*q=&m;a=p==&m;b=(*p)/(*q)+7;printf(&%d\n&,a);printf(&%d\n&,b);}为什么输出的结果是07程序是什么意思...
#include &stdio.h& main() {
int a, b, k=4, m=6, *p=&k, *q=&m;
b=(*p)/(*q)+7; printf(&%d\n&, a); printf(&%d\n&, b); }为什么输出的结果是 0 7
程序是什么意思
答题抽奖
首次认真答题后
即可获得3次抽奖机会,100%中奖。
a=0看a的赋值表达式,a=p==&m,也就是a=(p==&m),而p==&m的值是0,所以a=0。2.b=7看b的赋值表达式,b=(*p)/(*q)+7,(*p)/(*q)=4/6=0,所以b=0+7=7。
为你推荐:
其他类似问题
您可能关注的内容
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。在我上大学的时候就流传着这样一个超牛的C程序,只用三行代码就能计算π到小数点后800位,还有的地方开玩笑说是外星人写的,的确是牛的不得了。那个时候大家一起研究都搞不懂,昨天看了一篇文章解释这段代码,今天自己试验了很久,终于弄明白了,所以记下来和大家一起交流。
这段C代码是这样的:
#include "stdio.h"
long a=10000, b, c=2800, d, e, f[2801],
void main() {
for( ;b-c; ) f[b++] =a/5;
for( ; d=0, g=c*2; c-=14,printf("%.4d",e+d/a),e=d%a)
for(b=c; d+=f[b]*a,f[b] =d%--g,d/=g--,--b; d*=b) ;
我把解释这段代码的文章附在最后面了,作者叫王聪,看他的博客是很高手的样子。我的主要分析都是从他的文章里看到的。谢谢这位高手!这么多年的疑惑终于解开了。
从我的角度来理解,我不习惯把for语句拆开变成while来分析,我觉着现在这个样子就挺好的,当然个别语句还是要调整一下。我觉得说明以下几个问题就能完全搞明白了:算法(两点)、错误(两点)、其他(四点)。
1、π的计算公式
π/2=1+1!/3!!+2!/5!!+3!/7!!+...+k!/(2*k+1)!!+...
这个公式不记得了,好像是高数里学过。注:5!=1*2*3*4*5,5!!=1*3*5
2、公式的程序实现(数组存储余数)
把上面的公式做一下展开和调整
π/2 = 1 + 1!/3!! + 2!/5!! + 3!/7!! + ... + k!/(2*k+1)!!
= 1 + 1/3 + (1*2)/(3*5) + (1*2*3)/(3*5*7) + ... + (1*2*...*k)/(3*5*...*(2k+1))
= 1 + 1/3 + (1/3)*(2/5) + (1/3)*(2/5)*(3/7) + ... + (1/3)*(2/5)*...*(k/(2k+1))
= (1/3)*(2/5)*...*(k/(2k+1)) + ... + (1/3)*(2/5)*(3/7) + (1/3)*(2/5) + 1/3 + 1
= (k/(2k+1))*...*(2/5)*(1/3) + ... + (3/7)*(2/5)*(1/3) + (2/5)*(1/3) + 1/3 + 1
= (((((k/(2k+1)+1)*((k-1)/(2(k-1)+1)+1)*...)*3/7+1)*2/5+1)*1/3+1)/1
= (((((1/(2k+1)*k+1)/(2(k-1)+1)*(k-1)+1)/...)/7*3+1)/5*2+1)/3*1+1)/1
可以了,我们要做的就是做除法、做乘法、加1,做除法、做乘法、加1,...,这样直到做除法除以1。那么我们就可以在一个循环中完成它,用一个计数器i,1除以2i+1、乘以i、加1,循环。但是我们要输出800位小数,就只能用大数除法的办法了:分为n趟执行,这一趟把公式中每一次除法的余数保存下来,把商累计后输出;下一趟把保存的余数提高精度再做除法,把余数保存下来,把商累计后输出,以此类推。根据数学运算,当k=2800时,可以精确到小数点后800位(实际上是精确到小数点后844位),那么我们就设定一个2800的数组,全部初始化为1(也就是设定余数为1,就是公式中加的1),然后在循环中不断的做除法、乘法、加余数,过程中还要保存余数,和手工除法一样。
要说明的一点就是提高精度的办法,比如f[2800],初始值为1,除以5601、乘以2800,把商的整数部分加1放到下一项的运算中,余数保存下来,在下一趟乘以10,再除以5601、乘以2800,得到的商的整数部分就是上一趟运算结果的后一位数字。我们如果要每次输出4位数字,那么就要乘以10000,得到的商的整数部分不会超过4位数,就是上一趟运算结果的后四位数字。注意到上述公式的结果是π/2,那么我们就把数组都初始化为2,由于要一次输出4位,所以扩大10000倍。
可以由如下的一段代码实现:
#define M 2800
#include &stdio.h&
long b, d, f[M+1],
void main() {
for( ; b&=M; ) f[b++]=1000*2;
for( ; i&800/4; i++, printf("%.4d",f[0]+d/10000), f[0]=d%10000)
for(d=0, b=M; d+=f[b]*10000, f[b]=d%(2*b+1), d/=(2*b+1), b--)
如果写成这样就再明白不过了:
#define M 2800
#include &stdio.h&
void main()
long yushu[M+1], k = 0, i = 0, j = 0, sum = 0, PI = 0;
for (k = 0; k &= M; k++)
yushu[k] = 1000 * 2;
for (i = 1; i &= 800 / 4; i++)
for (j = M, sum = 0; j & 0; j--)
sum += yushu[j] * 10000;
yushu[j] = sum % (2 * j + 1);
sum /= (2 * j + 1);
sum += yushu[j] * 10000;
yushu[j] = sum % (2 * j + 1);
printf("%.4d", PI + sum / 10000);
PI = sum % 10000;
把第一段代码稍加变形,就是把b替换为b-1,就可以得到
#define M 2800
#include &stdio.h&
long b, d, e, f[M+1],
void main() {
for( ; b-M; ) f[++b]=1000*2;
for( ; i&800/4; i++, printf("%.4d",e+d/10000), e=d%10000)
for(d=0, b=M; d+=f[b]*10000, f[b]=d%(2*b-1), d/=(2*b-1), b&1; b--)
再对照着继续变形就能得到那段传说的原始代码了。这个过程中用了一些障眼法做混淆作用,尤其是故意设下两个错误,但却没有影响计算结果的精度,下面就要提到。
1、数组初始化
for( ;b-c; ) f[b++] =a/5;
这一行代码把数组f[0]至f[2799]设置为2000,f[2800]没有初始化,还是0,那么在实际运算中这一项是没有起到作用的,由于这一项的结果实在太小了。但是从计算逻辑上,却有很大的混淆作用,实际上f[0]是从来没有用到的,所以初始化应该是把f[1]至f[2800]初始化为2000,这样精度在小数点后848位才出现变化,由于结果是精确到第844位,所以这点精度实际上是没有意义的,但是算法却正确了。也就是
for( ;b-c; ) f[++b] =a/5;
2、除法的运算过程(除法的计算起点)
如果细心可以发现在第三个for循环的初始化中有一点不同,原始代码用的是b=c,我们用的是b=M,也就是b=2800,不同点在于我们按照公式把每一次除法都做了,而原始代码是每次漏掉一项,由于每趟计算的结果保存在余数数组里,所以这种遗漏对结果的影响非常小以致于可以忽略不计。但这样的混淆作用太大了,原来的算法几乎面目全非。所以这一点错误对于理解代码至关重要。
1、输出结果(printf)
代码中的d就是每趟运算中商的累计,就是要输出的结果,由公式及我们的算法处理可知,d不会超过8位,而且其左4位与前次余数e的和也不会超过8位,所以我们用printf("%.4d",e+d/10000)把左4位输出,把d的右4位保存在e中e=d%10000。printf("%.4d",…)输出4位整数,且显示最左面的0,就是那个.的作用了。
2、两个乘数()
在公式的程序实现中已经解释过这两个数字的来历了。
3、c的作用
在第二个for循环中用c-=14来控制循环次数,实际上的影响在于第三个for循环的初始化部分b=c,上面分析过这样的处理(错误)对精度几乎没有影响。实际上c-=14没有特殊的含义,只是因为)=14,我们完全可以用计数器来替代,就像我们的代码中一样。
4、g的作用
g就是公式中的2k+1,在我们的程序中完全可以用2*b+1来替代。
在我们的程序中,2800就是公式中的k,通过它来调整计算结果的精度,如果为了调试程序当然多少都可以了,我调试的时候用的是6。还有用到计数器i,i&800/4就是显示800位的意思,实际上我们显示的是小数点后799位,加上小数点前面的3总共是800位。
下面的文章中对f[2800]的分析实际上是不对的,对c-=14的说明如上“c的作用”,第二个for循环中b=c的错误作者没有提到,而且公式的展开还不到位,和程序中的算法实现对不上。
解读求pi的怪异代码
25th November,2005
Institute of Post and Telecommunications,Xi'an, P.R.China
Network Engineering Dep.
网上流传着一个怪异的求pi程序,虽然只有三行却能求出pi值连小数点前共800位。这个程序如下:
/*某年Obfuscated C Contest佳作选录:*/
#include &stdio.h&
long a=10000, b, c=2800, d, e, f[2801],
for(;b-c;)f[b++]=a/5;
for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a)
for(b=c;d+=f[b]*a,f[b]=d%--g,d/=g--,--b;d*=b);
/* (本程式可算出pi值连小数点前共800位)
(本程式录自sci.math FAQ,原作者未详)*/
咋一看,这程序还挺吓人的。别慌,下面就告诉你它是如何做到的,并且告诉你写怪异C程序的一些技巧。^_^
我们知道,在C语言中,for循环和while循环可以互相代替。
for(statement1;statement2;statement3){
上面的for语句可以用下面的while语句来代替:
statement1;
while(statement2){
statement3;
而且要写怪异的C程序,逗号运算符无疑是一个好的助手,它的作用是:
从左到右依次计算各个表达式的值,并且返回最右边表达式的值。
把它嵌入for循环中是写怪异代码的常用技巧之一。所以,上面的程序可以展开为:
#include &stdio.h& /*1*/
long a=10000, b, c=2800, d, e, f[2801], /*3*/
main(){ /*4*/
while(b-c!=0){ /*5*/
f[b]=a/5; /*6*/
b++; /*7*/
d=0; /*9*/
g=c*2; /*10*/
while(g!=0){ /*11*/
b=c; /*12*/
d+=f[b]*a; /*13*/
f[b]=d%--g; /*14*/
d=d/g--; /*15*/
--b; /*16*/
while(b!=0){ /*17*/
d=d*b+f[b]*a; /*18*/
f[b]=d%--g; /*19*/
d=d/g--; /*20*/
--b; /*21*/
c-=14; /*23*/
printf("%.4d",e+d/a); /*24*/
e=d%a; /*25*/
d=0; /*26*/
g=c*2; /*27*/
现在是不是好看一点了?
进一步化简
你应该能注意到a的值始终是10000,所以我们可以把a都换成10000。再就是,仔细观察g,在外层循环中,每次循环用它做除法或取余时,它总是等于2*c-1,而b总是初始化为c。在内层循环中,b每次减少1,g每次减少2。你这时会想到了吧?用2*b-1代替g!代进去试试,没错!另外,我们还能做一点化简,第26行的d=0是多余的,我们把它合并到第13行中去,第13行可改写为:d=f[b]*a; 。所以程序可以改为:
#include &stdio.h&
long b, c=2800, d, e, f[2801];
while(b-c!=0){
f[b]=2000;
while(c!=0){
d=f[b]*10000;
f[b]=d%(b*2-1);
d=d/(b*2-1);
while(b!=0){
d=d*b+f[b]*10000;
f[b]=d%(b*2-1);
d=d/(b*2-1);
printf("%.4d",e+d/10000);
e=d%10000;
少了两个变量了!
好了,马上进入实质性的分析了。一定的数学知识是非常有必要的。首先,必须知道下面的公式可以用来求pi:
pi/2=1+1!/3!!+2!/5!!+3!/7!!+...+k!/(2*k+1)!!+...
只要项数足够多,pi就有足够的精度。至于为什么,我们留给数学家们来解决。
写过高精度除法程序的人都知道如何用整数数组来进行除法用法,而避免小数。其实很简单,回想一下你是如何徒手做除法的。用除数除以被除数,把得数放入结果中,余数乘以10后继续做下一步除法,直到余数是零或达到了要求的位数。
原程序使用的数学知识就那么多,之所以复杂难懂是因为它把算法非常巧妙地放到循环中去了。我们开始具体来分析程序。首先,我们从数学公式开始下手。我们求的是pi,而公式给出的是pi/2。所以,我们把公式两边同时乘以2得:
pi=2*1+2*1!/3!!+2*2!/5!!+2*3!/7!!+...+2*k!/(2*k+1)!!+...
接着,我们把它改写成另一种形式,并展开:
pi=2*1+2*1!/3!!+2*2!/5!!+2*3!/7!!+...+2*n!/(2*n+1)!!
=2*(n-1)/(2*n-1)*(n-2)/(2*n-3)*(n-3)/(2*n-5)*...*3/7*2/5*1/3
+2*(n-2)/(2*n-3)*(n-3)/(2*n-5)*...*3/7*2/5*1/3
+2*(n-3)/(2*n-5)*...*3/7*2/5*1/3
+2*3/7*2/5*1/3
+2*2/5*1/3
对着公式看看程序,可以看出,b对应公式中的n,2*b-1对应2*n-1。b是从2800开始的,也就是说n=2800。(至于为什么n=2800时,能保证pi的前800位准确不在此讨论范围。)看程序中的相应部分:
d=d*b+f[b]*10000;
f[b]=d%(b*2-1);
d=d/(b*2-1);
d用来存放除法结果的整数部分,它是累加的,所以最后的d将是我们要的整数部分。而f[b]用来存放计算到b为止的余数部分。
到这里你可能还不明白。一是,为什么数组有2801个元素?很简单,因为作者想利用f[1]~f[2800],而C语言的数组下标又是从0开始的,f[0]是用不到的。二是,为什么要把数组元素除了f[2800]都初始化为有什么作用?这倒很有意思。因为从printf("%.4d",e+d/10000);看出d/10000是取d的第4位以前的数字,而e=d%10000; ,e是d的后4位数字。而且,e和d差着一次循环。所以打印的结果恰好就是我们想要的pi的相应的某4位!开始时之所以把数组元素初始化为2000,是因为把pi放大1000倍才能保证整数部分有4位,而那个2就是我们公式中两边乘的2!所以是2000!注意,余数也要相应乘以10000而不是10!f[2800]之所以要为0是因为第一次乘的是n-1也就是2799而不是2800!每计算出4位,c都要相应减去14,也就保证了一共能够打印出4*位。但是,这竟然不会影响结果的准确度!本人数学功底不高,无法给出确切答案。(要是哪位达人知道,请发email到xiyou.告诉我哦。)
偶然在网上见到一个根据上面的程序改写的“准确”(这个准确是指没有漏掉f[]数组中的的任何一个元素。)打印2800位的程序,如下:
long b,c=2800,d,e,f[2801],g;
int main(int argc,char* argv[])
for(b=0;b&c;b++)
while(c & 0)
for(b=c;b&0;b--)
d+=f[b]*10;
f[b]=d%(b*2-1);
d/=(b*2-1);
printf("%d",(e+d/10)%10);
不妨试试把上面的程序压缩成3行。
以Knuth图灵演讲中的一句话结束全文:
We have seen that computer programming is an art, because it applies accumulated knowledge to the world, because it requires skill and ingenuity, and especially because it produces objects of beauty. A programmer who subconsciously views himself as an artist will enjoy what he does and will do it better.
与大家共勉!^_^
π后100位的计算PI
π小数点后100位的计算,java提供了BigDecimal类来处理超大浮点数.
计算PI(π)的几种方法
计算π的方法
一、蒙特卡罗法
这种方法是一种利用计算机随机数的功能基于“随机数”的算法,通过计算落在单位圆内的点与落在正方形内的
点的比值求PI。
由于图形的对称性,我们靠考虑该图...
说起圆周率的计算,估计很多人首先想到的是祖冲之的割圆术。确实,在当时的条件下,割圆术能将π计算到一个较高的精度,实在不易。
不过我们现在,希望使用计算机快速计算高精度的π,这时我们该如何去做呢?算法...
Qt中计算一段代码的执行时间
利用gettimeofday(),其精度为us级
[html] view
plain copy
#include QDebug&
#include s...
计算圆周率 Pi (π)值, 精确到小数点后 10000 位 只需要 30 多句代码!
原文地址http://www.cppfans.com/articles/basecalc/c_pi_10000.asp by: Victor Chen
大家都知道π=3.1415926……无穷多位, ...
程序计算精确圆周率Pai的方法
一些参考资料:
http://www.guokr.com/blog/444081/
大家都知道π=3.1415926……无穷多位, 历史上很多人都在计算这个数, 一直认为是一个非常复杂的问题。现在...
根号2以及π的计算--关于无理数的畅想
曾经写过两篇用朴素的原始思想理解现代数学概念的文章:
《科普文章-另一个视角解读计算机编码(修订版)》
《原始人的除法引发的闲聊》
这两篇文章里,我发现不需要那些老师教的范式也能很好地理解那些现...
分析外星人计算Pi的程序
有一个只用4行代码就实现的计算Pi的程序,被称为外星人计算Pi的程序。有许多人讨论分析了该程序的实现原理,如:http://blog.csdn.net/panqiaomu/archive/2006/0...
计算PI的方法
今天看到hdu上有一题是要计算圆周率,查阅了一些资料,发现有这些方法:
1.正方形逼近;
2.迭代法;
3.蒙特卡罗法;
其中蒙特卡洛法是
生成N多个随机坐标落在1×1的方格里,统计x平方+y平...
没有更多推荐了,C语言所有复杂的指针声明,都是由各种声明嵌套构成的。如何解读复杂指针声明呢?右左法则是一个既著名又常用的方法。不过,右左法则其实并不是C标准里面的内容,它是从C标准的声明规定中归纳出来的方法。C标准的声明规则,是用来解决如何创建声明的,而右左法则是用来解决如何辩识一个声明的,两者可以说是相反的。右左法则的英文原文是这样说的: The
right-left
declaration
parentheses,
parentheses,
everything
parentheses
declaration
这段英文的翻译如下: 右左法则:首先从最里面的圆括号看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。
笔者要对这个法则进行一个小小的修正,应该是从未定义的标识符开始阅读,而不是从括号读起,之所以是未定义的标识符,是因为一个声明里面可能有多个标识符,但未定义的标识符只会有一个。
现在通过一些例子来讨论右左法则的应用,先从最简单的开始,逐步加深: int
(*func)(int
*p); 首先找到那个未定义的标识符,就是func,它的外面有一对圆括号,而且左边是一个*号,这说明func是一个指针,然后跳出这个圆括号,先看右边,也是一个圆括号,这说明(*func)是一个函数,而func是一个指向这类函数的指针,就是一个函数指针,这类函数具有int*类型的形参,返回值类型是int。 int
(*func)(int
(*f)(int*)); func被一对括号包含,且左边有一个*号,说明func是一个指针,跳出括号,右边也有个括号,那么func是一个指向函数的指针,这类函数具有int
(*)(int*)这样的形参,返回值为int类型。再来看一看func的形参int
(*f)(int*),类似前面的解释,f也是一个函数指针,指向的函数具有int*类型的形参,返回值为int。 int
(*func[5])(int
*p); func右边是一个[]运算符,说明func是一个具有5个元素的数组,func的左边有一个*,说明func的元素是指针,要注意这里的*不是修饰func的,而是修饰func[5]的,原因是[]运算符优先级比*高,func先跟[]结合,因此*修饰的是func[5]。跳出这个括号,看右边,也是一对圆括号,说明func数组的元素是函数类型的指针,它所指向的函数具有int*类型的形参,返回值类型为int。 int
(*(*func)[5])(int
*p); func被一个圆括号包含,左边又有一个*,那么func是一个指针,跳出括号,右边是一个[]运算符号,说明func是一个指向数组的指针,现在往左看,左边有一个*号,说明这个数组的元素是指针,再跳出括号,右边又有一个括号,说明这个数组的元素是指向函数的指针。总结一下,就是:func是一个指向数组的指针,这个数组的元素是函数指针,这些指针指向具有int*形参,返回值为int类型的函数。 int
(*(*func)(int
*p))[5]; func是一个函数指针,这类函数具有int*类型的形参,返回值是指向数组的指针,所指向的数组的元素是具有5个int元素的数组。 要注意有些复杂指针声明是非法的,例如: int
func(void)
[5]; func是一个返回值为具有5个int元素的数组的函数。但C语言的函数返回值不能为数组,这是因为如果允许函数返回值为数组,那么接收这个数组的内容的东西,也必须是一个数组,但C语言的数组名是一个右值,它不能作为左值来接收另一个数组,因此函数返回值不能为数组。 int
func[5](void); func是一个具有5个元素的数组,这个数组的元素都是函数。这也是非法的,因为数组的元素除了类型必须一样外,每个元素所占用的内存空间也必须相同,显然函数是无法达到这个要求的,即使函数的类型一样,但函数所占用的空间通常是不相同的。 作为练习,下面列几个复杂指针声明给读者自己来解析,答案放在第十章里。 int
(*(*func)[5][6])[7][8]; int
(*(*(*func)(int
*))[5])(int
(*(*func[7][8][9])(int*))[5];
实际当中,需要声明一个复杂指针时,如果把整个声明写成上面所示的形式,对程序可读性是一大损害。应该用typedef来对声明逐层分解,增强可读性,例如对于声明: int
(*(*func)(int
*p))[5]; 可以这样分解: typedef
(*PARA)[5]; typedef
(*func)(int
*); 这样就容易看得多了。
昨天刚把《C程序设计语言》中“指针与数组”章节读完,终于把心中的疑惑彻底解开了。现在记录下我对指针声明的理解,顺便说下如何在C语言中创建复杂声明以及读懂复杂声明。...
指针是C/C++语言中很重要的机制,一些C语言高级用法基本都需要指针的参与。本文从定义的角度,
解析各类用到指针的定义。
具体解析过程
定义普通变量p...
先说明正确的多个指针声明应该为:例:int *a,*b,*c,*d;
按照常理定义变量应该为:类型 变量名 如:int a;
但是定义指针时,int *a;依照 类型 变量名 的规则来看,就像定义了一...
指针数组是数组
数组指针是指针:指针指向的是一个数组。
int *p[5];
int (*p)[5];
int *(p[5]);//和第一个是一样的,小括号是多余的,用...
声明:1. 文章如有不妥的地方,请您指正,谢谢.
2.另外文中有些细节可能引用您的内容却未给出参考,请原谅我的疏忽,你的共享我不会忘记.
3. Email:lizh...
//这是一个普通的整形变量
C语言的指针是让新手很头疼的事情,但是由于其太过于灵活,以至于可以很好得的解决一些复杂的问题,因此不得不掌握。我最近正在学习指针相关的内容,因此在这里做一个小的总结。本篇是不涉及到函数以及结构体等复杂...
在阅读Linux的内核代码是经常会遇到一些复杂的声明和定义,诸如:
void * (* (*fp1) (int)) [10];
float (* (...
没有更多推荐了,}

我要回帖

更多关于 c语言求闰年 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信