C语言基础-上

C程序的基础框架

      "最少组成",写任何代码之前先敲好

 基础变量的认知

       要先定义再使用,例如:int a = 3;

       变量的三要素: 变量名 变量值 存储单元(地址)

标识符

       由字母数字下划线组成,且只能以下划线或者字母开头,不能以数字开头。

        区分大小写

注意:编译系统将大写字母和小写字母认为是两个不同的字符。因此,sum和SUM是两个不同的变量名,同样,Class和class也是两个不同的变量名。一般而言,变量名用小写字母表示,与人们日常习惯一致,以增加可读性。

计算机的数据类型

 整数类型:基本整型(int)    短整型(short int)   长整型(long int) 双长整型(long long int)

                    字符型(char)   布尔型(bool)

浮点类型:    单精度浮点型(float)   双精度浮点型(double)  复数浮点型(float_complex,double_comple ,long long_comple)

枚举类型(enum):

                             例如一周友7天可以这样声明

                              enum  weekdays{mo,tu,wends,thur,fri,satur,sun};

                              enum weekdays w;

                              w = wends; 

注意:枚举类型的值默认从零开始

派生类型:指针类型(*)   数组类型( [ ] )  结构体类型( struct )   共用体类型(  union )  函数类型

printf()函数中%m.nf输出指定宽度

在C语言的输出中,%m.nf意义:

1、f表示输出的数据是浮点数;
2、n表示输出的数据保留小数点后n位小数,第n+1位四舍五入,若不足n位则补0;
3、m表示输出数据在终端设备上占有m个字符,并右对齐,如果实际的位数小于m时,左边用空格补足,如果实际位数大于7时,向右扩展输出。

比如:
printf("%4f\n",123.4);
printf("%2f\n",123.4);
printf("%.4f\n",123.4);
输出结果为:
123.4
123.4
123.4000

scanf( )函数的使用

     1)scanf( )函数中的"格式控制"后面应当是变量地址,而不是变量名。例如,若a和b为整型变量,如果写成

      scanf("%f%f%f"a,b,c);

      是不对的。应将“a,b,c"改为"&a,&b,&c"。许多初学者常犯此错误。

     2)如果在"格式控制字符串"中除了格式声明以外还有其他字符,则在输入数据时在对应得位置上应输入与这些字符相同得字符,如果有

      scanf("a=%f,b=%f,c=%f",&a,&b,&c);

       在输入数据时,应在对应的位置上输入同样的字符,即输入

        a=1,b=3,c=2
    3)  在输入数值数据时,如输入空格,回车,Tab键或遇非法字符(不属于数值的字符),认为该数据结束,例如:

     scanf("%d%c%f",&a,&b,&c);

     1234a123o.26

      第1个数据对应%d格式,在输入1234之后遇字符'a',因此系统认为数值1234后已没有数字了,第1个数据应到此结束,就把1234送给变量a。把其后的字符'a'送给字符变量b,由于%c只要求输入一个字符,系统判定该字符已输入结束,因此输入字符a之后不需要加空格。字符'a'后面的数值应送给变量c。如果由于疏忽把1230.26错打成123o.26,由于123后面出现字母o,就认为该数值数据到此结束,将123送给变量c,后面几个字符没有被读入。

其它输入输出的方式 

getchar( )从标准输入中获取一个字符

putchar( )将一个字符写入标准输出中

puts( ) 将字符串写入标准输出中

gets( )从标准输入中获取字符串

#include<stdio.h>

int main(void)
{
   char c;
   puts("请输入一个字符:");
   c = getchar();
   
   putchar(c);
   putchar('\n');

   return 0;
}

puts( )跟printf( )的区别:

1.puts( )自动加入换行符,printf( )需要手动加入换行符

2.printf( )支持多种格式输出,puts( )只支持字符串输出

输入输出练习题

练习:从键盘输入一个大写字母,在显示屏上显示对应的小写字母。

#include<stdio.h>

int main(void)
{
   char c;
   puts("请输入一个大写字母:");
   c = getchar(); 
   puts("对应的小写字母为:");
   putchar(c+32);
   putchar('\n');

   return 0;
}

流程控制if else语句

  C语言提供6种关系运算符:

   1)< 小于

   2)<= 小于等于

   3)>    大于

   4)>= 大于等于

   以上4个关系运算符的优先级相同

   5)  == (等于)

   6)  !=  (不等于)

   以上2个关系运算符的优先级相同,但是优先级小于前面四个关系运算符

注意

关系运算符的值只能是0或1。

关系运算符的值为真时,结果值都为1。

关系运算符的值为假时,结果值都为0。

