个人用c笔记


2-7不可改变的常量

在程序执行过程中,值不发生改变的量称为常量。C语言的常量可以分为直接常量和符号常量

常量
-直接常量
-间接常量

2-8 直接常量

也称为字面量,是可以直接拿来使用无需说明的量

exp:

  • 整型常量:13、0、-13
  • 实型常量:13.33、-24.4
  • 字符常量:‘a’、’M‘
  • 字符串常量:“I love game”
printf("%d\n",233);  //整型常量
printf("%f\n",2.33); //实型常量
printf("%c\n",'A');  //字符常量
printf("I love game"); //字符串常量

在C语言中,可以用一个标识符来表示一个常量,称之为符号常量。符号常量在使用之前必需先定义,其一般形式为:

#define 标识符 常量值

2-9 强制类型转换

exp:

double num=2.33;
int numx = (int)num;
printf("%d",numx);

在使用强制转换时应注意以下问题:

1、数据类型和表达式都必须加括号,如把(int)(x/2+y)写成(int)x/2+y则成了把x转换成int型之后再除2再与y相加了。

2、转换后不会改变原数据的类型及变量值,只在本次运算中临时性转换

3、强制转换后的运算结果不遵循四舍五入原则

3-2 算数运算符

  • 加、减、乘、除:+ - * /

  • 求余运算符(模运算符): % exp:23%7=2

  • 自增运算符[?]: ++ exp: int a = 1;a++

  • 自减运算符[?]: – exp:int a = 1;a++


除法运算中注意:

如果相除的两个数都是整数的话,则结果也为整数,小数部分省略,如8/3 = 2;而两数中有一个为小数结果则为小数,如:9.0/2 = 4.500000。

取余运算中注意:

该运算只适合用两个整数进行取余运算,如:10%3 = 1;而10.0%3则是错误的;运算后的符号取决于被模数的符号,如(-10)%3 = -1;而10%(-3) = 1。

注:C语言中没有乘方这个运算符,也不能用×,÷等算术符号。

3-4 练习题

3-5 赋值运算符

exp:
+=-=*=/=%=
#include <stdio.h>
int main()
{
    int x = 10;
    int y = 10;
    //使用简单赋值语句实现x乘以2。
    x=x*2;
    //使用复合赋值语句实现y乘以2。
    y*=2;
    printf("x=%d\n", x);
    printf("y=%d\n", y);
    return 0;
}

3-6 关系运算符

exp:

#include <stdio.h>
int main()
{
    int x=5;
    int y=5;
    int z=10;
    printf("x是否大于y:%d\n",    x>y         ); //x是否大于y
    printf("y是否大于等于x:%d\n", y>=x        ); //y是否大于等于x
    printf("y是否小于z:%d\n", y<z            ); //y是否小于z
    printf("z是否小于等于x:%d\n",z<=x          ); //z是否小于等于x
    printf("z是否等于x+y:%d\n",     z=(x+y)       ); //z是否等于x+y
    return 0;
}

3-7 逻辑运算符

exp:

#include <stdio.h>
int main()
{
    int height = 175;   //身高为175cm
    double money = 1500000;  //银行存款为150万

    printf("是否符合条件:%d\n", height>=180 && money>=1000000);  //填写算式

    return 0;    
}
  1. 与运算(&&)

参与运算的两个变量都为真时,结果才为真,否则为假。例如:5>=5 && 7>5 ,运算结果为真;

  1. 或运算(||)

参与运算的两个变量只要有一个为真结果就为真。 两个量都为假时,结果为假。例如:5>=5||5>8,运算结果为真;

  1. 非运算(!)

参与运算的变量为真时,结果为假;参与运算量为假时,结果为真。例如:!(5>8),运算结果为真。


3-8 练习题

#include<stdio.h>
int main(void)
{
    int a,b;
    a=5;
    b=9;

    printf("选项A:%d",b++>a*2 && b-a<=a );
    printf("选项B:%d",b++>=a*2|| b-a<=a );
    printf("选项C:%d",!(a*2-b) );
    printf("选项D:%d",++b-a*2 );

    return 0;
}

注意英汉输入区别,上面逗号又TM弄错了

3-9 三目运算符

C语言中的三目运算符:“?:”,其格式为:

表达式1 ? 表达式2 : 表达式3;

执行过程是:

先判断表达式1的值是否为真,如果是真的话执行表达式2;如果是假的话执行表达式3。

