C变量

变量是程序运行时可以变化的数据。

C语言要求每个变量都有确定的类型。

语法:

修饰符 数据类型 变量名[=初始值];
#include<stdio.h>

int main(int argc,char** argv)
{
    int i = 100;
    printf("%d\n",i);
    return 0;
}

上面的代码声明了一个整型变量,名称为i,然后我们输出它。

其中的printf函数中的%d是占位符,表示将对应位置的参数按照整数的方式输出。

声明变量后,编译器会为我们分配内存来存储变量,变量名就是操作内存的入口。

编译后的代码没有变量名,只有内存地址。

C程序的内存分布

C语言程序内存分为全局区、栈和堆。

全局区用来存放全局变量,在整个程序运行开始时分配内存,程序运行中一直占用,程序退出时才释放。

栈是小片内存,一般是1M左右,用来保存局部变量和参数,当函数调用结束时,内存被释放。

堆是一片更大的内存空间,用开发者使用代码自行分配,回收时机也由开发者决定。

使用堆要用到动态内存分配和指针。

变量的生存期和作用域

生存期是指变量何时占用空间,作用域是指哪些地方可以使用变量。 生存期是程序执行时的概念,作用域是开发时的概念。 不同位置申明的变量有不同的生存期和作用域。

类型 作用域 生存期 存储位置
局部变量和参数 函数内部 函数执行
静态局部变量 函数内部 程序运行 全局
全局变量 定义文件和其他通过extern引入变量的文件 程序运行 全局
静态全局变量 定义文件 程序运行 全局

局部变量

局部变量和参数的生存期和作用域都在函数内部。

局部变量和参数在函数调用时,被分配在栈这个内存空间中。函数调用结束时被回收。

局部变量如果不初始化,变量的数值是不确定的。因此,始终初始化局部变量再使用。

全局变量

在所有函数外部定义的变量是全局变量。全局变量在整个程序运行过程都存在,程序结束由系统回收。

全局变量只会被初始化一次,如果不初始化,变量的所有字节都填充0。

静态局部变量

静态局部变量是一种特殊的全局变量,但是作用域被限定在某个函数中。

#include<stdio.h>

void f()
{
    static int i = 100;
    printf("%d\n",i);
    i=i+1;
}

int main(int argc,char** argv)
{
    f();
    f();
    return 0;
}

静态局部变量i的值只会初始化一次,后续修改会保留。

静态全局变量

静态全局变量是全局变量,但是使用范围为当前文件,不能被其他文件使用extern引入。

引入变量

使用extern修饰变量,说明该全局变量在另一个文件定义。

extern只能引入变量,不能初始化变量。

part.c

int i = 100;

main.c

#include<stdio.h>

extern int i;

int main(int argc,char** argv)
{
    printf("%d\n",i);
    return 0;
}

寄存器变量

使用register修饰的变量,是寄存器变量。寄存器是CPU中的存储空间,访问比内存快。

寄存器变量提示编译器将此变量保存到寄存器,而不是内存。

寄存器变量只是对编译器的提示,编译器不是必须要这么做。

寄存器变量无法进行取地址操作。

一般,无须使用寄存器变量,编译器会自行优化代码。

变量的默认值

局部变量如果不进行初始化,那么它的值是不确定的。

#include<stdio.h>

int main(int argc,char** argv)
{
    int i;
    printf("%d\n",i);
    return 0;
}

没有人知道输出的值是什么,它是不确定的。

之所以出现这种情况,是C语言不对代码进行任何额外的处理,不赋值就是之前栈内存中的数据。

对于全局变量,变量的所有字节都被初始化为0。对于整数和浮点数不初始化,就是0。

变量的地址

每定义一个变量,编译器都会分配内存保存变量。

通过取地址运算符&,可以获得变量的内存地址。

#include<stdio.h>

int main(int argc,char** argv)
{
    int i = 100;
    printf("%p\n",&i);
    return 0;
}

可以通过指针类型的变量来保存另一个变量的地址。

常量

常量是程序运行过程中不变的量。

语法:

const 类型 常量名;

常量和变量一样是有地址的,但是运行时不允许通过赋值修改。

const double PI = 3.14159265;
PI = 10;//编译错误。

字符串字面量也是常量,不允许进行修改。

char* s = "hello";
s[0] = 'e';

宏常量

宏常量是使用#define预处理指令定义的字面量,和常量有相似的作用。

#define PI 3.14159265

和常量不同,宏常量是预处理时进行替换,因此宏常量没有地址,只是字面量。