使用if控制进行代数法交换值

练习:输入三个数,使使之按从小到大的顺序输出(冒泡排序)

#include<stdio.h>

int main(void)
{
   int i,j;
   int arr[3];
   int temp;
   puts("请输入三个整数:");
   scanf("%d%d%d",&arr[0],&arr[1],&arr[2]);

   /*冒泡排序*/
   for( i = 0; i < 2; i++)
   {
      for(j = 0;j < 2 - i; j++)
      {
             if(arr[j] > arr[j+1])
              {
                  temp = arr[j];
                  arr[j] = arr[j+1];
                  arr[j+1] = temp;
              }

      }
   }

   printf("arr[0] = %d, arr[1] = %d, arr[2] = %d\n",arr[0],arr[1],arr[2]); 

   puts("请输入三个整数:");
   scanf("%d%d%d",&arr[0],&arr[1],&arr[2]);

   /*选择排序:外层循环指明正在处理数组的哪一个元素,
              内层循环决定存放在该元素上的值*/ 
   for(i = 0; i < 2; i++)
   {
      for(j = i+1;j < 3; j++)
      {
           if(arr[i] > arr[j])
            {
                 temp = arr[i];
                 arr[i] = arr[j];
                 arr[j] = temp; 
            }
      }
   }

   printf("arr[0] = %d, arr[1] = %d, arr[2] = %d\n",arr[0],arr[1],arr[2]); 


   return 0;
}

逻辑判断与或非

C语言有三种逻辑运算符(与或非)

与运算符:   &&   例如:a && b  如果a和b都为真,则结果为真,否则为假

或运算符:    ||     例如:a || b     如果a和b有一个以上为真,则结果为真,二者都为假时,结果为假

非运算符:   !    例如: !a     如果a为假,则!a为真;如果a为真,则!a为假

ifelse编程练习

     输入一个字符,判断它是否为大写字母,如果是,将它转换成小写字母,如果不是,不转换,然后输出最后得到的字符。

#include<stdio.h>

int main(void)
{
   char c;
   puts("请输入一个字符:");
   c = getchar();
   
   if( c >= 97 && c <= 122)
         putchar(c);
   else if(c >=65 && c <= 90)
         printf("对应的小写字母为:%c",c+32);
   else
        printf("请输入正确的字符!"); 
   
   putchar('\n'); 


   return 0;
}

列表选择switchcase语句

     if语句只有两个分支可供选择,而实际问题中常常需要用到多分支的选择。例如,学生成绩分类等。当然这些都可以用嵌套的if语句来处理,但如果分支较多,则嵌套的if语句层数多,程序冗长而且可读性降低。C语言提供switch语句直接处理多分支选择。

#include<stdio.h>

int main(void)
{
   int idata;
   puts("请输入一个整数:");
   scanf("%d",&idata);

   switch(idata)
   {
        case 1:
        case 2:
               puts("满足情况1或者情况2");
               break;
        case 3:
               puts("满足情况3");
	       break;
        default:
               puts("不存在该情况!");
               break;
   }


   return 0;
}

注意事项

1)每个分支都需要加上break;否则会执行多条分支语句

2)默认分支可有可无;注意default不要拼写错误,拼写错误编译器是不会报错的。

3)case的标签可以是整型数,或者字符型(字符型本质也是整型数)。

switch练习

练习:学生成绩的划分,判断score/10的分数属于哪个分支。

#include<stdio.h>

int main(void)
{
   int score;
   puts("请输入学生的成绩:");
   scanf("%d",&score);

   switch(score/10)
   {
	   case 1:
	   case 2:
	   case 3:
	   case 4:
	   case 5:
		   puts("成绩不合格");
		   break;
	   case 6:
                   puts("成绩合格");
		   break;
	   case 7:
	   case 8:
		   puts("成绩良好");
		   break;
	   case 9:
	   case 10:
		   puts("成绩优秀");
		   break;
	   default:
		   puts("成绩非法!");
		   break;
   }


   return 0;
}

练习:根据x的值,算出对应y的值

#include<stdio.h>

int main(void)
{
   int x;
   puts("请输入x的值:");
   scanf("%d",&x);

   if(x < 1)
   {
         printf("y = %d\n",x);

   }else if(x >= 1 && x < 10)
   {
         printf("y = %d\n",2*x -1);        

   }else if( x >= 10)
   {
 	 printf("y = %d\n",3*x - 11);        
   }else
   {
         printf("输入的x值有误\n");
   }





   return 0;
}

while循环

while循环语句的形式:

 while(循环条件)                         

{

        循环语句

};

只要循环条件为非0,就会一直循环下去;只有当循环条件为0,才能结束循环.

