# 作用域
C语言变量的作用域分为:
- 代码块作用域,如
for
、while
、if
、switch
等 - 函数作用域,如
main
函数 - 文件作用域,如全局变量
# 局部作用域
局部变量的作用域是从声明开始到所在代码块结束, 也叫
auto
变量, 一般情况下代码块{}
内部定义的变量都是局部变量
- 在一个函数内部定义的变量,只能在函数内部使用
- 在复合语句中定义的变量,只能在复合语句中使用
- 随着函数调用的结束或复合语句的结束,变量的生命周期也结束了
- 如果没有初始化,局部变量的值是随机的
#include <stdio.h>
int main(void)
{
int a = 1;
{
int b = 2;
printf("a = %d, b = %d\n", a, b);
}
printf("a = %d, b = %d\n", a, b); // error: 'b' undeclared (first use in this function)
return 0;
}
# 静态局部变量
static
局部变量的作用域也是定义的函数内有效static
局部变量的生命周期是整个程序运行期间,只初始化一次,但是可以被多次赋值static
局部变量的值如果没有初始化,则由系统自动赋值:数值型变量为0,字符型变量为'\0'
,指针型变量为NULL
#include <stdio.h>
int main(void)
{
int i;
for (i = 0; i < 3; i++)
{
static int a = 1;
a++;
printf("a = %d\n", a);
}
return 0;
}
# 全局作用域
- 在函数外部定义的变量,可被本文件中的所有函数使用,也叫
extern
变量。 - 全局变量的生命周期和程序的运行周期一样,从程序开始运行到程序结束
- 不同文件中的全局变量不可以重名。
// main1.c
#include <stdio.h>
int a = 1; // 全局变量
void func(void)
{
printf("a = %d\n", a);
}
// main.c
#include <stdio.h>
extern int a = 1; // 全局变量
int main(void)
{
printf("a = %d\n", a);
return 0;
}
# 静态全局变量
- 在函数外定义,作用范围被限制在所定义的文件内
- 不同文件中的静态全局变量可以重名,但是不能在同一个文件中重名
static
全局变量的生命周期和程序的运行周期一样,同时static
全局变量的值只初始化一次,但是可以被多次赋值
// main1.c
#include <stdio.h>
static int a = 1; // 静态全局变量
void func(void)
{
printf("a = %d\n", a);
}
// main.c
#include <stdio.h>
static int a = 1; // 静态全局变量
int main(void)
{
printf("a = %d\n", a);
return 0;
}
# extern
全局变量声明
extern
全局变量的作用域是从声明开始到文件结束。
// main1.c
#include <stdio.h>
int a = 1; // 全局变量
void func(void)
{
printf("a = %d\n", a);
}
// main.c
#include <stdio.h>
extern int a; // 全局变量声明
int main(void)
{
printf("a = %d\n", a);
return 0;
}
# 全局函数和静态函数
在C语言中函数默认是全局的,使用关键字
static
可以将函数定义为静态函数,静态函数只能在本文件中使用,不能被其他文件调用。
TIP
- 允许在不同的函数中使用相同的函数名,它们代表不同的函数。
- 同一源文件中,允许全局变量和局部变量同名,但是局部变量优先级高于全局变量。
- 所有的函数默认都是全局函数,可以被其他文件调用。所以所有的函数不能重名。如果是静态函数,只能在本文件中使用,可以和其他文件中的函数重名。
// main1.c
#include <stdio.h>
static void func(void)
{
printf("func\n");
}
void func1(void)
{
printf("func1\n");
}
// main.c
#include <stdio.h>
extern void func(void); // 函数声明
extern void func1(void); // 函数声明
int main(void)
{
func(); //报错,因为func是静态函数,只能在main1.c中使用
func1(); //正确,因为func1是全局函数,可以在main.c中使用,输出`func1`
return 0;
}
# 总结
类型 | 作用域 | 生命周期 | 初始化 |
---|---|---|---|
auto 变量 | 一对大括号内 | 一对大括号内 | 随机值 |
static 变量 | 一对大括号内 | 整个程序运行期间 | 0 |
extern 变量 | 整个文件 | 整个程序运行期间 | 0 |
static 全局变量 | 整个文件 | 整个程序运行期间 | 0 |
extern 全局变量 | 整个文件 | 整个程序运行期间 | 0 |
static 函数 | 整个文件 | 整个程序运行期间 | 0 |
extern 函数 | 整个文件 | 整个程序运行期间 | 0 |
register 变量 | 一对大括号内 | 一对大括号内 | 随机值 |
全局变量 | 整个文件 | 整个程序运行期间 | 0 |
# 内存管理
# 内存分区
C语言程序在执行时,将内存大方向划分为4个区域
- 代码区:存放函数体的二进制代码,由操作系统进行管理的
存放CPU执行的机器指令,代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可
- 全局区:存放全局变量和静态变量以及常量
该区包含了在程序中所有的全局变量、静态变量、常量和字符串常量,程序结束后由系统释放
- 栈区:由编译器自动分配释放,存放函数的参数值,局部变量等
存入的是全局变量的地址,函数的参数值,局部变量等,由编译器自动分配释放,存放函数的参数值,局部变量等
- 堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
堆区是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。
# 内存操作函数
# 内存操作函数
函数 | 功能 | 参数 | 返回值 | 头文件 |
---|---|---|---|---|
memset | 内存初始化 | 目标地址、初始化值、初始化字节数 | 目标地址 | string.h |
memcpy | 内存拷贝 | 目标地址、源地址、拷贝字节数 | 目标地址 | string.h |
memmove | 内存拷贝 | 目标地址、源地址、拷贝字节数 | 目标地址 | string.h |
memcmp | 内存比较 | 内存1地址、内存2地址、比较字节数 | 相等返回0,内存1大于内存2返回1,内存1小于内存2返回-1 | string.h |
memchr | 内存查找 | 目标地址、查找字符、查找字节数 | 查找到返回目标地址,查找不到返回NULL | string.h |
memset
#include <stdio.h>
#include <string.h>
void *memset(void *s, int c, size_t n);
// 功能:将s的内存区域的前n个字节以参数c填入,返回s
// 参数:s:目标地址
// c:初始化值
// n:初始化字节数
// 返回值:目标地址
int main(void)
{
char str[10] = {0};
memset(str, 'a', sizeof(str));
printf("str = %s\n", str); // str = aaaaaaaa
return 0;
}
memcpy
#include <stdio.h>
#include <string.h>
void *memcpy(void *dest, const void *src, size_t n);
// 功能:将src的前n个字节拷贝到dest,返回dest
// 参数:dest:目标地址
// src:源地址
// n:拷贝字节数
// 返回值:目标地址
int main(void)
{
char str[10] = {0};
char str1[] = "hello";
memcpy(str, str1, sizeof(str1));
printf("str = %s\n", str); // str = hello
return 0;
}
memmove
#include <stdio.h>
#include <string.h>
void *memmove(void *dest, const void *src, size_t n);
// 功能:将src的前n个字节拷贝到dest,返回dest
// 参数:dest:目标地址
// src:源地址
// n:拷贝字节数
// 返回值:目标地址
int main(void)
{
char str[10] = {0};
char str1[] = "hello";
memmove(str, str1, sizeof(str1));
printf("str = %s\n", str); // str = hello
return 0;
}
memcmp
#include <stdio.h>
#include <string.h>
int memcmp(const void *s1, const void *s2, size_t n);
// 功能:比较s1和s2的前n个字节,返回相等返回0,s1大于s2返回1,s1小于s2返回-1
// 参数:s1:内存1地址
// s2:内存2地址
// n:比较字节数
// 返回值:相等返回0,s1大于s2返回1,s1小于s2返回-1
int main(void)
{
char str[10] = "hello";
char str1[] = "hello";
int ret = memcmp(str, str1, sizeof(str1));
printf("ret = %d\n", ret); // ret = 0
return 0;
}
# 堆内存分配和释放
函数 | 功能 | 参数 | 返回值 | 头文件 |
---|---|---|---|---|
malloc | 分配内存 | 内存大小 | 分配成功返回内存首地址,失败返回NULL | stdlib.h |
calloc | 分配内存 | 内存大小、元素个数 | 分配成功返回内存首地址,失败返回NULL | stdlib.h |
realloc | 重新分配内存 | 内存首地址、内存大小 | 分配成功返回内存首地址,失败返回NULL | stdlib.h |
free | 释放内存 | 内存首地址 | 无 | stdlib.h |
malloc
#include <stdio.h>
#include <stdlib.h>
void *malloc(size_t size);
// 功能:分配size字节的内存,返回分配的内存首地址
// 参数:size:内存大小
// 返回值:分配成功返回内存首地址,失败返回NULL
int main(void)
{
int *p = NULL;
p = (int *)malloc(sizeof(int));
if (p == NULL)
{
printf("malloc error\n");
return -1;
}
*p = 10;
printf("*p = %d\n", *p); // *p = 10
free(p);
return 0;
}
calloc
#include <stdio.h>
#include <stdlib.h>
void *calloc(size_t nitems, size_t size);
// 功能:分配nitems个size字节的内存,返回分配的内存首地址
// 参数:nitems:元素个数
// size:内存大小
// 返回值:分配成功返回内存首地址,失败返回NULL
int main(void)
{
int *p = NULL;
p = (int *)calloc(1, sizeof(int));
if (p == NULL)
{
printf("calloc error\n");
return -1;
}
*p = 10;
printf("*p = %d\n", *p); // *p = 10
free(p);
return 0;
}
realloc
#include <stdio.h>
#include <stdlib.h>
void *realloc(void *ptr, size_t size);
// 功能:重新分配内存,返回分配的内存首地址
// 参数:ptr:内存首地址
// size:内存大小
// 返回值:分配成功返回内存首地址,失败返回NULL
int main(void)
{
int *p = NULL;
p = (int *)malloc(sizeof(int));
if (p == NULL)
{
printf("malloc error\n");
return -1;
}
*p = 10;
printf("*p = %d\n", *p); // *p = 10
p = realloc(p, sizeof(int) * 2);
if (p == NULL)
{
printf("realloc error\n");
return -1;
}
printf("*p = %d\n", *p); // *p = 10
free(p);
return 0;
}
free
#include <stdio.h>
#include <stdlib.h>
void free(void *ptr);
// 功能:释放内存
// 参数:ptr:内存首地址
// 返回值:无
int main(void)
{
int *p = NULL;
p = (int *)malloc(sizeof(int));
if (p == NULL)
{
printf("malloc error\n");
return -1;
}
*p = 10;
printf("*p = %d\n", *p); // *p = 10
free(p);
printf("*p = %d\n", *p); // *p = 10
return 0;
}