局部变量
概念:定义在函数内部的变量
作用域:从定义位置开始,到包裹该变量的第一个右大括号结束
全局变量
概念:定义在函数外部的变量
作用域:从定义位置开始,默认到文件结束位置,其他文件如果想使用,可以使用声明的方式将作用域导出
1.extern修饰的全局变量可以使用其他文件的定义
2.全局变量的默认值为0
//test15.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int a = 10;
int main15(void)
{
printf("test15->a=%d\n", a);
return 0;
}
//test15-extern.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
extern int a;
int main(void)
{
printf("test15-extern->a=%d\n", a);
return 0;
}
静态全局变量
static int a = 10;//定义在函数外
作用域:被限制在本文件内部,不允许其他文件通过extern导入
静态局部变量
static int a = 10;//定义在函数内
特性:静态局部变量只定义一次,函数调用结束后静态局部变量没有销毁,下一次调用函数时依旧可以使用
作用域:同局部变量
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
static int a = 10;
void test1501() {
static int b = 10;
printf("b=%d\n", b++);
}
int main(void)
{
//printf("test15->a=%d\n", a);
for (int i = 0; i < 5; i++) {
test1501();
}
return 0;
}
运行结果:
b=10
b=11
b=12
b=13
b=14
全局函数
定义语法:函数原型+函数体
static函数
定义语法:static+函数原型+函数体
作用域:只能在本文件内部使用,其他文件即使声明也无法使用
生命周期
- 局部变量:从变量定义开始到函数调用完成结束
- 全局变量:从代码加载到内存(程序启动)开始,到程序终止结束
- static局部变量:同全局变量
- static全局变量:同全局变量
- 全局函数:同全局变量
- 静态static函数:同全局变量
命名冲突就近原则
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
static int a = 10;
int main(void)
{
int a = 20;
printf("test15->a=%d\n", a);//输出20
return 0;
}
内存
- 程序运行时使用到的内存区域按如下4区划分
代码段:text段,程序源代码(二进制形式)
数据段:只读数据段.rodata段;初始化数据段.data段;未初始化数据段.bss段
stack:栈,在栈上开辟栈帧
heap:堆,给用户自定义数据提供空间
- 堆空间申请和使用
-
开辟heap空间
void* malloc(size_t size);
功能:申请size大小的空间,返回实际申请到的内存空间首地址 -
释放heap空间
void free(void *ptr);
1.malloc申请的空间是连续的,可以当做数组使用
2.free后的内存里数据会清空,但是指针没有失效,依旧指向申请到的内存空间首地址,所以通常free后可以手动将指针置为NULL
3.free的地址必须是malloc申请返回的地址,否则会出错
4.如果malloc之后的地址一定会变化,可以使用临时变量保存地址
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
//int arr[1000000] = { 10,20,40 };
//申请堆内存,堆空间大于栈空间,可以使用的内存更多
int *p = (int*)malloc(sizeof(int) * 1000000);
if (p == NULL) {
printf("malloc error\n");
return -1;
}
for (size_t i = 0; i < 10; i++)
{
p[i] = i + 10;
}
for (size_t i = 0; i < 10; i++)
{
printf("%d ", p[i]);
}
putchar('\n');
//释放申请的堆内存
free(p);
p=NULL;
return 0;
}
- 二级malloc
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
//申请空间
int** p = malloc(sizeof(int*)*3);
for (size_t i = 0; i < 3; i++)
{
p[i]=malloc(sizeof(int) * 5);
}
//写空间
for (size_t i = 0; i < 3; i++)
{
for (size_t j = 0; j < 5; j++)
{
p[i][j] = i+j;
}
}
//读空间
for (size_t i = 0; i < 3; i++)
{
for (size_t j = 0; j < 5; j++)
{
printf("%d ", *(*(p+i)+j));
}
printf("\n");
}
//释放空间
for (size_t i = 0; i < 3; i++)
{
free(p[i]);
p[i] = NULL;
}
free(p);
p = NULL;
return 0;
}
- 内存操作函数
void* memset(void* buff,int c,size_t n)
函数作用:按字节重置内存数据
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char* p = (char*)malloc(sizeof(char) * 10);
memset(p, 65, 10);
for (size_t i = 0; i < 10; i++)
{
printf("%c ", p[i]);
}
printf("\n");
free(p);
return 0;
}
void* memcpy(void* dest,const void* src,size_t n);
函数作用:拷贝src的n个字节到dest
strcpy与memcpy的区别:
1.strcpy拷贝字符串,memcpy可以拷贝一块内存
2.拷贝结束标识不同,strcpy以’\0’结束,memcpy按字节数数拷贝
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
int* p = malloc(sizeof(int) * 10);
memcpy(p, arr, 40);
for (size_t i = 0; i < 10; i++)
{
printf("%d ", p[i]);
}
printf("\n");
free(p);
return 0;
}
void* memmove(void* dest,const void* src,size_t n);
函数功能:和memcpy一样,区别在于dest和src所指内存空间重叠时,memmove效率比memcpy低,memmove要使用额外空间存储重叠区域
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
memmove(&arr[5], arr, 20);
for (size_t i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
int memcmp(const void* buf1, const void* buf2,size_t n)
函数作用:比较buf1和buf2的前n个字节,前n个字节相等返回0,buf1>buf2返回1,buf1<buf2返回-1
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int arr1[10] = {1,2,3,4,5,6,7,8,9,0};
int arr2[5] = {1,2,3,4,7};
int val = memcmp(arr1, arr2,20);
printf("%d", val);
return 0;
}