while循环计算1到100的和

#include<stdio.h>
#include<stdlib.h>

int main(void)
{
   int sum = 0;
   int n = 100;
   while(n)
   {

       sum += n;

       n--;
   }

   printf("0到100的和为:%d\n",sum); 


   return 0;
}

whlie和do while的区别

    do while先循环一次然后再进行循环条件的判断

#include<stdio.h>
#include<stdlib.h>

int main(void)
{

   do
   {
       printf("do-while-\n");
   }while(0);

   while(0)
   {
       printf("while\n"); 
   }

   


   return 0;
}

while的表达式及for循环等价引入

1)无限循环的两种写法:  while(1);    for(;;);

2)for循环 和 while循环的等价形式如下:

for(表达式1;表达式2;表达式3)

{

       循环语句

}

无条件等价如下的while循环形式:

   表达式1

   while 表达式2

   {

          循环语句

          表达式3

    }

3个表达式的主要作用是:

表达式1:设置初始条件,只执行一次,可以为零,一个或多个变量设置初值

表达式2:是循环条件表达式,用来判定是否继续循环。在每次执行循环体前先执行此表达式,决定是否继续执行循环。

表达式3:作为循环的调整,例如使循环变量增值,它是在执行完循环体后才进行的。

这样:for语句就可以理解为

for(循环变量赋初值;循环条件;循环变量增值)

      语句

while循环和for循环的等价示例:

#include<stdio.h>
#include<stdlib.h>

int main(void)
{
  int i = 0;
  while(i < 10)
  {
      printf("i = %d\n",i);
      i++;
  }

  for(int j = 0; j < 10; j++)
     {
        printf("j = %d\n",j);
     }

   return 0;
}

循环干涉之break和continue

         break关键字的作用是提前结束循环;return的作用结束函数调用,这一点需要区分开来。

练习:在全系1000学生中,征集慈善募捐,当总数达到10万元时就结束,统计此时募捐的人数,以及平均每人捐款的数目。

#include<stdio.h>

int main(void)
{
   int total_num;
   int total_money = 0;
   int money;

   for(total_num = 0;total_num < 1000; total_num++)
   {
       printf("请输入捐款金额:\n");
       scanf("%d",&money);       
       
       total_money += money;
    
       if(total_money >= 100000)
       {
             printf("捐款金额达到10万元以上!\n"); 
             break;//跳出循环体
       } 

   } 

   printf("捐款人数为:%d 捐款的平均金额:%0.2f\n",total_num+1,(float)total_money/(total_num+1));      





   return 0;
}

关键字continue的作用是提前结束循环,直接进入下一次循环;

练习:

#include<stdio.h>

int main(void)
{

	int i;
	for(i = 100; i <= 200; i++)
	{
             if( i%3 == 0)
                continue; //如果能被3整数直接跳过进入下一次循环
             printf("%d ",i);

	}


        putchar('\n');



   return 0;
}

循环嵌套输出某个规律得数列

输出一下4*5的矩阵:

1    2     3    4     5 

2    4     6     8    10

3    6     9     12   15

4    8     12   16    20

#include<stdio.h>

int main(void)
{

   int i,j;

   for(i = 1; i < 5; i++)
   {
       for(j = 1; j < 6; j++)
       {
          printf("%d\t",i*j);
       }

       putchar('\n');
   }

   return 0;
}

练习1:水仙花数 ,是指一个三位数,其各位数字的立方和等于该数本身。求出所有水仙花数

思路:需要分离出三位数的百位 ,十位,个位;

#include<stdio.h>
#include<math.h>


int main(void)
{
   int i;
   int one;
   int ten;
   int hundred;
   for(i = 100; i < 1000; i++)
   {
        hundred = i/100;
        ten = i/10%10;
        one = i%10;     
        if(hundred*hundred*hundred + ten*ten*ten + one*one*one == i)
           printf("%d ",i); 


   }


   putchar('\n');




   return 0;
}



练习:输入两个正整数m和n,求其最大公约数和最小公倍数

辗转相除法

辗转相除法又名欧几里得算法(Euclidean algorithm),目的是求出两个正整数的最大公约数。它是已知最古老的算法,其可追溯至公元前300年前。

这条算法基于一个定理:两个正整数 a 和 b(a 大于 b),它们的最大公约数等于 a 除以 b 的余数 c 和 较小数 b 之间的最大公约数。

算法计算过程是这样的:

  • 2个数相除,得出余数

  • 如果余数不为0,则拿较小的数与余数继续相除,判断新的余数是否为0

  • 如果余数为0,则最大公约数就是本次相除中较小的数。

