第十二讲 函数(1)

      关于昨天的问题,不知道大家是不是已经吃透了,不过就算是吃透了,我想大家一定会觉得那样做太过麻烦了,今天在说尼科彻斯定理之前,我们再来看看另一个比较简单的方法,昨天我们用的C语言来实现,今天我们用C++来实现吧,虽然说现在还没正式开讲C++,但是让那些还没接触过C++的同学可以对比一下两者的区别。
今天,我们不要那么麻烦,不用返回那些奇奇怪怪的东西了,我们直接使用STL里的vector容器来实现,但是今天我们不说vector,留在C++部分再讲。
————————————-
#include <iostream>#include <vector>using namespace std;

int main()
{
vector<int>age;

int n,m,a[10]={0 },s[10]={0 };

long sum1,sum2;

for(int i=0;

i<25;

i++)
{
sum1 = i*i*i;

sum2 = i*i*i*i;

if(sum1 >1000 &

&

sum1 <10000 &

&

sum2 >100000 &

&

sum2 <1000000)
{
age.push_back(i);

}
}
int size = age.size();

n = age[0];

m = age[size-1];

do
{
sum1 = n*n*n;

for(int i=3;

i>=0;

i–)
{
a[i] = sum1%10;

sum1 = sum1/10;

}
sum2 = n*n*n*n;

for(int i=9;

i>3;

i–)
{
a[i] = sum2%10;

sum2 = sum2/10;

}
for(int i=0;

i<=9;

i++)
{
s[a[i]]++;

}
for(int i=0;

i<=9;

i++)
{
if(s[i] == 1)
{
if(i == 9)
cout<<“这位同学的年龄是:”<<n<<endl;

}
else
break;

}
n++;

}while(n!=m);

cin.get();

return 0;

}
————————————-
今天的设计思路是将同时满足sum1和sum2的数值存放在age容器里面,然后分别取出第一个数和最后一个数来做do while循环,在do while循环和昨天实现的一样,所以没什么好说的,现在我们来看看输出和昨天的有没有区别:
第十二讲 函数(1)
结果和昨天的一样,大家是不是发觉C/C++是无所不能的啊,解决的方案还有很多,大家有兴趣的话可以自己去探索,现在回到我们今天的主题——函数。
说到函数,现在想必大家都比较熟悉了,但是为什么大家都熟悉的函数我们现在还要搬出来讲呢?因为在C/C++里,函数是完成特定任务的程序代码的自包含单元,所以,所以无论我们想要实现什么功能,都需要一个个的函数来实现。就好比昨天我们留下的尼科彻斯定理的证明就可以用一个函数来实现,下面我们先分析一下要实现这个问题的关键。
解决这个问题的关键,首先我们要确定这一连串的奇数的最大值的范围,我们声明一个int对象sum来储存一个数的立方,sum的一半n如果是奇数的话,那么 n+n+2的值就大于sum了,所以,我们可以得出一个结论,  这一连串中的奇数的最大值不会大于n,那么n是偶数的情况怎么办呢?我们应该+1还是-1?我们选择+1,那么另一个奇数就是n-1,n+n+1-1刚好等于sum,所以当n为偶数的时候,最大奇数的取值范围不会超过n+1,在确定范围后,接下来的是就好办了,我们直接从最大值开始用while来循环穷举:
———————————-
#include <stdio.h>#include <stdlib.h>int main()
{
int i, j, k ,a, n, m, sum,flag=1;

printf(“请输入一个数:n”);

scanf(“%d”, &

a);

sum = a*a*a;

n = sum / 2;

if (n % 2 == 0)
n = n + 1;

while (flag==1&

&

n >= 1)
{
m = 0;

k = 0;

while (1)
{
m += (n – 2 * k);

k++;

if (m == sum)
{
printf(“%d*%d*%d=%d=”, a, a, a, sum);

for (j = 0;

 j <k – 1;

j++)
printf(“%d+”, n – j * 2);

printf(“%dn”, n – (k – 1) *2);

flag=0;

break;

}
if (m >sum)
break;

}
n -= 2;

}
system(“PAUSE”);

return 0;

}
——————————————–
这个函数不难看懂,我们现在来看这个函数的输出:
第十二讲 函数(1)
大家可以多验证一下,那么现在我们来分析一下这个函数的结构:
#include <stdio.h>
 #include <stdlib.h>
