1.review

 

2.变量的作用域

 

变量之分

1.局部变量

凡是大括号{}以内的变量,都是局部变量。

附:形式参数也是局部变量。其作用域,起始于定义处,截止于所在的大括号。

若未赋值,其值是随机的。


2.全局变量

凡是大括号以外的变量,都是全局变量。

其作用域起始于定义处,截止于本文件结束。

若未赋值,系统将其初始化为,零。

全局量,在多文件编程中,可以通extern声明的方式,将作用域扩展到其它文件中去。


  • 凡是在{}以内的变量称为局部变量,也包含形式参数
  • 凡是在{}以外的变量称为全局变量

  • 作用域这个概念
  • {}以内的作用域,称为局部作用域
  • {}以外的作用域,称为全部作用域
  • 同一作用域内,不可以用重名的变量。
  • 同一作用域内,不可以用重名的函数。
  • 同一作用域内,不可以用重名的标识符

作用域叠加而是指的是,全局变量同局部变量的作用域叠加
当小范围内的作用域和大范围的作用域,出现叠加,且有重名变量的时候,
小范围作用域内的变量名会覆盖大范围作用域内的变量名。
也就是通常所说的,局部变量同全局变量重名的问题。
强龙不压地头蛇。


局部变量的作用域,起始于定义处,直到所在的大括号结束
全局变量的作用域,起始于定义处,直到本文件的结束


更小的作用域
func()
{}

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

int main()
{

    int a = 10000;
    {
        int a =10;
        printf("%d\n",a);
    }
    return 0;
}




基础九_局部变量


全局命名污染

不同作用域的局部变量,既使重名也是无所谓,不会对程序的编译,造成任何的影响。

全局变量则不然!!!!!!!!

全局变量是指同一工程内的所有c文件中的全局变量,在全局作用域内,如果有重名则会造成重定义。

当一个项目,大到由n(n>1000)多个文件,有m(m>500)多个人参与开发。

在进行编译和调试的过程中会带来很多的麻烦,所以尽量少用全局变量。

除非,有人负责对全局变量进行统一管理。


3.变量生命周期和修饰符

 

生命周期(Duration)


局部变量的生命周期:
局部变量的生命周期,同其所在的函数。局部变量随着函数的执行而有生命,随着函数的执行结束而生命截止。


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



// 函数的生命周期,起于调用,结束于调用结束
// 局部变量的生命周期,起于调用,结束于调用结束


//main开始==》进程的开始
//main函数的结束==》进程的结束
//main函数的生命周期就是程序的生命周期

//全局变量的生命周期,起于main调用,结束于main调用结束,等同于程序的生命周期
//特殊的局部变量:main函数中的局部变量,生命周期和main一样

int a =999 ;

void func()
{
    int a;
}
int main()
{
    func();
    return 0;
}

修饰符(Storage Description )

修饰符放在,变量的定义的类型之前,或改变生命周期,或改变存储区域,或者均有所改变。格式如下∶

auto int a;

auto只能修饰局部变量,可以省略,局部变量若无其它的修饰,则默认为auto。它修饰的变量的特点是,随用随开,用完即消。

auto只能用于修饰局部变量,表示该变量存储于栈stack
存储于栈上的数据在有什么特点:随有随开,用完消失
默认的局部变量,就是auto类型的,所以通常将其省略

register

register存储于cpu的一个变量,速度很快,但数量有限,所以通常被优化。

只能修饰局部变量,原则上,将内存中的变量升级到CPU寄存器中存储,这样访问速度会更快。

但由于CPU寄存器数量相当有限,通常会在程序优化阶段,被优化为普通的auto类型变量。

可以通过汇编代码来查看,优化过程(具体优化,与平台和编译相关)。

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


//register存储于cpu的一个变量,速度很快,但数量有限,所以通常被优化。

int main()
{
    register int a = 5;register int b = 6;register int c = 7;register int d = 8;register int e =9;register int f = 0;register int aa = 15;register int ab = 52;register int ac = 53;register int ad = 54;register int ae = 55;register int af = 56;register int ba = 57;register int bb = 58;
    printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d",
    a,b,c,d,e,f,aa,ab,ac,ad,ae,af,ba,bb);

    return 0;
}