比如数字 25 和 10 ,使用辗转相除法求最大公约数过程如下:

  • 25 除以 10 商 2 余 5

  • 根据辗转相除法可以得出,25 和 10 的最大公约数等于 5 和 10 之间的最大公约数

  • 10 除以 5 商 2 余 0, 所以 5 和 10 之间的最大公约数为 5,因此25 和 10 的最大公约数为 5

#include<stdio.h>
#include<stdlib.h>

int main(void)
{
   int m,n;
   int temp;
   int a;
   int min;
   printf("请输入m:\n");
   scanf("%d",&m);
   printf("请输入n:\n");
   scanf("%d",&n);
   min = m*n; 
   
   if(m < n)
     {
          temp = m;
          m = n;
          n = temp;
     } 

     while(a = m%n)
     {
         m = n;
         n = a;
     }
     printf("最大公约数:%d\n",n);

     printf("最小公倍数:%d\n",min/n); 


   return 0;
}

数组的引入及基本用法

     要使用数组,必须在程序中先定义数组,即通知计算机;由哪些数据组成数组,数组中有多少元素,属于哪个数据类型,否则计算机不会自动地把一批数据作为数组处理。例如,下面是对数组的定义:

     int a[10];

     它表示定义了一个整型数组,数组名为a,此数组有10个整型元素。

      定义一维数组的一般形式为:

      类型符 数组名[常量表达式];

    注意:

             1)中括号中的数字表示数组中元素的总个数 

             2)下标法表示数组中的某个元素,从0开始计数

计算数组的大小和初始化数组的几种情况

1)全部初始化

       在定义数组时对全部数组元素赋予初值,例如:

       int a[0] = {0,1,2,3,4,5,6,7,8,9};

       将数组中各元素的初值顺序放在一对花括号内,数据间用逗号分隔,花括号内的数据就称为"初始化列表"。经过上面的定义和初始化之后,a[0] = 0, a[1]  = 1, a[2] = 2, a[3] = 3, a[4] = 4,

a[5] = 5, a[6] = 6, a[7] = 7, a[8] = 8, a[9] = 9。

 2) 部分初始化

        可以只给数组中的一部分元素赋值。例如: 

        int a[10] = {0,1,2,3,4};

        定义a数组有10个元素,但花括号内只提供5个初值,这表示只给前面5个元素赋初值,系统自动给后5个元素赋初值为0。

 3) 初始化成0

        如果想使一个数组中全部元素值为0,可以写成

        int a[10] = {0,0,0,0,0,0,0,0,0,0};  

        或

        int a[10] = {0};        //注意:未赋值的部分元素自动设为0

不指定数组大小的情况

       在对全部数组元素赋初值时,由于数据的个数已经确定,因此可以不指定数组长度。例如:

       int a[5] = {1,2,3,4,5};

       可以写成

       int a[ ] = {1,2,3,4,5};

计算数组大小的方法

        例如 : 数组a的大小为  size = sizeof(a) / sizeof(a[0]);

        sizeof是c语言关键字,也是运算符;以字节的形式给出操作数存储空间的大小

数组编程练习

练习:对10个数组元素依次赋值为0,1,2,3,4,5,6,7,8,9,要求按逆序输出。

#include<stdio.h>

int main(void)
{
    int a[10];
    for(int i = 0; i < 10; i++)
    {
         a[i] = i;
    }

    //逆序输出
    for(int i = 9; i >= 0; i--)
    {
          printf("a[%d] = %d\n",i,a[i]);
    }


    return 0;
}

练习:输出斐波那契数列前30项:0,1,1,2,3,5,8..(第n项等于 a[n] = a[n-1] + a[n-2])

#include<stdio.h>

int main(void)
{

    int a[30];
    a[0] = 0;
    a[1] = 1;
    
    for(int i = 2; i < 30; i++)
          a[i] = a[i-1] + a[i-2];

    for(int i = 0; i < 30; i++)
         printf("%d ",a[i]);
 

    putchar('\n');




    return 0;
}

冒泡排序法

      依次比较两个相邻的元素,直至最大(或最小)的元素移至数组的一侧;然后进行第二轮冒泡,一共需要进行n-1次冒泡。

#include<stdio.h>
#include<stdbool.h>

int main(void)
{
    int temp;
    int a[] = {101,1,4,8,3,2,10,54,84,33,100};
    int size = sizeof(a)/sizeof(a[0]);
    bool in_order; 

    for(int i = 0; i < size-1; i++)
    {
        in_order = true;
        for(int j = 0; j < size-1-i; j++)
           {
                 if(a[j] > a[j+1])
                 {
         		temp = a[j]; 
                        a[j] = a[j+1];
			a[j+1] = temp; 
                        in_order = false;
                 }
           }
        if( in_order)
           break;

    }

    for(int i = 0; i < size; i++)
    {
           printf("%d ",a[i]);
    }


   putchar('\n');




    return 0;
}

