作用域:变量所起作用的范围。C语言变量的作用域分为:代码块作用域、函数作用域、文件作用域。
int c;//文件作用域;
fun a()
{
int b ;//函数作用域;
for(int i = 0 ;i <10;i++)
{}
//代码块作用域;
}
局部变量:在{}范围之内定义的变量;也叫auto自动变量(auto可写可不写)。有以下特点:
在一个函数内定义,只在函数范围内有效;
在符合语句中定义,只在复合语句中有效;
在运行到定义变量的时候开辟空间,随着函数调用的结束或者复合语句的结束局部变量的生命周期也结束;
如果没有赋初值,则内容为随机;
#include <stdio.h>
void test()
{
//auto 写不写是一样的;
//auto 只能出现在{}范围内部;
auto b = 10;
int a = 0;
{
int b = 1;
printf("%d",a);//a的作用域范围内;
}
printf("%d",b);//b的作用域外;
}
静态局部变量:在{}范围之内定义的变量,前面加上static修饰,如 static int a;
作用域:在定义变量的{}范围内;
生命周期:在main函数执行之前已经开辟空间,程序结束之后才释放空间;
未初始化的值:0;
void fun()
{
static int num =1;//在main函数运行之前已经开辟空间;
num++;
printf("num = %d",num);
{
static int sum = 100;
}
printf("%d",sum);//sum的作用范围也是在{}内,外面不可用;
}
int main()
{
fun();//第一次调用结果为2;
fun();//第二次调用结果为3;因为第一次调用的结果未被释放,所以第二次调用直接在上面的基础上再加1;
}
全局变量:在{}范围之外定义的变量;
作用域:作用域整个工程;
生命周期:执行main函数之前开辟空间,整个工程结束后才释放空间;
未初始化值:0
int num32;//全局变量,作用于整个工程。
//执行main函数之前开辟空间,整个工程结束后才释放空间;
void fun1()
{
num32 = 10;
}
int main()
{
printf("%d",num32);//0
fun1();
printf("%d",num32);//10
return 0 ;
}
静态全局变量:在全局变量前加static修饰。
作用域:当前文件
生命周期:从main函数执行之前开辟空间,在程序结束之后释放空间;
未初始化的值:0
int num32;//全局变量,作用于整个工程。
//执行main函数之前开辟空间,整个工程结束后才释放空间;
static int num64;//静态全局变量,作用于当前文件,不可用于其他文件;
void fun1()
{
num32 = 10;
num64 =2000;
}
int main()
{
printf("%d",num32);//0
printf("%d",num64);
fun1();
printf("%d",num32);//10
printf("%d",num64);
return 0 ;
}
6、总结:
作用域:局部变量(普通局部变量、静态局部变量)在{}范围内;普通全局变量作用于整个工程,静态全局作用域当前文件;
生命周期:只有普通局部变量是运行至定义处开辟空间,函数结束释放;其他变量都是执行main函数之前开辟空间,在程序结束之后释放空间;
未初始化的值:只有普通局部变量是随机值,其他变量都是0;
7、全局变量分文件问题:最好在.h文件中只进行声明不进行定义,.c文件中进行定义。所有变量的声明都在前面加extern。
//main.c文件
int num =0;//全局变量在其中一个分文件中定义后,可以在其他份文件通过extern引用。
extern void fun();
int main()
{
fun();
printf("%d,num);
return 0;
}
//demo.c文件;
extern int num ;
void fun()
{
num = 100;
}
8、变量重名问题
不同作用域的变量可以重名;
int num = 100;
int main()
{
int num =10;
printf("num1 = %d",num);//10
{
int num = 100;
printf("num2 = %d",num);//100
}
printf("num3 = %d",num);//10
}
9、函数作用域
全局函数:普通定义,没有任何修饰,所有文件均可使用。
静态函数:定义时函数名前用static修饰,只能被当前文件调用。
10、内存分配
栈区(普通局部变量) | |
堆区(使用时malloc动态申请) | |
静态全局区 | bss(未初始化的静态全局区) |
data(已初始化的静态全局区)(包括常量区) | |
text(代码区) |
静态全局:普通静态局部变量、全局变量、静态全局变量;
int e ;//bss
static int f;//bss;
int g = 100;//data;
static in h = 10;//data;
int main()
{
int a;//栈区;
int b = 19;//栈区;
static c ;//bss;
}
10、内存操作函数
memset()
#include <string.h>
void *memset(void *s,int c,size_t n);//将s的内存区域的前n个字节以参数c填入;
参数:s:需要操作内存s的首地址;
c:填充的字符,c虽然是int,但必须是unsigned char,范围为0~255;
n:制定需要设置的大小;
返回值:s的首地址;
memcpy():与strncpy()的区别在于遇到‘\0’时,不会中断。
#include <string.h>
void *memcpy(void*dest,const *src,size_t n);
功能:拷贝src所指的内存内容的前n个字节到dest所指的内存地址上。
参数:dest 目的内存首地址;
src 源内存首地址;dest和src不得重叠,否则报错。
n 需要拷贝的字节数;
返回值:dest的首地址。
memcmp():与strncmp的区别在于strncmp()遇到0时会中断;
#include<string.h>
int memcmp(const void *s1,const void *s2,size_t);
功能:比较s1与s2所指内存区域的前n个字节。
参数:
s1:内存首地址1;
s2:内存首地址2;
n:须比较的前n个字节;
返回值:
相等:0;
大于:>0;
小于:<0;
11、在调用过程中传递实参的地址,可以改变实参的值。
void mem_p2(char **k)//参数是指向指针的指针;
{
*k = malloc(1024);
return ;
}
int main()
{
char *p = NULL;
mem_p2(&p);//将p的地址传递给函数;
strcpy(p,"hello");
printf("%s\n",p);
return 0;
}
12、通过函数的值传递不能改变实参的值
void mem_p(char *q)
{
q = malloc(1024);
return;
}
int main()
{
char *p =NULL;
mem_p(p);//仅传递值;
strcpy(p,"hello");
return 0;
}
总结:能不能返回地址需要看这个地址所指向的空间有没有被释放。单向的值传递不能改变实参的值。