这是我们每次写函数的时候都会在最开头添加的两句代码,大家想必都很熟悉了,但是我想对于初学者来说这个问题可能让大家觉得有些疑惑,这到底是干嘛呢?
这是函数的预处理,也就是包含相关的头文件,何为头文件?就是一个以“.h”结尾的文件,这个文件里面包含有相关的函数接口,我们要使用的标准IO都是在stdio.h这个文件里声明的,所以,我们只要包含了这个头文件就可以在接下来的代码里面使用里面的相关接口。所以如果我们需要包含什么相关文件,需要使用#include预处理命令。
除了#include命令之外,我们还会看到其他命令,如同下面这些:
#define PI 3.1415926
这是一个宏定义,就是把PI定义为3.14.5926,只要在函数开头添加了这个预处理命令,在接下来的代码中,凡是遇到PI他就表示3.1415926,所以,如果想要定义一个常量,可以使用#define 命令,记住这个命令的用法是后面只能用一个数字:
———————————
#define PI 3.1415926;//错误的方式
#define PI  3.1415929  3.1415927//错误
#define PI  2 * 3.1415926//正确的方式
#define PI  3.1415926 //正确
———————————–
当然,如果只是定义一个常量的话,我们以后会用const来定义,const的效率要比#define的高。
在函数开头使用#XXX的一般都是程序的预处理命令,大家可以多了解一些,这里就不多说了。
接下来是主线程的入口:main(),main()是控制台函数的入口,我们之所以能够看到那个黑乎乎的窗口,就是通过这个main()呼唤出来的,还记得在第一讲的时候我们说过吗?当函数执行到main()下面的左花括号({)的时候那个黑乎乎的窗口就出现了。
在SDK程序里,应用程序的窗口的入口函数是WinMain(),同时也是MFC程序的窗口入口函数,不过我们暂时不说这个函数,留待讲SDK程序的时候再说。
那么大家是不是还记得在第一讲里面我们在main()的前面使用的是void,而后来我们都用int,而细心的同学可能也注意到了,我们用void的程序没有return,而用int的都有一句
return 0
;的语句,这是为什么呢?
在c99以前,其实我们是可以不用在main()前面添加什么关键词的,因为那时候的默认情况就是void,有void修饰的函数是不需要返回的,所以我们那时候就没有使用return语句。
在标准里面,main可以定义为int/void,所以大家会看到这两种情况,但大家通常见到的都是int,带一个默认返回值,返回值一般是用来检验错误的,但是对于main来说几乎没这个必要,所以void也成了他的标准。
一个修饰词说了这么多,有点过分了,我们接着说下一点,定义一个函数,除了函数名和类型外,还需要参数和代码段的实现。
说道参数,还记得第十一讲里面我们自定义的power(int n,int m)函数吗?括号里面的n,和m便是这个函数的两个参数,但是我们又经常遇到一些没带参数的函数,没带参数的函数可以这么定义,fun(void),但是void是可以省略的,所以我们经常会看到这样的类型fun()。
每一个函数都有他的用处,那么我们怎么拿出来用呢?我们怎么把他引入主线程main()中来呢?这就关乎着函数的接口了。
说到函数的接口,大家应该不会默认,相信大家已经想到了,函数的接口就是参数和返回值。今天说得好像不少了,微信学习讲究的是轻松越快,每天花几分钟的时间就好即可,所以关于参数和返回值留待明天再说。

第十一讲 do while

      今天的内容主要是说昨天留给大家思考的问题,这个问题说难不难,就是有些麻烦,相信有同学已经得出答案了,不管如何,还是以前那句话,我们从头理一理吧。
从原题目入手,年龄的三次方是4位数,那么我们可以得出一个范围来,我们可以声明一个long类型变量来储存这个值
long  sum1;
sum1的取值范围我们可以明确的知道大于1000并且小于10000。
(sum1>1000 &

&

sum1 <10000)
接下来我们可以再从第二个条件知道,年龄的4次方是6位数,于是我们再声明一个long类型变量sum2来储存这个值,并且得到他的取值范围是在100000和1000000之间:
long sum2;
     (sum2>100000 &

&

sum2<1000000);


说到这里,顺便说一下,算是补漏吧,千万不要写出下面类型的判断语句出来,这是C/C++不认同的:
(100000<sum2<1000000)(错误的代码);


既然说到sum1和sum2,那么大家是不是想问,sum1和sum2的值从何而来?在C/C++里面的math.h库里有个power(n,m)函数,该函数返回n的m次方值,不过今天,我们不想直接使用这个库,我们自己写一个计算幂次方的函数来调用就好,反正是公众课,所以我想大家不会嫌代码多的是吧,下面我们就简单的先把幂次方的函数定义出来:
——————————–
long power(int n,int m)
{
long s=1;

while(m–)
{
s *= n;

}

return s;

}
——————————-
既然power已经定义好了,那么我们的sum1和sum2就顺理成章的计算出来了:
sum1 = power(i,3);


     sum2 = power(i,4);


i是一个int变量,用来遍历年龄的,上面的代码如果不是因为教学的原因,可以不用写那个幂次方函数,直接使用i*i*i和i*i*i*i即可。
但是大家是不是发现一个问题,同学满足sum1和sum2的值不少,而且我们又看不见,难道说我们还要先把这个值打印出来再来研究这问题吗?其实本来有种思想就很简单的,就是自己预先演算一边,把同时满sum1和sum2的值计算出来,然后来用do while循环计算出年龄,这种方法要自己一个数字一个数字的去计算,不过可以根据我们大概的判断一下范围来围绕计算也不会是太难的,但是这不是我们今天要说的重点,毕竟我也很懒不想去想这个范围到底在哪里。既然这样,那我们把同时满足sum1和sum2的值的个数和最大值分别用一个函数计算出来,然后把他们传回main()中就可以了,下面我们分别实现返回个数和最大的两个函数:
—————————————-
//返回同时满足sum1和sum2的年龄数
int age()
{
int age[100];

int count = 0;

long sum1,sum2;

for(int i=0;

i<100;

i++)
{
sum1 = power(i,3);

sum2 = power(i,4);

if(sum1 >1000 &

&

sum1 <10000 &

&

sum2 >100000 &

&

sum2 <1000000)
{
age[i] = i;

count++;

}
}

return count;

}
————————————-
————————————-
//返回满足sum1和sum2的最大值
int agemax()
{
int age[25]={0 },max = 0;

long sum1,sum2;

for(int i=0;

i<25;

i++)
{
sum1 = power(i,3);

sum2 = power(i,4);

if(sum1 >1000 &

&

sum1 <10000 &

&

sum2 >100000 &

&

sum2 <1000000)
{
age[i] = i;

}
if(max<age[i])
{
max = age[i];

}
}

return max;

}
————————————
两个函数差不多,如果我们直接使用打印输出的话只需要一个函数就好,但是我们现在是用他们的返回值来作为参数,所以我们把他们写成两个函数,分别返回不同的值。
我们现在知道最大值和个数,再加上这些数据都是连续的整数,所以我们通过最大值+1再减去个数便得到最小满足sum1和sum2的值。
这些都准备好了,现在我们可以回来设计我们的计算部分了,这里我们会使用do while来循环计算,wo while是我们今天的主角,所以现在来说说一下这个循环的用法。
———————————-
do
{
do something;
}while(条件);
———————————–
从上面这个声明中,想必大家都清楚了,do while是先执行一遍程序然后再来判断满足否,如果不满足直接退出,如果满足继续循环,所以在三个循环函数中,可以根据具体的情况选择不同的循环来循环。
大家是不是还意识一点,在三个循环函数中,只有do while循环在while后面加分号,记住,这是一定要加的。
循环就是循环,没有什么花样,下面我们就用这个循环来计算昨天留下的问题,不过再给出最终代码之前,还是有先说一些必要的要点。
我们虽然得到一个范围,但是我们还有一个条件没有满足,那就是sum1和sum2里面没有重复的数字,这一点怎么来得出呢?首先我们要把sum1和sum2里面的所有数字取出来,怎么取?大家还记得前几讲说过的取余“%”运算符吗?现在我们就要用它和取整来对sum1和sum2取余,然后我们把每位都储存在一个数组里面,所以我们要在开头先声明一个数组,为了和早些时候的sum1和sum2区分开,我们这里声明为sum3和sum4操作如下:
——————————–
int  a[10] ={0 }//分辨用0来初始化
……
//对sum3
for(i=3;

i>=0;

i–)
{
       a[i] = sum3%10;
       sum /=10 ;

// sum = sum/10;
}
//对sum4
for(i=9;

i>3;

i–)
{
       a[i] = sum4%10;


       sum4 /= 10;


}
————————————
这样,我们便得到一个包含10个元素的数组,其中这10个元素要满足各不相同的条件,也就是他们分别是:0,1,2,3,4,5,6,7,8,9。那么怎么判断呢?我们可以再声明一个数组int s[10]={0 },同样用0去初始化,然后用a[10]的元素去作为的下标,统计这些数字出现的次数,方法如下:
————————————-
//统计数字出现的次数
for(i=0;

i<=9;

i++)
{
     s[a[i]]++;


}
————————–
接下来我们判断一下有没有重复的数字,方法如下:
——————————
//判断有没有重复数字然后顺便打印出结果
for(i=0;

i<=9;

i++)
{
     if(s[i] == 1)//如果有重复,就不会满足这个条件,然后会跳转到下面的break。
    {
         if(i == 9)//这个判断没多大意义,就是为了只打印一遍就好,否则会打印出10遍来。
            printf(” 同学的年龄是:%dn”,c);

     
      }
     else
        break;


}
————————————
说到这里,想必大家应该都清楚了,下面是完整的程序清单,当然大家可以尝试一下简单的那个方法,就是自己预先算出能够满足sum1和sum2的值,然后再做循环,那样就不需要另外的三个程序。
—————————————-
//完整清单
#include <stdio.h>#include <stdlib.h>long power(int n,int m);

int age();

int agemax();

int main()
{
int n,m,c;

long a[10]={0 },s[10]={0 },i,sum3,sum4;

n = age();

m = agemax();

c = m-n+1;

do
{
sum3 = power(c,3);

for(i=3;

i>=0;

i–)
{
a[i] = sum3%10;

sum3 = sum3/10;

}
sum4 = power(c,4);

for(i=9;

i>3;

i–)
{
a[i] = sum4%10;

sum4 = sum4/10;

}
for(i=0;

i<=9;

i++)
{
s[a[i]]++;

}
for(i=0;

i<=9;

i++)
{
if(s[i] == 1)
{
if(i == 9)
printf(“这位同学的年龄是:%dn”,c);

}
else
break;

}
c++;

}while(c<=m);

system(“PAUSE”);

return 0;

}
//实现幂次方
long power(int n,int m)
{
long s=1;

while(m–)
{
s *= n;

}

return s;

}
//求满足sum1和sum2的个数
int age()
{
int age[25];

int count = 0;

long sum1,sum2;

for(int i=0;

i<25;

i++)
{
sum1 = power(i,3);

sum2 = power(i,4);

if(sum1 >1000 &

&

sum1 <10000 &

&

sum2 >100000 &

&

sum2 <1000000)
{
age[i] = i;

count++;

}
}

return count;

}
//求出满足sum1和sum2的最大值
int agemax()
{
int age[25]={0 },max = 0;

long sum1,sum2;

for(int i=0;

i<25;

i++)
{
sum1 = power(i,3);

sum2 = power(i,4);

if(sum1 >1000 &

&

sum1 <10000 &

&

sum2 >100000 &

&

sum2 <1000000)
{
age[i] = i;

}
if(max<age[i])
{
max = age[i];

}
}

return max;

}
———————————–
现在我们来看下输出:
第十一讲 do while
哦,原来臭小子是18岁啊,如果有持怀疑精神的可以自己推算一下吧,把这个程序理解后我相信大家不但学会了do while还学会了很多东西,好吧,今天就到这里,大家有兴趣证明一下尼科彻斯吗?
====================
尼科彻斯定理:
任何一个整数的立方都可以写成一连串的连续奇数之和,大家可以编程证明这个定理,知识点不会超出我们现在所讲范围。
====================

第十讲 switch()

         昨天留下的问题不知道大家思考得怎么样,不管大家思考得怎么样,我想大家心中已经有了答案,不过我还是要说说,这个问题最适合探讨for()和if()的用法了,这个问题的解决方案就是用for来遍历,用if来判断,是或非,在一遍遍的循环比较中最终得出答案,下面我们来看看这个实现清单:
—————————————–
#include <stdio.h>
#include <stdlib.h>
int main()
{
    int A,B,C,D,E;


    for(A=1;

A<6;

A++)
   {
        for(B=1;

B<6;

B++)
       {
             if(A!=B)
             {
                 for(C=1;

C<6;

C++)
                {
                     if(C!=B &

&

C!=A)
                    {
                         for(D=1;

D<6;

D++)
                         {
                              if(D!=C&

&

D!=B&

&

D!=A)
                             {
                                  for(E=1;

E<6;

E++)
                                 {
                                      if(E!=D&

&

E!=C&

&

E!=B&

&

E!=A)
                                       {
                                            if((C!=1)&

&

(D-E==2)&

&

(E!=2)&

&

(A!=1)&

&

(A!=5)&

&

(B-C==1))
                                             {
                                                printf(“A:%d”,A);


                                                printf(“B:%d”,B);


                                                printf(“C:%d”,C);


                                                printf(“D:%d”,D);


                                                printf(“E:%d”,E);


                                             
}

                                      
}

                                  
}

                              
}

                          
}

                     
}

                  }
             
}

        
}

    
}

     system(“PAUSE”);


    

return 0;


}
——————————————-
这循环虽然嵌套得有些复杂,但是不难看懂,这个循环简单,就是遍历一遍名次后再做比较然后继续下一个,直到最终比对出答案,现在我们来看看运行结果:
第十讲 switch()
是不是很有意思?其实很多有趣问题我们都可以通过简单的代码来轻松实现,不过,这些问题留待大家去探索,现在我们先来说说switch函数吧,还记得昨天我们讲的if()语言说的那个菜单问题吗?现在我们不妨来个更简单明了的现实:
—————————————-
#include <stdio.h>#include <stdlib.h>int main()
{
char ch;


   
int n;

printf(“回复D或者d查看目录:n”);

while(scanf(“%c”,&

ch))
{
switch(ch)
{
case ‘D’:
case ‘d’:
printf(“第一讲 Hello World.tn”);

printf(“第二讲 printf()(1).tn”);

printf(“第三讲 printf()(2).tn”);

printf(“…………tn”);

printf(“回复相应的数字查看相应章节.tn”);

goto d;

default:
printf(“无效字符,请重新输入:n”);

}
}
d:    while(scanf(“%d”,&

n))
{
switch (n)
{
case 1:
printf(“第一讲 Hello World.tn”);

break;

case 2:
printf(“第二讲 printf().tn”);

break;

case 3:
printf(“第三讲 printf()(2).tn”);

break;

default:
printf(“敬请期待……n”);

break;

}
}
system(“PAUSE”);

return 0;

}
———————————————
这个实现中,我们用了2个while和两个switch来制作这个菜单,第一个while嵌套switch用来查看目录,相信细心的同学应该知道这个目录就是我们这个公众课的目录,第二个while嵌套switch用来查看目录,但由于现在我们主要是讲这个switch的用法,所以我们就只是简单的把章节名拿出来show一下就好,等到以后我们就可以输入相应的章节序号可以直接打开章节文本和内容或者直接从网络上获取。
大家可能看到一个奇怪的“d:”标志,这里顺便也就给大家说一下goto语句,goto是一个让人讨厌又让人喜欢的语句,讨厌之处是本身容易出错,但是好处就是可以直接从一个深度循环里面直接跳转出来,由于while循环有个共性,只要你给的条件满足他就会一直循环下去,俗称死循环,像我们上面的这种写法就更容难退出了,这是我们所不希望看到的,因为如果这样的话我们就会被这个while给套牢了,我们想要的是当我们进入目录之后就可以进入查看章节的章程,当然如果我们没有进入目录自然会有重新尝试的机会,所以,我们应该在正确进入目录后直接跳出目录然后进行查看章节的环节,所以我们在打印完章节后我们使用goto语句直接退出循环,进入下一个环节,goto在这里就起到了关键作用,goto后面的d是一个标识符,标明要跳转d标记的地方,想要标记某个位置就直接在该行代码前加上该标识符和冒号即可,当程序运行到goto语句时直接跳转到标记处。
说完goto,现在还有个陌生的东西要给大家说,这同时也是今天的重点,switch语句,大家是不是都看到了,在两个循环里面,switch似乎都是和case一起使用,所以我们可以简单的总结一下switch的用法:
————————————
switch(what)//判断what是什么
{
 case  what =what1://当what是what1的时候
         do something;
         break;
 case   what = other what://是其他情况的时候
         do something;
         break;
case  ……:
       ……
default://表示自己不希望what = 的值
      break;
————————————
从上面我们总结出来的用法中,大家似乎又接触到了一个新东西:break;既然今天连碰到goto和break,我们不妨再把另一个关键字拿出来一起说了吧,这个关键字当然说的是continue,这三个关键字都有跳转的意思,我们现在来看看三个关键字的区别,以便大家不要用错了:
break 命令可以与三种循环形式中的任何一种以及 switch 语句一起使用。它导致程序控制跳过包含它的循环或 switch 语句的剩余部分,继续执行紧跟在循环或 switch 后的下一条命令。
continue 命令可以与三种循环形式中的任何一种一起使用,但不能和 switch 语句一起使用。它导致程序控制跳过循环中的剩余语句。对于 while 或 for 循环,开始下一个循环周期。对于 do while 循环(明天再说这个循环),对退出条件进行判断,如果必要,开始一个循环周期。
goto 语句导致程序控制跳转到由指定标签定位的语句。冒号用来将被标记的语句同它的标签相分隔。标签名遵循变量的命名规则。被标记的语句可以出现在 goto 之前或之后。
现在陌生的东西我们都弄清楚了,我们就来看下这个程序的效果吧:
第十讲 switch()
今天 就说到这里了,大家可以尝试一下其他的吧,现在还是老规矩,留个问题大家思考一下吧:
—————————————
        一个同学很喜欢数学,有人问他年龄时他却说:“ 我的年龄平方是三位数,立方是四位数,四次方是六位数,三次方和四次方正好占遍了0,1,2,3,4,5,6,7,8,9这10个数字。”现在大家能够猜到这位同学年龄吗?
—————————————–

第九讲 if()

       周末很愉快的就过去了,不知道上一讲留给大家思考的问题有没有实现出来,好吧,不管如何,我们今天就从乘法口诀表开始吧:
实现乘法的算法很简单,我们大家都知道怎么实现,所以这个问题所以的考察的要点有两点,一是for循环的运用,二是换行符的使用,如果大家还有疑问,我们不妨先看下程序再来看看是不是还有疑问。
——————————
#include <stdio.h>
#include <stdlib.h>
int main()
{
     
int i,j;


     for(i=1;

i<=9;

i++)
     {
             for(j=1;

j<=i;

j++)
                   printf(“%d*%d=%dt”,j,i,j*i);


             printf(“n”);


     
}   

      system(“PAUSE”);


}
———————————–
程序的设计很简单,不过这其中包含了一个要给大家说的知识点,那就是嵌套循环,这里的嵌套循环就是一个for循环里面又套了一个for循环,嵌套循环的要旨没什么难理解的,就是从外入内又从内入外,为什么什么这么说呢?因为每一个循环都得从最外的循环开始进入,然后执行内部循环,把内部循环执行完成之后,又重新回到外部循环进行下一项,再进入内部循环,所以这样无休无止的循环直到把最外层循环执行完成之后才会退出循环。
嵌套循环的时间复杂度给n的m次方,每个循环所执行的次数,嵌套的循环数,就好比我们现在这个例子,他的时间复杂度就是9的2次方,当然这是数据结构该研究的范畴,或许我们会说一些数据结构的知识,不过不是现在,我们还是回到正题上来。
上面的例子中,当函数执行到第一个for处,i=1,然后进入第二个循环,因为第二个循环用了第一个循环传递进来的i做参数,所以第二个循环j执行到1时便结束了第二个循环,这里就是1*1 = 1,这个时候我们要做的是要换行,但是换行不能用用在第二个循环里面,而要在第一个循环里面来执行,当然有疑惑的同学可以试着把第二循环写成下面这样来运行一下看看结果:
—————————
for(j=1;

j<=i;

j++)
     printf(“%d*%d=%dtn”,j,i,j*i);


—————————–
然后把下面的printf(“n”)给注释起来,说到注释,又得说一下,如果大家不想要某一行代码参与运行,可以在这行代码前添加两条斜杠”\”,当然大家也可以在某行代码的后面添加注释,标明改行代码是干嘛的,这些注释前代码的分号后面记得要加上双斜杠。如果想要把某段代码全部注释起来呢?当然也可以每一行前面添加双斜杠,但还有一个更简单的方法,那就是用单斜杠搭配*号来围起来,怎么围呢?就是正反来一个就好了,像这样即可:
——————————–
/*———————–
   需要注释起来的代码段
————————*/
——————————–
还是回到上面的问题,如果我们把打印换行的那一句给注释起来,大家是不是发觉打印出来的东西特么的别扭,所以,这个例子不光考察了大家对循环的理解,还同时考察了大家对换行符的使用,好吧,说到这里,想必大家都应该清楚了,我们现在来看下输出:
第九讲 if()
 

大家是不是看到每一列都很完整的对齐?这就是有人疑惑的那个t的功劳了,t上一讲我们说了,这是一个水平制表符,他的作用就是水平跳几个空格,保证每一列都能够实现左对齐。乘法口诀表就到这里吧,同时for也就到这里。
————————————-
if,顾名思义,这是一个条件判断语句,通常和else配合使用,也可以单独使用,他的意思是如果什么,那就做什么,否则就做什么。
———————-
if(什么)
     做什么;
else if(什么)
     做什么;
……
else
    做什么;
————————
光说不练就是纸上谈兵了,我们来个实例,也便好说明这个问题。
——————————
#include <stdio.h>
#include <stdlib.h>
int main()
{
     
int i;


      while(scanf(“%d”,&

i))
    {
          if(i>=0&

&

i<60)
               printf(“不及格,重考,下一个n”);


          else if(i>=60 &

&

i<70)
               printf(“一般般吧,勉强过关,下一个n”);


          else if(i>=70 &

&

i<90)
                printf(“好像还不错的样子,再接再厉,下一个n”);


          else if(i>=90 &

&

i<=100)
                printf(“漂亮,就是要这样,下一个n”);


          else
                printf(“无效成绩,什么玩意,下一个n”);


   
}

     system(“PAUSE”);



return 0;


}
—————————————
我们在看看运行效果,我们随便输入几个数字看看:
第九讲 if()
是不是觉得挺有意思的啊?是不是发现这好像有些菜单的感觉?嗯,不错,之所以举这个例子,主要是因为后面我们在说到switch()的时候我们用switch来实现这个例子,我们用switch来实现大家就更清楚了,实现菜一个单功能的思路也就更加清晰了。
if()同样可以和for()和while()等函数嵌套使用,关于这一点,留在明天吧,今天给大家留个思考题,大家有兴趣的话去分析一下怎么计算。
———————————————
      ABCDE五人在一场比赛中经过强烈的竞争后终于排下名次来,这五人的共同之处是有同一个好朋友,但遗憾的是他们的好朋友却因为一些事而不能参加,比赛结束后他们的好朋友分别询问了他们的名次,得到的回答如下:
      C不是第一名,D比E低两个名次,而E不是第二名,A既不是第一名也不是最后一名,B比C低一个名次。
      他们的朋友想了想终于得出了答案,现在要让大家用一个控制台程序来实现这个排名,大家能够实现吗?
——————————————

第七讲 数据类型&&C/C++关键字

        开始正事之前说两句题外话,我们这个课虽然叫C/C++,但是我现在给大家说的都是C的基础知识,当然同时也是C++的基础知识,不过大家最好把他当成C来理解,把C部分说完后会给大家讲C++,就好比现在讲OI的时候我并没有把cout和cin给拿进来,因为我怕把大家说懵了,分不清哪个是C那个是C++。可能有人听我这么一说会更纳闷,为什么不说清楚些呢?为什么不特意标明这是C不是C++呢?对此,我想说的是,不管是C还是C++用来写C++的程序是完全没问题的,如果可以,在以后我们编写C++程序的时候我希望大家能够把C++程序写成C风格的,好了废话撤远了,回到正题上来。
 

============================
昨天让大家验证一下putchar()和printf()的效率,不知道各位有没有去验证然后把我前天的结论给推翻,其实这两个函数真没啥好比的,C语言是一门面向过程的语言,讲究的效率,但这两个函数都能够满足,当输出10万个字符时,printf()的效率高于putchar(),但当输出100万个时候,putchar()明显又胜了一筹,所以,对于字符来说,用哪一个作为标准输出函数,就看大家的选择了。今天我们来说说C/C++的关键字和数据类型,下面我们来看看这个程序:
——————————
#include <stdio.h>
#include <stdlib.h>
int main()
{
     
int a,b,c;


      printf(“请输入a和b的值:n”);


      scanf(“%d,%d”,&

a,&

b);


      c = a + b;


      printf(“c = %dn”,c);


      system(“PAUSE”);


      
return 0;


}
————————————
这个程序主要是键入两个数,然输出這两个数的和,现在我们来看看运行结果:
第七讲 数据类型&

&

C/C++关键字
看来毫无问题,我们再来输入两个带小数的看看:
第七讲 数据类型&

&

C/C++关键字
为什么会是这样呢?c似乎就没抓到值一样,我们不妨来设个断点,抓取a和b的值看看有什么异常先,断点我们设在 c = a + b;

这里。
第七讲 数据类型&

&

C/C++关键字
看来只读取了a小数点前面的部分,b完全没有被我们键入的值初始化,这是为什么呢?这就是我们要说的数据类型了。因为我们在一开始声明变量的时候就把他们声明为整形,而我们却键入一个浮点型的数据,所以编译器凌乱了。为了实现能够小数相加,我们只需稍微的修改了上面程序的关键字即可,把int换成float,同时将类型转换换成%f即可。现在我们来看看是不是这样:
第七讲 数据类型&

&

C/C++关键字
第七讲 数据类型&

&

C/C++关键字
 

现在是不是正常了?这说明了一点,关键字很重要,下面我们来说说C/C++里面常用的几个关键字。
C/C++的数据类型关键字我们简单的说下下面这几个:
——————————————
int, short, long,unsigned, char,float, double, bool
——————————————-
其中int,short,long,char可以归纳为整形,整形顾名思义,就是整数类型。所以,一旦你声明一个变量为整形后,他就只会读取你的整数部分。所以如果你想要连小数部分读取,就得声明为了float或者double。
为什么表示整形有这么多表示方法呢?其实在C/C++有这么个定义,short不会比int长,同样long不会比int短,所以可以根据自己的需求声明不同的类型来节约资源。
float,double,doublefloat为带小数点的类型,他所声明的大概就相当于数学里面大家所理解的实数。
char,大家可以有些疑惑,明明是个字符型为什么上面把他归纳为整形呢?简单点说,其实每个字符或者标点符号都是被转换为整形来储存在0到127之间的,就好比65表示大写字母A,所以通常意义下是可以用char来表示-128到127之间的整数的。
bool,布尔,通常意义下表示真假,但是很多时候他却和整形挂钩,为什么呢?我想大家都清楚布尔值,那就是0为假1为真,所以有时候在程序里面会看到没有true和false,只有1和0,也就是这个道理,关于C/C++的类型和关键字,可以说是要说他没啥讲的他讲的也很多,要说他有啥讲的又感觉没啥讲的,所以今天就到这里,大家把这几个记下来基本能够应付一些程序了,至于其他今天没提到的,以后在程序里面会给大家解释,那时候大家也就记住了。
 

在讲for循环之前,给大家留个题,大家自己尝试一下怎么实现:
一个小球从100高空自由落下,每次落地弹起的高度是原来高度的一半,求小球第十次落地时共经历了多远?同时计算出第十次的反弹高度是多少?

第八讲 for

        昨天留给大家的问题不知道大家有没有去考虑,我想大家应该都很清楚这是一道物理题,当然我们并没有像研究物理题那样考虑得太多了,这里我们只需要计算出小球第十次接触地面的时候小球所经过的距离之和,再加上在第十次反弹起来的高度,所以这道题和真正的物理题比起要简单得多。
我们先来分析这道题的着手点吧。小球第一次下落时所经过的路程是100M,接下来的都是一上一下,所以我们可以定义一个float变量 h用来储存每次弹起的高度,第一次下落的100M我们就另当别论,不在这一上一下之列,那么现在抛开第一次触地之外,余下来的时间上只有九次了,不过这九次都是一上一下,换句话来说,这九次所经历的路程分别都是h*2。现在却跑出了一个难题,难道我们要用9*h*2吗?答案当然不是,那么我们应该怎么来考虑呢?
为了解答上面留下的问题,我们再声明一个float的变量s来储存小球所路径的路程,当小球没经历一次上下之后便把这个路程储存在s里面,最后我们再把历经9次得来的s相加起来,得到的便是我们所要计算的总路程。
那么最后第十次弹起的高度呢?第十次弹起的高度是第九次弹起的一半,而上面已经得出了第九次弹起的高度h,所以,第十次弹起高度自然就是h/2了。
题目我们已经分析完成,那么怎么来实现呢?这就是我们今天要说的for循环了。我们现在先来看看for循环一般的用法吧:
——————————
     for(表达式1;表达式2;表达式3)
       {
                      do something;
       
}

———————————-
该形式可以这么来理解,表达式1按表达式3的方式靠近表示2,表达式1表示for循环的入口,表达式2表示for循环的出口,表示3控制了for循环的循环方式。例如:
for(int i = 0;

i<n;

i++)
该循环的第一次是i = 0,接着用i++来控制循环方式的,表示i没增加1运行一次for函数,直到i = n-1时结束循环。
上面的函数语句里面我们说到i++这个概念,这是一个新概念,我们不如趁着现在顺便把C/C++里的运算符说一下。
C/C++里面的运算符其实和数学的里面的还是差不多的,就好比+-*/表示加减乘除,不过说到除法(/),C/C++里的整形的除法和数学里的有些不一样,C/C++里需要用两个符号一起方才能够表示一个数学里完整的除法,这两个符号分别是(/)和(%),(/)得到的结果是两数相除的整数部分,(%)得到的是余数部分,如下声明:
——————————-
int   n = 64;
        int   h  = n/60,m = n%60;


        printf(“%d : %d”,h.m);


———————————
上面的函数会打印出1:4,我想大家应该一眼就可以看出来,这其实就是计算随便输入一个分钟数,然后把他用标准小时和分钟打印出来,从这个例子里大家是不是明白了C/C++里面为什么会需要两个除法了吧,这里面的取余和取整都有很多妙用,当然具体情况还得靠大家去实现。
C/C++里面同样也有()运算,还有=,不过大家要记住一点,C/C++里面的=不是数学里面的=,C/C++里面的=是个赋值运算符,简单点说就是把右值赋给左值,通常情况下右值都是一个常量,左值是一个可变的变量,当然如果大家想要使用等号,那么记得使用“==”,也就是连写两个等号,事实上,在C/C++里面“==”存在的意义几乎就是用来断定的,通常用在if和while里面。
除了上面这些常用的运算符外,C/C++里面还有两个特殊的运算符,++ 和 –,++表示自加1,–表示自减1,如果这两个运算符出现变量的左边便是先加(减)再取变量的值,如果在右边,那就是先使用后再自加(减)给下次再使用该值。
当然C/C++里面同样存在逻辑运算符,和数学里面一样,他也有或且非,我们通常用&

&

表示或,用||表示且,用!表示非:
—————————————–
1<5 &

&

1>7     (该表达式为假,布尔值为0);
1<5 || 1>7        (该表达式为真,布尔值为1);
!(1<5 &

&

1>7)  (该表达式为真,布尔值为1);
!(1<5 &

&

1>7)  (该表达式为假,布尔值为0);
——————————————
通过上面的例子大家是不是明白了逻辑预算法的用了吧,
说了这些,就是让大家对运算符有所了解,现在我们言归正传,再回到我们刚才的正题上来。如果说刚才大家不知道该如何实现,那么现在是不是一切都在掌控之中了呢?首先把需要用的头文件包含起来,这个函数比较简单,就用一个标准输出IO就好,所以我们只需要包含stdio.h就好:
#include <stdio.h>
当然为了使用system(“PAUSE”)我们在包含另一个头文件:
#include <stdlib.h>
接下来我们分别声明三个变量,分别用来储存路程和高度
float  s = 100,h = 100;
int i = 0;
现在我们用for循环来计算高度和路程,用i来控制该循环,由于我们只需要循环9次,所以可以如下声明:
for(i;

i<9;

i++)
由于每一次反弹期的高度是上一次的一半,所以我们得出:
h = h/2;
大家是不是对这句有些疑惑,为什么h/2 就等于h了呢?这不符合数学逻辑啊,是啊,这本来就是什么数学逻辑,因为这里的h是变量,=并不表示等,而是赋值,所以这里是把上次的高度除以2后把值赋给h,从而改变了h的值。
明白了这里的赋值操作之后接下来我们应该把这个高度乘以2后加上上次的路:
 s = s + h*2;
每落地一次便是循环一次,所以每循环一次便会计算出上次反弹起的高度和所历经的路程,所以到此处我们的循环又开始下一次循环,直到循环九次后退出循环,然后打印出两关的s和h/2(第十次弹起的高度当然是我们计算出来的第九次的一半),下面我们把上面的代码整理一下:
——————————-
#include <stdio.h>
#include <stdlib.h>
int main()
{
    float h = 100,s = 100;


    
int i = 0;


     for(i;

i<9;

i++)
    {
          h = h/2;


          s = s + h*2;


     
}

      printf(” 小球下落共经过:%f米           n”,s);

    
      printf(“小球第10次落地后弹起的高度: %f米n”,h/2);

 
     system(“PAUSE”);

return  0;


}
——————————————–
好吧,现在我们来看看输出吧:
第八讲 for
至于这结果对与不对,有兴趣的同学可以自行笔算来核对一下吧。
现在想必大家都对for循环和运算符有一定的理解了,为了加深些印象,现在再留一道题给大家思考一下:
用for循环打印乘法口诀表:
提示一下吧,这里顺便说一下C/C++里的转义符:
a         警报(ANSIC)
b         退格
f         走纸
n         换行
r         回车
t         水平制表符
v         垂直制表符
\         反斜杠()
‘         单引号(‘)
”         双引号(“)
?         问题(?)
�oo       八进制值(o表示一个八进制数字)
xhh       十六进制值(h表示一个十六进制数字)