简单选择排序法

       将整个序列看作有序部分和无序部分;每一轮排序有序部分的元素增加一个,需要进行n-1次循环。 外层循环指明正在处理数组的哪一个元素,内层循环找出存放在该元素上的值。

#include<stdio.h>

int main(void)
{
    int temp;
    int a[] = {101,1,4,8,3,2,10,54,84,33,100};
    int size = sizeof(a)/sizeof(a[0]);

    for(int i = 0; i < size-1; i++)
    {
        for(int j = i+1; j < size; j++)
           {
                 if(a[i] > a[j])
                 {
         		temp = a[i]; 
                        a[i] = a[j];
			a[j] = temp; 
                 }
           }

    }

    for(int i = 0; i < size; i++)
    {
           printf("%d ",a[i]);
    }


   putchar('\n');




    return 0;
}

二维数组

     1) 二维数组常称为矩阵,把二维数组写成行和列的排列形式,可以有助于形象化地理解二维数组的逻辑结构。

     2)二维数组定义的一般形式为:

                  类型说明符 数组名[常量表达式][常量表达式]

                  例如:

                    float a[3][4],b[5][10];

                 定义a为3×4(3行4列)的数组,b为5×10(5行10列)的数组。

      3)c语言对二维数组采用这样的定义形式,使得二维数组可被看作是一种特殊的一维数组:它的元素又是一个一维数组。例如,可以把a看作是一个一维数组,它有3个元素:

      a[0] , a[1] , a[2]

      每个元素又是一个包含4个元素的一维数组

       a[0]  - - - a[0][0]  a[0][1]  a[0][2]  a[0][3]

       a[1]  - - - a[1][0]  a[1][1]  a[1][2]  a[1][3]

       a[2]  - - - a[2][0]  a[2][1]  a[2][2]   a[2][3]

二维数组的初始化

全部初始化

      1) 分行给二维数组赋初值。例如:

          int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};

      这种赋初值方法比较直观,把第1个花括号内的数据给第1行的元素,第2个花括号内的数据赋给第2行的元素... ... 即按行赋初值。

     2)可将所有数据写在一个花括号内,按数组元素在内存中的排列顺序对各元素赋初值。例如:

        int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};

         效果与前面相同,但是以第(1)种方法为好,一行对一行,界限清楚。用第(2)种方法如果数据多,则会写成一大片,容易遗漏,也不易检查。

部分初始化

     1)int a[3][4] = {{1},{5},{9}};

      它的作用是只对各行第1列(即序号为0的列)的元素赋初值,其余元素值自动为0,赋初值后数组各元素为:

       1   0   0    0

       5   0   0    0

       9   0   0    0

   2)如果对全部元素都赋初值(即提供全部初始数据),则定义数组时对第1维的长度可以不指定,但第2维的长度不能省。例如:

        int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};

        与下面的定义等价:

        int a[ ][4] = {1,2,3,4,5,6,7,8,9,10,11,12};

二维数组小练习

练习:有一个3×4的矩阵,要求编程求出其中值最大的那个元素的值,以及其所在的行号和列号。

思路:  定义一个变量max,假设max = a[0][0];遍历整个二维数组,判断当前元素是否比max大,如果比max大,则将该元素的值赋给max。

#include<stdio.h>

int main(void)
{

	int arr[3][4] = {
		{1,5,87,453},
		{43,77,23,11},
		{99,567,321,43},
	};

        int row;
        int column;
        int max = arr[0][0];

        for(int i = 0; i < 3; i++)
        {
		for(int j = 0; j < 4; j++)
		{
                       if( max < arr[i][j])
                        {
                             max = arr[i][j];
                             row = i;
			     column = j;
                        }
		}               
        } 


        printf("最大值:%d 在第%d行 第%d列.\n",max,row,column);



        return 0;
}

函数

     函数的作用能实现某个功能,具有复用性,避免代码的冗长。如同组装计算机一样,事先生产好各种部件(如电源,主板,硬盘驱动器,风扇等),在最后组装计算机时,用到什么就从仓库里取出什么,直接装上就可以了,绝不会采用手工业方式,在用到电源时临时去生产一个电源,用到主板时临时生产一个主板。这就是模块化程序设计的思路。

      按功能划分,每个函数代表一个功能,而函数的名字要体现函数的功能含义,类似变量标识符y=f(x);