基础九_局部变量_02

extern

只能用来修饰全局变量,全局变量本身是全局可用的,但是由于文件是单个完成编译,并且编译是自上而下的

所以说,对于不是在本范围内定义的全局变量,要想使用必须用extern 进行声明

如果不加上extern ,就会造成重定义。

注意,经extern声明的变量,不可以再初始化。


如果main.c中没有extern int a,但是由于后面又使用了变量a,则会报错。

如果main.c中有extern int a,则编译通过,如果在链接中,其它文件中有定义,则顺利链接通过,否则的话,则会链接失败。

全局变量,本质作用域内通用,即所有的c文件中均可使用,但是由于,单文件编译,则需要声明。extern有省略用法,不讲,也不推荐。

基础九_字符串_03


基础九_作用域_04
基础九_局部变量_05

同文件使用

#include <stdio.h>extern int a;
extern int mm;
int main(int argc,char *argv[]){
	printf("%d\n",a);
	printf("mm = %d\n" ,mm);return o;
}
int mm = 300;

声明和定义的区别

声明: int a;
定义: int a =100;
但是 int a;有可能是定义,也有可能是声明

4.static修饰符

 

static修饰局部变量

static修饰,局部变量,即修改了存储区域,又修改了局部变量的生命周期。
使其生命周期同进程或是main()函数。
static变量若未初始化,则系统初始化为零,并且只进行一次初始化。

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

// static修饰局部变量,默认初始化为零

int main()
{
    static int a;
    printf("%d",a);

    return 0;
}

基础九_作用域_06

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

// static修饰局部变量,默认初始化为零
// auto修改的局部变量,存储在栈上,随有随开,用完即消
// static修改的局部变量,存储在data段上,生命周期等同于进程
// static变量的初始化,只执行一次。

void func()
{
    int a =1;
    printf("a = %d\t",a++);

    static int b =1;
    printf("b = %d\n",b++);
    printf("+++++++++++++++++++++++++\n");
}

int main()
{

    for (int i=0;i<10;i++) {
        func();
    }


    return 0;
}




基础九_局部变量_07

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

// static修饰局部变量,默认初始化为零
// auto修改的局部变量,存储在栈上,随有随开,用完即消
// static修改的局部变量,存储在data段上,生命周期等同于进程

//控制执行次数,记录打印某函数的调用次数
void print(int num, int age,char sex,float score)
{
    static int flag = 1;
    if(flag == 1)
    {
        printf( "num\tage\tsex\tscore\tidx\n" );
        flag = 0;
    }
    static int count = 0;
    printf("%d \t%d \t%c \t%.2f\t%d\n",num ,age,sex,score,++count);
}


int main()
{

    print(1001,21,'x',99.9);
    print(1001,21,'x',99.9);
    print(1001,21,'x',99.9);
    print(1001,21,'x',99.9);
    print(1001,21,'x',99.9);
    print(1001,21,'x',99.9);
    print(1001,21,'x',99.9);
    print(1001,21,'x',99.9);
    print(1001,21,'x',99.9);
    print(1001,21,'x',99.9);
    print(1001,21,'x',99.9);
    print(1001,21,'x',99.9);
}




基础九_#include_08

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMovie>
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on__start_clicked()
{
    static QMovie movie("E:\\WorkPlace\\C\\untitled\\cats.gif");//硬盘资源只需要加载一次
    ui->_show->setMovie(&movie);
    ui->_show->setVisible(true);
    movie.start();

}

void MainWindow::on__stop_clicked()
{
    ui->_show->setVisible(false);
}

基础九_字符串_09

static修饰全局变量

全局变量,会带来命名污染,全局可用,避免传参。
一个全局变量,天然的拥有外延性,可以被其它的文件所引用,extern
static修饰全局变量以后,处延性消失,变成本文件内部的全局变量
static 全局变量 也存储在 data段

也适用于函数

other.c

static int a=100;

static void func(){
	printf( "hello world\n" );
}

main.c

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

//全局变量,会带来命名污染,全局可用,避免传参。
//一个全局变量,天然的拥有外延性,可以被其它的文件所引用,extern
//static修饰全局变量以后,处延性消失,变成本文件内部的全局变量
//static 全局变量  也存储在 data段