exp:

#include <stdio.h>
int main()
{
    //定义小编兜里的钱
    double money =  12    ; 
    //定义打车回家的费用
    double cost =  11.5     ;  
    printf("小编能不能打车回家呢:"); 
    //输出y小编就打车回家了,输出n小编就不能打车回家
    printf( "%c",money>cost?'y':'n' );
    return 0;
}

3-10 运算符优先级

优先级顺序表

优先级别为1的优先级最高,优先级别为10的优先级别最低。


4-1 分支结构-简单if语句

[img

如果表达式的值为真,则执行其后的语句,否则不执行该语句

exp:

#include <stdio.h>
int main()
{
    int height;
    printf("输入你的身高:");
    scanf_s("%d", &height);


    if (height >= 175)
    {
        printf("恭喜你可以参加篮球队\t");
    }

    if (height < 175)
    {
        printf("给爷爪巴\t");
    }

    return 0;
}

4-2 分支结构之简单if-else语句

img

如果表达式的值为真,则执行代码块1,否则执行代码块2

img

#include <stdio.h>
int main() 
{
    int year = 2014; //今年是2014年
    //补全一下代码
    if( (year%4 == 0 &&year%100 != 0) || year%400 == 0    )
    {
        printf("%s\n","今年是闰年");
    }
    else
    {
        printf("%s\n","今年是平年");
    }



    return 0;
}

4-3 分支结构-多重if-else语句

img

依次判断表达式的值,当出现某个值为真时,则执行对应代码块,否则执行代码块n

img

exp(乱搞):

#include <stdio.h>
int main(void) 
{
    int score = 7200;

    //完善一下代码

    if (score >= 10000 )
    {
        printf("钻石玩家");
    }
    else if(score >= 5000)
    {
        printf("白金玩家");    
    }
    else if(score >= 1000)
    {
        printf("青铜玩家");     
    }
    else  if (score <1000)
    {
        printf("普通玩家");    
    }

    return 0;
}

4-4 分支结构-嵌套if-else语句

img

img

exp:

#include <stdio.h>
int main() 
{
    int sale=120; //销售业绩为120万
    int year=1; //刚刚进入公司1年
    //完善代码
    if (sale > 100)
    {    
        if (year >= 2)
        {
            printf("恭喜");
        }

        else
        {    
        printf("很遗憾,期望你再接再厉");

        }

    }
    else 
    {
        printf("很遗憾希望你再接再厉");
    }



    return 0;
}

4-6 循环结构-while循环

img

表达式表示循环条件,执行代码块为循环体

img

#include <stdio.h>
int main()
{
    int i,sum=0;
    i=1;
    while( i <= 100    )  //循环条件应该是什么呢?
    {
        sum=sum+i;
        i=i+1   ;      //这里是不是应该改变循环变量的值
    }
    printf("100以内所有整数之和为:%d\n", sum);
    return 0;
}

4-7 循环结构-do-whlie循环

img

它先执行循环中的执行代码块,然后再判断while中表达式是否为真,如果为真则继续循环;如果为假,则终止循环。因此,do-while循环至少要执行一次循环语句

img

exp:

#include <stdio.h>
int main()
{
    int number=200;
    int year=2014;
    do{
      year++;     
      number=number*1.2 ;                   //这里是不是应该写点什么?
    }while(number<1000);
    //这里好像缺点什么
    printf("到%d年招工规模突破1000人\n", year);
    return 0;
}

exp2:

#include <stdio.h>
int main()
{
    int number=200;
    int year=2014;
    do{
      year++;     
      number=(number*0.2)+number ;                   //这里是不是应该写点什么?
    }while(number<1000);
    //这里好像缺点什么
    printf("到%d年招工规模突破1000人\n", year);
    return 0;
}

4-8 循环结构-for循环<1>

img

img

exp:

#include <stdio.h>
int main()
{
    // 定义变量sum, num
    int sum, num;  
    sum = 0;
    for(num = 0;  num <=10  ;   num++   ) //for循环条件与num的变化值
    {
         sum=sum+num  ;  //计算每次数字之间的和sum
    }
    printf("10以内数的和为:%d", sum);
    return 0;
}

4-9 循环结构-for循环<2>

在for循环中,表达式1是一个或多个赋值语句,它用来控制变量的初始值表达式2是一个关系表达式,它决定什么时候退出循环;表达式3是循环变量的步进值,定义控制循环变量每循环一次后按什么方式变化。这三部分之间用分号(;)分开

4-10 循环结构-三种结构的比较

while、do-while和for三种循环在具体的使用场合上是有区别的,如下:

1、在知道循环次数的情况下更适合使用for循环

2、在不知道循环次数的情况下适合使用while或者do-while循环,如果有可能一次都不循环应考虑使用while循环,如果至少循环一次应考虑使用do-while循环

但是从本质上讲,while,do-while和for循环之间是可以相互转换的,如:小明被老师罚抄10次computer这个单词,分别用三种语法写:

img

三种循环结构输出的结果是完全一样的。

exp:

#include <stdio.h>
int main()
{
    /* 小伙伴们:
           选择你们认为最合理的循环结构完成功能吧 */
    int sum = 0;  //定义计算结果变量sum
    int i = 1;    //定义循环数字变量i
    int flag = 1; //定义符号状态变量flag



    //使用for循环
    for(i=1;i<=100;i++)
    {
        sum=sum+i*flag;

        flag*= -1;

    }  
    printf("sum=%d\n",sum); 

    return 0;    
}

4-11 练习题

4-12 循环结构-多重循环

在功能需求上,往往一个循环满足不了,比如:循环用一个“*”输出,得到一下图形

img

上面这个例子显然我们用一个循环不是太容易实现,这个时候我们就要用到多重循环,多重循环就是在循环结构的循环体中又出现循环结构

在实际开发中一般最多用到三层重循环。因为循环层数越多,运行时间越长,程序越复杂,所以一般用2-3层多重循环就可以了。另外不同循环之间也是可以嵌套的。

多重循环在执行的过程中,外层循环为父循环,内层循环为子循环,父循环一次,子循环需要全部执行完,直到跳出循环。父循环再进入下一次,子循环继续执行…

img

注:一个父循环可以有多个子循环

那么上面这个用“*”输出的矩形用多重循环实现如下:

#include <stdio.h>
int main()
{
    int i, j, k;
    for(i=1; i<5; i++)
    {
        /* 观察每行的空格数量,补全循环条件 */
        for( j=i  ; j<5  ; j++   )  
        {
            printf(" ");    //输出空格
        }
        /* 观察每行*号的数量,补全循环条件 */
        for( k=0 ; k<2*i-1  ; k++ ) 
        {
            printf("*");   //每行输出的*号
        }
        printf("\n");     //每次循环换行
    }
    return 0;
}

(没看懂)

4-13 使用for循环打印9x9乘法表

#include <stdio.h>
int main(void)
{
    // 定义相乘数字i,j以及结果result
    int i, j, result;
    /*
     * 使用for循环解决本题相对简单哦~
     * 小编偷偷的将源码放在任务“不会了怎么办”中了哦~
     * 小编希望童鞋们独立完成哦~
     */

    for (j = 9;j>=1 ; j--)
    {
        for (i = 1; i <= j; i++)
        {
            printf("%d*%d=%d ",j,i,j*i );
        }

        printf("\n");
    }

    return 0;
}

4-14 结束语句-break语句

实现如下:

img

运行结果:

img

使用break语句时注意以下几点:

1、在没有循环结构的情况下,break不能用在单独的if-else语句中

2、在多层循环中,一个break语句只跳出当前循环

exp:

#include <stdio.h>
int main()
{
    int m, n;
    for(m=2; m<=50; m++)
    {
        for(n=2; n<m; n++)
        {
            if(  m%n == 0  )       //什么条件下跳出当前循环
            break;            //这里应该退出当前循环了
        }    
        if(m == n)   //n循环结束后,如果m=n的话就输出m
            printf("%d  ", m);
    }
    return 0;    
}

4-15 结束语句- continue语句

img

img

continue语句的作用是结束本次循环开始执行下一次循环

break语句与continue语句的区别是:break是跳出当前整个循环,continue结束本次循环开始下一次循环。

exp:

#include <stdio.h>
int main()
{
    int i, sum;
    for(i=1, sum=0; i<=20; i++)
    {
        if( i % 3 == 0  )    //能被3整除这个条件如何写呢?
        {
            continue;             //应该用哪个循环结束语句呢?
        }                  
        sum += i;
    }
    printf("sum=%d\n", sum);
    return 0;    
}

4-16 分支结构-switch语句

img

要对紧跟在关键字switch后圆括号中的表达式求值

求值完成后,程序扫描标签(指,case ‘a’:、case ‘b’:等),直到发现一个匹配值,然后跳转到那一行。

注:若无符合标签,并且有default,则会跳转到default。否则会继续执行switch之后的语句。

img

在使用switch语句时还应注意以下几点:

1、在case后的各常量表达式的值不能相同,否则会出现错误。

2、在case子句后如果没有break;会一直往后执行一直到遇到break;才会跳出switch语句。

3、switch后面的表达式语句只能是整型或者字符类型

4、在case后,允许有多个语句,可以不用{}括起来。

5、各case和default子句的先后顺序可以变动,而不会影响程序执行结果。

6、default子句可以省略不用

exp:

#include <stdio.h>
int main() 
{
    int score = 87; //考试分数为87分 
    score /= 10;
    switch(score)
    {
        /*想想以下代码为什么用这种方式;
          这种方式的好处?*/
        case 10:
        case 9:
            printf("等级A");
            break;
        case 8:
            printf("等级B");
            break;                //这里是不是缺点什么?            
        case 7:
        case 6: 
            printf("等级C");
            break;                //这里是不是缺点什么?  
        default:
            printf("等级D");
            break;    
    }
    return 0;
}

4-17 switch与if语句的应用

请使用switch语句和if…else语句,计算2008年8月8日这一天,是该年中的第几天。

程序分析:

以5月1日为例,应该先把前4个月的天数加起来,然后再加上1天即本年的第几天。

特殊情况:

在计算闰年的时候,2月是29天。

img

#include <stdio.h>
int main() 
{ 
    /* 定义需要计算的日期 */
    int year = 2008;
    int month = 8;
    int day = 8;

    int alldays; 
    /*
     * 请使用switch语句,if...else语句完成本题
     * 如有想看小编思路的,可以点击左侧任务中的“不会了怎么办”
     * 小编还是希望大家独立完成哦~
     */
    if ((year%4 == 0 &&year%100 != 0) || year%400 == 0)

    {
        alldays = 366;
    }

    else
    {
        alldays =365;
    }


    switch()
    {




    }






    return 0;
}

未完成

4-18 练习题

4-19 goto 语句

goto语句是一种无条件分支语句,goto 语句的使用格式为:

goto 语句标号;

例如:用goto语句和if语句构成循环求10以内的数之和。

img

运行结果为: sum=55

#include <stdio.h>
int main()
{
    int sum = 0;
    int i;
    for(i=1; i<=10; i++)
    {
        printf("%d\n", i);
        if(i==3)                    //是不是少了一个判断呢?

        goto loop;//在这里使用goto语句
    }
    loop:printf("结束for循环了....");  //请选择合适位置添加标识符
    return 0;    
}

5-1 自创函数

img

注意:

1、[]包含的内容可以省略,数据类型说明省略,默认是int类型函数;参数省略表示该函数是无参函数,参数不省略表示该函数是有参函数;

2、函数名称遵循标识符命名规范

3、自定义函数尽量放在main函数之前,如果要放在main函数后面的话,需要在main函数之前先声明自定义函数,声明格式为:[数据类型说明] 函数名称([参数]);

exp:

#include <stdio.h>

/* 自定义整型函数 sayLove() */
int sayLove()
{
    printf("Love imooc");
    //在这里输入输出语句printf,输出内容为I Love imooc 

    return 0;
}

/* 自定义整型函数 dividLine() */
int dividLine()
{
    printf("%s\n", "*************");
    return 0;
}

/* 主函数 */
int main()
{
    return 0;
}

5-2 函数调用

在C语言中,函数调用的一般形式为:

函数名([参数]);

注意:

1、对无参函数调用的时候可以将[]包含的省略。

2、[]中可以是常数,变量或其它构造类型数据及表达式,各参数之间用逗号分隔。

exp:

#include <stdio.h>

/* 自定义整型函数 sayLove() */
int sayLove()
{

    //在这里输入输出语句printf,输出内容为I Love imooc 
    printf("%s\n", "I Love imooc");
    return 0;
}

/* 自定义整型函数 dividLine() */
int dividLine()
{
    printf("%s\n", "*************");
    return 0;
}

/* 主函数 */
int main()
{
    /* 调用所写函数 */
    dividLine();
    sayLove();
    dividLine();
    return 0;
}

5-3 有参与无参

在函数中不需要函数参数的称之为无参函数,在函数中需要函数参数的称之为有参函数,有参和无参函数的一般形式如下:

img

有参函数和无参函数的唯一区别在于:函数()中多了一个参数列表。

下面看一个例子对比有参和无参函数:

img

对应输出结果:

img

在该例子中,我们不难发现有参函数更为灵活,输出的图形可以随着n的改变而随意变动,只要在main函数中传递一个参数就可以了;而在无参函数中输出的相对就比较固定,当需要改动的时候还需要到自定义的方法内改变循环变量的值。

exp:

#include <stdio.h>
/* 考虑一下哪个输出该用无参函数哪个输出该用有参函数呢? */

int havecanshu(int n)
{

    printf("小明在慕课网上已经参与学习了%d门课程\n",n);

}

int wucanshu()
{
    printf("小明在慕课网上学习\n");
}


int main()
{
    wucanshu();
    havecanshu(5);
    return 0;
}

5-4 形参与无参

exp:

#include <stdio.h>
int getGirth(int a,int b,int c)
{
    if( (a+b)<=c || (a+c)<=b || (b+c)<=a )   //判断是否为三角形
    {
        printf("不构成三角形\n");
        return 0;                                
    }
    else
    {
      int cirf = a+b+c ;     //计算三角形周长
      return cirf;
    }

}

int main()
{
    /* 定义三角形三边长 */
    int a, b, c;
    a = 3;
    b = 4;
    c = 5;
    printf("三角形的周长是:%d\n", getGirth(a,b,c));  //调用周长函数
    return 0;
}

函数的参数分为形参实参两种,形参是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数实参是在调用时传递该函数的参数

函数的形参和实参具有以下特点:

  • 形参只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量。
  • 实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。因此应预先用赋值等办法使实参获得确定值。
  • 在参数传递时,实参和形参在数量上,类型上,顺序上应严格一致,否则会发生类型不匹配”的错误。

例如:以下函数multiDouble(int x)实现把x乘以2再返回给函数调用处。

img

5-5 函数的返回值

exp:

#include <stdio.h>
/* Jone算出结果应该怎么写函数? */
 int  joneResult(int x, int y, int z)
{
   int sum = x+y+z;
   return sum/3;          //这里是不是应该将sum返回呢?
}
/* Jack没有算出结果只说了一句话是不是应该用无返回值函数? */
 void jackResult(int x, int y, int z)
{
    printf("我算不出来\n");
}
int main(void)
{
    int a, b, c;
    a = 10;
    b = 20;
    c = 30;
    //Jone的返回值类型是什么?
      int   jR = joneResult(a, b, c); 
    printf("Jone运算结果是:%d\n", jR);
    printf("Jack运算结果是:");
    //Jack没有算出结果只说了句话,是不是直接调用函数就可以了?
    jackResult(a,b,c);
    return 0;
}

函数的返回值是指函数被调用之后,执行函数体中的程序段所取得的并返回给主调函数的值。

函数的返回值要注意以下几点:

\1. 函数的值只能通过return语句返回主调函数。return语句的一般形式为:

return 表达式 或者为: return (表达式);

\2. 函数值的类型和函数定义中函数的类型应保持一致。如果两者不一致,则以函数返回类型为准,自动进行类型转换。

就如小刚说选A,那么就返回一个字符型数据,用代码表示就是:

img

小刚说值为100,那么就返回一个整型数据,用代码表示就是:

img

\3. 没有返回值的函数,返回类型为void。如果小刚算了一会没有返回结果的话,那么用代码表示就是:

img

注意:void函数中可以有执行代码块,但是不能有返回值,另void函数中如果有return语句,该语句只能起到结束函数运行的功能。其格式为:return;

5-6练习题

自定义的函数中可以有多个return语句,但是只能返回一个值

5-7 递归函数(一)

那么这就要给大家引入一个新的概念——递归,递归就是一个函数在它的函数体内调用它自身。执行递归函数将反复调用其自身,每调用一次就进入新的一层。

例如:计算n的阶乘可以使用以下代码:

img

运行结果为: 5的阶乘=120

exp:

#include <stdio.h>
/* 定义获取单词数量的函数 */
int getWordNumber(int n)
{   
    if(n == 1)
    {
        return 1;    //第一天只会1个单词
    }
    else{
        return  getWordNumber(n-1)+n;       //到第天会的单词数量
    }


}
int main()
{
    int num = getWordNumber(10);     //获取会了的单词数量
    printf("小明第10天记了:%d个单词。\n", num);
    return 0;
}

5-8递归函数(二)

exp:

#include <stdio.h>
int getPeachNumber(n)
{
    int num;    //定义所剩桃子数
    if(n==10)
    {
       return 1;       //递归结束条件
    } 
    else
    {
        num = (getPeachNumber(n+1)+1)*2;   //这里是不应该用递归呢?
        printf("第%d天所剩桃子%d个\n", n, num); //天数,所剩桃子个数
    }
    return num;
}
int main()
{
    int num = getPeachNumber(1);
    printf("猴子第一天摘了:%d个桃子。\n", num);
    return 0;
}

5-9 递归函数练习

#include <stdio.h> 
/*
 * 请使用递归函数完成本题
 * 小编已将正确代码放在左侧任务的“不知道怎么办”里
 * 小编希望各位童鞋独立完成哦~
 */

int getAge(numPeople)
{
    int age;
    if (numPeople == 1)
        age = 10;
    else
        age = getAge(numPeople - 1) + 2;

    return age;
}



int main()
{
    int fifthage = getAge(5);
    printf("第5个人的年龄是%d岁", fifthage);
    return 0;
}

5-10 局部与全局

#include <stdio.h>
int x = 77;
void fn1()
{
    printf("fn1(): x=%d\n", x);       
}
int main()
{
    int x = 10;
    if(x>0)
    {
        int x = 100;
        x /= 2;
        printf("if语句内, x=%d\n", x);       
    }
    printf("main方法内, x=%d\n", x);
    fn1();
    return 0;
}
  • 在同一个函数内,变量是可以重新赋值的,在本例中如果不改动,在if内就改变了原先x的值,所以第二句话肯定是x=50;改动的话就相当于在if 语句块内声明了一个新的变量x,和main函数内声明的变量x是两个不同的变量。(对上边代码块中main()函数体中if判断中变量x的解释)

局部变量也称为内部变量。局部变量是在函数内作定义说明的。其作用域仅限于函数内, 离开该函数后再使用这种变量是非法的。在复合语句中也可定义变量,其作用域只在复合语句范围内。

全局变量也称为外部变量,它是在函数外部定义的变量。它不属于哪一个函数,它属于一个源程序文件。其作用域是整个源程序

5-11 变量存储类别(内容较多)

#include <stdio.h>
void fn()
{
    static int x = 1;   //定义静态局部变量
    x*=2;
    printf("x=%d\n",x);     
}

int main()
{
    int i;
    for(i=0;i<5;i++)
    {
        fn();
    }
    extern int x;      //调用外部变量
    printf("x=%d\n",x);
    return 0;
}
int x=100;
  • 例程使用了局部静态变量和外部变量

C语言根据变量的生存周期来划分,可以分为静态存储方式动态存储方式

静态存储方式:是指在程序运行期间分配固定的存储空间的方式。静态存储区中存放了在整个程序执行过程中都存在的变量,如全局变量。

动态存储方式:是指在程序运行期间根据需要进行动态的分配存储空间的方式。动态存储区中存放的变量是根据程序运行的需要而建立和释放的,通常包括:函数形式参数;自动变量;函数调用时的现场保护和返回地址等。

C语言中存储类别又分为四类:自动(auto)、静态(static)、寄存器的(register)和外部的(extern)。

1、用关键字auto定义的变量为自动变量,auto可以省略,auto不写则隐含定为“自动存储类别”,属于动态存储方式。如:

img

2、用static修饰的为静态变量,如果定义在函数内部的,称之为静态局部变量;如果定义在函数外部,称之为静态外部变量。如下为静态局部变量:

img

注意:静态局部变量属于静态存储类别,在静态存储区内分配存储单元,在程序整个运行期间都不释放;静态局部变量在编译时赋初值,即只赋初值一次;如果在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符(对字符变量)

3、为了提高效率,C语言允许将局部变量得值放在CPU中的寄存器中,这种变量叫“寄存器变量”,用关键字register作声明。例如:

img

注意:只有局部自动变量和形式参数可以作为寄存器变量;一个计算机系统中的寄存器数目有限,不能定义任意多个寄存器变量;局部静态变量不能定义为寄存器变量。

4、用extern声明的的变量是外部变量,外部变量的意义是某函数可以调用在该函数之后定义的变量。如:

img

5-13 内部函数与外部函数

exp:

//hello.C程序
#include <stdio.h>
#include "test.c"   //引用test.c文件
extern void printLine()
{
   printf("**************\n");   
}
int main()
{
    say();
    return 0;
}
//test.c程序
#include <stdio.h>
static void say(){
    printLine();
    printf("I love imooc\n");
    printf("good good study!\n");
    printf("day day up!\n");
    printLine();
}
  • 关于在hello.c中test.c的引用对say()函数的冲突问题解决
  • test.c被引用了,如果say()仍作为外部函数,会和hello.c中主函数下的say()重复,就没法运行了就是说你test.c被引用了的话,把say()当成内部函数就行了

在C语言中不能被其他源文件调用的函数称谓内部函数 ,内部函数由static关键字来定义,因此又被称谓静态函数,形式为:

static [数据类型] 函数名([参数])

这里的static是对函数的作用范围的一个限定,限定该函数只能在其所处的源文件中使用,因此在不同文件中出现相同的函数名称的内部函数是没有问题的。

在C语言中能被其他源文件调用的函数称谓外部函数 ,外部函数由extern关键字来定义,形式为:

extern [数据类型] 函数名([参数])

C语言规定,在没有指定函数的作用范围时,系统会默认认为是外部函数,因此当需要定义外部函数时extern也可以省略。

5-14 综合练习

6-1 数组

同样我们在程序中也需要容器,只不过该容器有点特殊,它在程序中是一块连续的,大小固定并且里面的数据类型一致的内存空间,它还有个好听的名字叫数组。可以将数组理解为大小固定,所放物品为同类的一个购物袋,在该购物袋中的物品是按一定顺序放置的。

我们来看一下如何声明一个数组:

数据类型 数组名称[长度];

数组只声明也不行啊,看一下数组是如何初始化的。说到初始化,C语言中的数组初始化是有三种形式的,分别是:

1、 数据类型 数组名称[长度n] = {元素1,元素2…元素n};

2、 数据类型 数组名称[] = {元素1,元素2…元素n};

3、 数据类型 数组名称[长度n]; 数组名称[0] = 元素1; 数组名称[1] = 元素2; 数组名称[n-1] = 元素n;

我们将数据放到数组中之后又如何获取数组中的元素呢?

获取数组元素时: 数组名称[元素所对应下标];

如:初始化一个数组 int arr[3] = {1,2,3}; 那么arr[0]就是元素1。

注意:

1、数组的下标均以0开始;

2、数组在初始化的时候,数组内元素的个数不能大于声明的数组长度;

3、如果采用第一种初始化方式,元素个数小于数组的长度时,多余的数组元素初始化为0;

4、在声明数组后没有进行初始化的时候,静态(static)和外部(extern)类型的数组元素初始化元素为0,自动(auto)类型的数组的元素初始化值不确定。

exp:

#include 
int main()
{
    //第一种形式
    int arrFirst[3] = {1,2,3};
    //第二种形式
    int arrSecond[] = {1,2,3};
    //第三种形式
    int arrThird[3];
    //给arrThird数组每个元素初始化
    arrThird[0]=1;
    arrThird[1]=2;
    arrThird[2]=3;
    //输出第一个数组中的第二个元素
    printf("%d\n", arrFirst[1]);
    //输出第二个数组中的第二个元素
    printf("%d\n", arrSecond[1]);
    //输出第三个数组中的第二个元素
    printf("%d\n", arrThird[2]);
    return 0;
}

6-2 数组的遍历

exp:

#include <stdio.h>
int main()
{
    int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    //补全代码实现对数组arr的遍历
    //可以采用你自己喜欢的循环结果
   int x;
   for(x=0;x<=9;x++)
   {
       printf("%d\n",arr[x]);
   }

    return 0;
}

数组遍历时要注意以下几点:

1、最好避免出现数组越界访问,循环变量最好不要超出数组的长度,比如:

img

2、C语言的数组长度一经声明,长度就是固定,无法改变,并且C语言并不提供计算数组长度的方法。

由于C语言是没有检查数组长度改变或者数组越界的这个机制,可能会在编辑器中编译并通过,但是结果就不能肯定了,因此还是不要越界或者改变数组的长度

6-3 练习题

6-4数组作为函数参数

exp:

#include <stdio.h>
void replaceMax(int arr[],int value)
{
    int max = arr[0];
    int index = 0;
    int i;
    for(i=1;i<5;i++)
    {
        if(arr[i]>max)
        {
           max = arr[i];            //将数组中较大的数赋值给max
            index = i;  //记录当前索引
        }                
    }  
    arr[index] = value;
}

int main()
{
    int arr1[] = {10,41,3,12,22};
    int arr2[] = {1,2,3,4,5};
    int i;
    replaceMax(arr1, arr2[0]  ); //将数组arr1和数组arr2的第一个元素传入函数中
    for(i=0;i<5;i++)
    {
        printf("%d ",arr1[i]);                
    }
    return 0;    
}

数组作为函数参数时注意以下事项:

1、数组名作为函数实参传递时,函数定义处作为接收参数的数组类型形参既可以指定长度也可以不指定长度。

2、数组元素作为函数实参传递时,数组元素类型必须与形参数据类型一致

6-5 数组的应用(一)

exp:

#include <stdio.h>
int main()
{
    double arr[]={1.78, 1.77, 1.82, 1.79, 1.85, 1.75, 1.86, 1.77, 1.81, 1.80};
    int i,j;
    printf("\n************排队前*************\n");
    for(i=0;i<10;i++)
    {
        if(i != 9)   
            printf("%.2f, ", arr[i]);  //%.2f表示小数点后精确到两位
        else
            printf("%.2f", arr[i]);    //%.2f表示小数点后精确到两位
    }
    for(i=8; i>=0; i--)
    {
        for(j=0;j<=i;j++)
        {
            if( arr[j]>arr[j+1] )      //当前面的数比后面的数大时
            {
                double temp;    //定义临时变量temp
                temp = arr[j];     //将前面的数赋值给temp
                arr[j] = arr[j+1];              //前后之数颠倒位置
                arr[j+1] = temp;              //将较大的数放在后面    
            }                 
        }                
    }
    printf("\n************排队后*************\n");
    for(i=0;i<10;i++)
    {
        if(i != 9)   
            printf("%.2f, ", arr[i]);  //%.2f表示小数点后精确到两位     
        else
            printf("%.2f", arr[i]);    //%.2f表示小数点后精确到两位
    }
    return 0;    
}

6-6数组的应用(二)

exp:

#include <stdio.h>
int getIndex(int arr[5],int value)
{
    int i;
    int index;
    for(i=0;i<5;i++)
    {
       /* 请完善数组查询功能 */
       if(arr[i]==value)       
          {
            index = i;
            break;      
          }
       else
       {
           index = -1;
       }
    }
    return index;
}

int main()
{
    int arr[5]={3,12,9,8,6};
    int value = 8;
    int index = getIndex(arr,value);      //这里应该传什么参数呢?
    if(index!=-1)
    {
        printf("%d在数组中存在,下标为:%d\n",value,index);             
    }
    else
    {
        printf("%d在数组中不存在。\n",value);    
    }
    return 0;    
}

6-7字符串与数组

#include <stdio.h>
/* 定义say函数 */
void say(char string[])       //数组参数应该怎么写呢?
{
    printf("%s\n",string);     //打印字符串
}

int main()
{
    //定义字符串数组
    char string[] = "我在慕课网上学习IT技能!";
    say(string);                 //调用say函数输出字符串
    return 0;
}

6-8 字符串格式

img

exp:

#include <stdio.h>
#include <string.h>
int main()
{
    char s1[100]="";
    char s2[]="我爱,";
    char s3[]="慕课网";
    /*在以下补全代码*/

    strcpy(s1,s2);
    strcat(s1,s3);

    printf("%s\n",s1);
    return 0;    
}

6-9 多维数组

#include <stdio.h>
int main()
{
    int arr1[2][2]={{10,20},{20,40}};
    //使用第一种方式初始化方式声明并初始化二维数组arr1
    int arr2[2][2];
    int arr2[0][0]=10;
    int arr2[0][1]=20;
    int arr2[1][0]=30;
    int arr2[1][1]=40;
    //使用第二种方式初始化方式声明并初始化二维数组arr2

    return 0;    
}

6-10 练习题

解析:二维数组定义的时候,可以不指定行的数量,但是必须指定列的数量。可以查看多维数组这节的相关知识
友情链接: http://www.imooc.com/code/5636


文章作者: 张百川
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 张百川 !
评论
  目录