函数三要素

    函数的三要素:

    1) 函数名(函数名要体现函数的功能)

    2) 参数列表(可以有0个形式参数,也可以有任意个形式参数)

    3)返回值

    函数在使用之前需要先定义;即 函数原型函数调用函数定义 缺一不可。如果缺少了函数原型或者函数定义,在编译时会产生如下错误:undefined reference to "函数的名字(为定义的函数名字)"。

     函数体: 具体执行什么样的功能,涉及的处理代码叫做函数体

注意事项

    在自己定义函数时,要时刻函数三要素,粗心时可能会忘记写返回值,或者参数列表中的类型不匹配,在函数调用时写错函数名都存在。函数名标志性符号就是在函数名后面有一个中括号。

形式参数和实际参数区别

     在调用有参函数时,主调函数和被调函数之间有数据传递关系。从前面已知:在定义函数时函数名后面括号中的变量名称为"形式参数"(简称"形参")。在主调函数中调用一个函数时,函数名后面括号中的参数称为"实际参数"(简称"实参")。实际参数可以是常量,变量或表达式

     注意注意:传递参数,传递的是------形参值和实参值相同,但是地址空间不同

     形参和实参虽然值,名字,类型都相同,但是地址空间不同;所以他们不是同一个变量。

局部变量

     在fun1函数中定义了变量a,b,在fun2函数中定义了变量a,c。fun1函数中变量a和fun2函数中的变量a不是同一个对象。它们分别有自己的有效范围。正如同高一甲班有一个同学叫王建国,高一乙班也有一学生叫王建国,二者不是同一个人。不同的班允许有同名的学生,互不干扰。高一甲班点名时,只有该班的王建国喊"到",乙班的王建国不在甲班活动,不会同时喊"到"的。他们的活动范围局限在本班,或者说这些名字的有效范围是局部的(只在本班有效)。

获取两个数中较大值编程示例

使用三目运算符 a < b?a:b;

#include<stdio.h>

int getMax(int a, int b);

int main(void)
{


      printf("%d\n",getMax(5,3));




        return 0;
}


int getMax(int a, int b)
{
    return a<b?b:a;

}

函数总结

1)在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。在发生函数调用时,函数的形参被临时分配内存单元。

2)将实参对应的值传递给形参。例如实参的值为2,把2传递给相应的形参x,这时形参x就得到值2,同理,形参y得到值3。

3)通过return语句将函数值带回到主调函数。执行return语句就把这个函数返回值带回主调函数main。应当注意返回值的类型与函数类型一致。

4)调用结束,形参单元被释放。注意,实参单元仍保留并维持原值,没有改变。如果在执行一个被调函数时,形参的值发生改变,不会改变主调函数的实参的值。这是因为实参与形参是两个不同的存储单元。

调用库函数

 1)如果使用库函数,应该在本文件开头用#include指令将调用有关库函数时所需用到的信息"包含"到本文件中来。例如:#include<stdio.h>

      其中"stdio.h"是一个"头文件"。在stdio.h文件中包含了输入输出库函数的声明。如果不包含"stdio.h”文件中的信息,就无法使用输入输出库中的函数。同样,使用数学库中的函数,应该用#include<math.h>。h是头文件所用的后缀,表示是头文件(header file).

2)如果使用用户自己定义的函数,而该函数的位置在调用它的函数(即主调函数)的后面(在同一个文件中),应该在主调函数中对被调的函数做声明。声明的作用是把函数名,函数参数的个数和参数类型等信息通知编译系统,以便在遇到函数调用时,编译系统能正确识别函数并检查调用是否合法。

数组和函数

     数组名作为实参传递给形参的是指针,即传递的是数组地址(或者说首元素的地址)。

     形参和实参实际上是两个不同的变量;虽然它们的类型,名,值相同,但是地址空间不同,所以本质上是不同的变量,修改形参的值并不会改变实参的值。

     而数组名作为实参传递的也是值,只不过传递的是地址;通过地址能间接访问数组元素,如果不想数组的值发生变化,可以在形参前加上const关键字。

数组和函数练习

练习:计算不同班级学生的平均分

#include<stdio.h>
#define LEN1 5
#define LEN2 10 


void initClass(int *p, int n);
void printClass(const int *p, int n);
float getAverage(const int *p, int n);


int main(void)
{
    int class1[LEN1];
    int class2[LEN2];
        
    initClass(class1,LEN1);
    initClass(class2,LEN2);

    printClass(class1,LEN1);
    printClass(class2,LEN2);


    printf("一班平均分为:%0.2f\n",getAverage(class1,LEN1));
    printf("二班平均分为:%0.2f\n",getAverage(class2,LEN2));
  

    return 0;
}

