一、两种变量
局部变量:在函数内部定义
全局变量:在函数外部定义
二、 四种存储类
auto (自动类型):
修饰局部变量auto int a;
平时定义的变量都是自动变量,auto可以省略 , 没有赋初值为随机数 ,栈空间存放 ,从定义位置开始,到当前代码块结束,即局部变量用完就释放 ,作用于当前代码块。
register (寄存器类型):
修饰局部变量 register int a;
平时的变量都保存在栈中,如果有一些数据需要频繁存取,将数据存储到寄存器中,方便存取。
static (静态):
①修饰局部变量 ,static int a;
这个变量只会被初始化一次,存放在静态数据段,从定义位置开始到整个程序将结束,作用域为当前代码块,修饰全局变量 ,在全局变量的定义之前加static修饰,这个变量只能本当前文件使用,就算其他文件extern声明也不能使用。
②修饰函数 ,在函数定义之前加static
这个函数只能被当前文件下的函数调用,不能被其他文件调用,就算其他文件进行了extern声明。
extern (外部):
①修饰全局变量
定义一个全局变量,存在静态区域,当前代码结束才会释放空间 ,作用域本文件,其他文件不能使用。默认没有外部链接属性,如果其他文件要是用本文件的全局变量的话,要进行extern声明。
②修饰函数
如果函数的定义在其他文件中,需要先外部声明函数,就可以调用其他文件中的函数。
链接:
一个具有外部链接的变量可以在一个多文件程序的任何地方使用;一个具有内部链接的变量可以在一个文件的任何地方使用。
int giant=5; //文件作用域,外部链接
static int dodgers=3; //文件作用域,内部链接
三、堆空间 主动申请主动释放
#include <stdlib.h>
void *malloc(size_t size); //在堆空间中申请size个字节大小空间,返回这块空间的首地址
//int * char *
//void *:通用类型地址 相当于一级指针
//void **
int a=10;
int *p=(int *)malloc(4); //在堆空间定义一个int
int a[10];
int *p=(int *)malloc(40); //在堆空间定义一个int数组
char ch[20];
char *p=(char *)malloc(20); //在堆空间定义一个char数组
void free(void *ptr); //释放堆空间
void *calloc(size_t nmemb, size_t size);
//在堆空间中申请nmemb块,每块size个字节大小的堆空间,返回首地址,对申请的空间清空为0
/*
int a[10];
int *p=(int *)malloc(40);
int *q=(int *)calloc(10,sizeof(int)); //便于代码可读性
*/
void *realloc(void *ptr, size_t size); //修改ptr指向的堆空间的大小变为size个字节
/*
int a[10]; //数组长度固定,不能改变
int *p=(int *)malloc(40); //在堆空间定义int数组
p=realloc(p,80); //把数组长度扩充 //动态数组:数组长度可变
*/
例1:验证局部变量的生存期
#include <stdio.h>
int *fun(void)
{
//static int a; //代码正确
int a; //代码错误,局部变量a,当前代码块结束就释放,所以当函数调用结束,a就释放了,在主函数中不能使用a
a=10;
return &a;
}
int main(void)
{
int *p=fun();
*p=20; //错误
printf("%d\n",*p);
return 0;
}
例2:验证局部变量的生存期与作用域
#include <stdio.h>
int a=100;
int b=200;
int main(void)
{
printf("%d %d\n",a,b);
int a=10;
int b=20;
{
int a=5;
int b=6;
int c=30;
printf("%d %d %d\n",a,b,c); //变量使用,往上找定义语句。
}
printf("%d %d\n",a,b);
return 0;
}
例3:static修饰局部变量 这个局部变量只能被初始化一次
#include <stdio.h>
void fun(void)
{
static int a=1; //虽然多次调用这个函数,但这句话只会在第一次调用的时候执行.
a++;
printf("%d\n",a);
}
int main(void)
{
int i;
for(i=0;i<10;i++)
{
fun();
}
return 0;
}
例4:演示多个编译单位
main.c
#include <stdio.h>
int main(void)
{
fun();
return 0;
}
fun.c
#include <stdio.h>
void fun(void)
{
printf("i am fun!\n");
}
gcc main.c fun.c -o main
./main
例5:static与extern修饰函数
main.c
#include <stdio.h>
extern void fun(void);
int main(void)
{
fun();
return 0;
}
fun.c
#include <stdio.h>
static void fun(void)
{
printf("i am fun!\n");
}
例6: static与extern修饰全局变量
main.c
#include <stdio.h>
static int a=10;
int main(void)
{
fun();
printf("%d\n",a);
return 0;
}
fun.c
#include <stdio.h>
extern int a;
void fun(void)
{
printf("%d\n",a);
a=20;
printf("%d\n",a);
}
例7: 实验堆空间申请与释放函数
#include <stdio.h>
#include <stdlib.h>
int *fun(void)
{
//int a=10;
int *p=(int *)malloc(sizeof(int));
return p;
}
int main(void)
{
int *p=fun();
*p=20;
free(p);
printf("%d\n",*p);
//free(p);
return 0;
}
四、宏定义
编译预处理命令行:以#开头的行 宏定义 文件包含 条件编译 …
1、没有参数的宏
#define 宏名 替换文本 //在文件起始位置函数之外定义,没有;结尾
宏名 : 名字,变量名的规则 一般大写
替换文本 : 宏所代表的的内容
#define N 10
#define QQQ printf(“i love you”)
#define QQQ printf(“i love you!\n”);printf(“marry me!\n”);printf(“do you?\n”)
例1:
#include <stdio.h>
#define N 10
void fun(int *p)
{
int i;
for(i=0;i<N;i++)
{
p[i]=0;
}
}
int main(void)
{
int a[N];
fun(a);
int i;
for(i=0;i<N;i++)
{
printf("%d ",a[i]);
}
return 0;
}
2 、带参数的宏
#define 宏名(参数) 替换文本
#define PRINT(a) printf("%d\n",a)
要注意参数最好每个都用小括号括起来
3 、宏替换 :
它与函数调用的方法不同 ,先把宏的替换文本替换对应的宏的位置,然后把参数一一替换.
#include <stdio.h>
//#define SUM(a,b) ab
//#define SUM(a,b) (a)(b)
#define SUM(a,b) ((a)+(b)) //最安全的写法
int main(void)
{
int x=10;
int y=20;
int ret=SUM(x+y,y); //(x+y)*(y)
printf("%d\n",ret);
return 0;
}
4 、预定义符号
#include <stdio.h>
int main(void)
{
printf("%s\n",__FILE__);
printf("%d\n",__LINE__);
printf("%s\n",__FUNCTION__);
printf("%s\n",__DATE__);
printf("%s\n",__TIME__);
return 0;
}
//system() //执行一个shell命令 system("clear");