//也适用于函数
static void func(){

printf( "hello world\n" );
}

static int a=100;
int main()
{
     func();
     printf("%d",a);
}




基础九_#include_10

5.字符串常量

 

字符串是,是由双引号,引起的一串字符。
系统在字符串常最后添加了一个字符‘\0’

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


//字符串是,是由双引号,引起的一串字符。
//系统在字符串常最后添加了一个字符‘\0’
#if 0
stack


heap
data: 全局变量  static局部变量  常量
text
endif

int main()
{
    printf( "sizeof(\"major\") = %d\n",sizeof("major")) ;
    return 0;
}

基础九_#include_11

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


//字符串是,是由双引号,引起的一串字符。
//系统在字符串常最后添加了一个字符‘\0’

int main()
{
    printf( "sizeof(\"major\") = %d\n",sizeof("major")) ;


    char *p = "major";
    printf("p = %p p+1 =%p p[0]=%c 2[p] = %c\n",p,p+1,p[0],2[p]);

    printf(" = %p  =%p =%c  = %c\n","major","major"+1,"major"[0],2["major"]);
    return 0;
}




基础九_作用域_12

c语言,是如何处理常量字符串的。将其处理一个向data段这段字符串的首地址

对比数组,三要素,起始地址,步长,范围

char*能不能代表了整个字符串,起始地址 、步长、 ‘\0’ 可以带表整个字符串

6.字符串与字符数组

 

//寻求改变,我要改变这些面的数据。
//正是因为字符数组和字符串,他们具有相同的性质,
//所以为了要改变字符串的内容,能常将常字符串,拷贝字符数组中去。

// arr[6]是栈上的空间 “china”是data一块常量区域

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

//寻求改变,我要改变这些面的数据。
//正是因为字符数组和字符串,他们具有相同的性质,
//所以为了要改变字符串的内容,能常将常字符串,拷贝字符数组中去。

// arr[6]是栈上的空间     “china”是data一块常量区域

int main()
{


    char arr[6] = "major";//他们之间存在着某种等价关系

    printf("sizeof(arr)= %d arr= %p  arr+1 = %p\t\n",
           sizeof(arr) , arr , arr+1);

    printf("sizeof( \"china\")= %d \"china\"= %p  \"china\"+1 = %p\t\n",
           sizeof("china") , "china" , "china"+1);



    return 0;
}




//字符数组和字符串这间的相同性质。并不代表字符串可以与任意的字符数组之间划等号

//等价条件:sizeof(字符数组)的大小>=sizeof(字符串)的大小
//sizeof(字符数组)的大小< sizeof(字符串)的大小此时不存在等价关系字符数组,此时只是字符数组而己

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

//字符数组和字符串这间的相同性质。并不代表字符串可以与任意的字符数组之间划等号

//等价条件:sizeof(字符数组)的大小>=sizeof(字符串)的大小
//sizeof(字符数组)的大小< sizeof(字符串)的大小此时不存在等价关系字符数组,此时只是字符数组而己

int main()
{

    char arr[2] = "major";
    printf("arr =%s\n",arr);

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


//自适应
char[]  = "mmmmmmmmmmmmmmmmmmmmmmaaaaaaaaaaaaaajjjjjjjjjjjjjjoooooooooooooooooorrrrrrrrrrrr";

7.字符串的输入与输出

 

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

//字符数组和字符串这间的相同性质。并不代表字符串可以与任意的字符数组之间划等号

//等价条件:sizeof(字符数组)的大小>=sizeof(字符串)的大小
//sizeof(字符数组)的大小< sizeof(字符串)的大小此时不存在等价关系字符数组,此时只是字符数组而己
//输入的字符串,一般越数组界,此时的数组,仅仅是字符数组而已。
//scanf遇到空格结束输入。,除非 scanf("%[^\n]s",arr); 或者用gets(arr)
//fgets比较安全


int main()
{


    char arr[100] = "major";
    printf("%s",arr);
    puts("");
    puts(arr);
    printf("********************");
    puts("");  // 换行

    char arr1[6] = "major";
    fgets(arr1,10,stdin);
    printf("%s",arr1);


    return 0;
}




基础九_局部变量_13