void initClass(int *p, int n)
{
    int i;
    for(i = 0; i < n; i++)
    {
	    printf("请输入%d个学生的成绩:\n",i+1);
            scanf("%d",&p[i]);
    }

    printf("\n初始化完毕!\n");
}

void printClass(const int *p, int n)
{

    int i;
    
    printf("总人数%d个\n",n);
    for(i = 0; i < n; i++,p++)
    {
           printf("%d ",*p);
    }

    putchar('\n');   
 
}



float getAverage(const int *p, int n)
{
    
    int i;
    int sum = 0;

    for(i = 0; i < n; i++,p++)
    {
          sum +=*p;
    }
 

    return (float)sum/n;
}

二维数组和函数

      二维数组是由若干个一维数组组成的,在内存中,数组是按行存放的,因此,在定义二维数组时,必须指定列数(即一行中包含几个元素),由于形参数组与实参数组类型相同,所以它们是由具有相同长度的一维数组所组成的。不能只指定第1维(行数)而省略第2维(列数),下面的写法是错误的:

       int array[3][ ];

       在第2维大小相同的前提下,形参数组的第1维可以与实参数组不同,例如,实参数组定义为:

        int score[5][10];

        而形参数组定义为:

        int  array[ ] [10];

        或

         int array[8][10];

          均可以,这时形参数组和实参数组都是由相同类型和大小的一维数组组成的。C语言编译系统不检查第一维的大小

练习:有3×4矩阵,初始化它并输出,然后求最大值并输出

#include<stdio.h>


void initArray(int (*p)[4], int n);
void printArray(const int (*p)[4], int n);
void getMaxValue(const int (*p)[4], int n);

int main(void)
{
    int arr[3][4];
    initArray(arr,3);
    printArray(arr,3);
    getMaxValue(arr,3);

    return 0;
}

void initArray(int (*p)[4], int n)
{
    int i;
    int j;

    for(i = 0; i < n; i++)
    {
       for(j = 0; j < 4; j++)
       {
           printf("请输入第%d行 第%d列的数据:\n",i,j);
           scanf("%d",*(p+i)+j);
       }
    }

}


void printArray(const int (*p)[4], int n)
{
   int i,j;
 
   for(i = 0; i < n; i++)
   {
      for(j = 0; j < 4; j++)
      {
            printf("%d\t",*(*(p+i)+j));
      }
      putchar('\n');
   }

}


void getMaxValue(const int (*p)[4], int n)
{
   int i,j;
   int maxValue = **p;  
   int max_i,max_j;   
 
   for(i = 0; i < n; i++)
   {
      for(j = 0; j < 4; j++)
      {
	      if(maxValue < *(*(p+i)+j))
	      {
		      maxValue = *(*(p+i)+j);
                      max_i = i;
                      max_j = j;
	      }


      }
   }

   printf("最大数:%d 在第%d列 在第%d行!\n",maxValue,max_i,max_j);

}



外部变量和全局变量

      在函数内部定义的变量,称为局部变量;局部变量具有块作用域,自动存储期。

      在函数外部定义的变量,称为全局变量;全局变量具有文件作用域,静态存储期。全部变量根据链接属性又分为内部链接变量,外部链接变量。内部链接变量只能在一个翻译单元使用(在一个文件中使用,使用关键字static进行修饰)。外部链接变量可以在多个文件中使用。

      全局变量也是外部变量,只不过全局变量写在文件最开头。

练习:班上10个学生,封装一个函数,调用该函数后获得班上的平均分,最高分,最低分

#include<stdio.h>
int max;
int min;

float getResult(const int *p, int n);

int main(void)
{
	int arr[] = {32,44,15,76,87,33,55,89,11,45};
	int size = sizeof(arr)/sizeof(arr[0]); 
	float average;

	average = getResult(arr, size);
        printf("最高分:%d 最低分:%d\n 班级平均分:%0.2f\n",max,min,average);

	return 0;
}


float getResult(const int *p, int n)
{
   int i;
   int sum = 0;
   max = min = *p;  
 
   for(i = 0; i < n; i++,p++)
   {
       if(max < *p)
           max = *p; 
 
       if(min > *p)
           min = *p;
          

       sum += *p; 
   }


   return  (float)sum/n;
}

封装冒泡排序和选择排序   

#include<stdio.h>
#include<stdbool.h>

void printArray(const int arr[], int size);
void bubbleSort(int *arr, int size);
void selectSort(int *arr, int size);

int main(void)
{
    int arr[] = {1,2,65,43,78,44,33,102,453,239};
    int size = sizeof(arr)/sizeof(arr[0]);
    printArray(arr,size); 
    bubbleSort(arr,size);
    printArray(arr,size); 


    int arr1[] = {1,2,65,43,78,44,33,102,453,239};
    int size1 = sizeof(arr1)/sizeof(arr1[0]);

    printArray(arr1,size1); 
    bubbleSort(arr1,size1);
    printArray(arr1,size1); 



    return 0;
}


void printArray(const int arr[], int size)
{
    int i;
    for(i = 0; i < size; i++)
    {
         printf("%d ",arr[i]);
    }
    putchar('\n');

}


void bubbleSort(int *arr,int size)
{
   int i,j;
   int temp; 
   bool in_order;   

   for(i = 0; i < size-1; i++)
   {
       in_order = true;
       for(j = 0; j < size-1-i; j++)
       {
             if(arr[j] < arr[j+1])
              {
                   temp = arr[j];
                   arr[j] = arr[j+1];
		   arr[j+1] = temp; 
                   in_order = false;
              } 
            
           if(in_order)
             break; 
       }
   }


}


void selectSort(int *arr, int size)
{
   int i,j;
   int temp;
   for(i = 0; i < size-1; i++)
   {
       for(j = i+1; j < size; j++ )
       {
            if(arr[i] < arr[j])
            {
                   temp = arr[j];
                   arr[j] = arr[j+1];
		   arr[j+1] = temp; 
            }
       }

   }   



}



练习:要求输入10个数,找出最大数以及最大数的下标

#include<stdio.h>
#include<stdbool.h>

void printArray(const int arr[], int size);
void initArray(int *arr, int size);
int getMax(const int *arr, int size, int *max_i);

int main(void)
{
    int arr[10];
    int max_i;
    int max;
    initArray(arr,10); 
    printArray(arr,10);
    max = getMax(arr,10,&max_i); 
    printf("最大值为:%d 下标为:%d\n",max,max_i);    


    return 0;
}


void printArray(const int arr[], int size)
{
    int i;
    for(i = 0; i < size; i++)
    {
         printf("%d ",arr[i]);
    }
    putchar('\n');


}

void initArray(int *arr, int size)
{
    int i;
    for(i = 0; i < size; i++,arr++)
    {
        printf("请输入第%d个元素的值:\n",i);
        scanf("%d",arr);

    }


}

int getMax(const int *arr, int size, int *max_i)
{
    int max = *arr;
    int i;
    for(i = 0; i < size; i++,arr++)
    {
	    if( max < *arr)
	    {
		    max = *arr;
                    *max_i = i;                  
	    }
    }



    return max;
}

递归函数

有5个学生坐在一起,问第一个学生多少岁,他说比第4个学生大2岁,问第4个学生岁数,他说比第3个学生大2岁,问第3个学生,又说比第2个学生大2岁,问第2个学生,说比第1个学生大2岁,最后问第1个学生,他说是10岁,请问第5个学生多大。

思路:要知道第5个多大,就得知道第4个多大...使用递归函数来求解

#include<stdio.h>

int getAge(int num);

int main(void)
{
    int num;
    printf("请输入人数:\n");
    scanf("%d",&num);

    printf("第%d个人的年龄是:%d\n",num,getAge(num));


    return 0;
}

int getAge(int num)
{
    int age;
    if(num == 1)
    {
        return 10;
    }
    age = getAge(num-1) + 2;
    return age;


}

递归求阶乘

#include<stdio.h>


int factorial(int i);

int main(void)
{
   int i;  
   printf("请输入阶乘:\n");
   scanf("%d",&i);   
  
   printf("%d的阶乘为:%d\n",i,factorial(i));


   return 0;
}


int factorial(int i)
{
    int result;
    if(i == 0)
    {
       return 1;
    }
   
    result = factorial(i-1)*i;

    return result;
}

使用递归函数封装十进制数转二级制数

      对于二进制数来说,偶数的余数是0,奇数的余数是1。因此可以通过对2取余来计算最后一位数。第一算出来的反而是最后一位,这种情况就适合使用递归函数。只要十进制数大于等于二,就说明还有余数,因此可以用该条件作为递归终止的条件。

#include<stdio.h>


void to_binary(int num)
{
    int r;
    r = num%2;

    if(num >= 2)
    {
       to_binary(num/2);
    }   
 
    printf("%d",r);

}

int main(void)
{
    int num;
    printf("请输入十进制数:\n");
    scanf("%d",&num);
    
    printf("对应的二进制数为:\n");
    to_binary(num);

    putchar('\n');

  return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值