01 全局变量和局部变量
全局和局部变量
1、局部变量作用域:从创建到所在函数结束
2、如果在函数中 函数创建顺序从右往左
打印变量地址结果:从高向低增长
注意:不同函数中变量名可以一样,其所对应的地址不一样;
3、全局变量:作用在整个项目中,使用的前提是需要在使用的文件中进行声明
4、声明变量就是可以使用这个变量,声明不会分配内存空间
注意:如果在函数外部是全局变量 在函数外面是局部变量
如果全局变量写在主函数下面,想使用需要声明
全局和局部变量.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//声明变量 就是可以使用这个变量 声明不会分配内存空间
extern int a;
//全局变量 作用整个项目中 使用的前提是需要在使用的文件中进行声明
//int a = 100;
void fun01(int a, int b, int c)
{
//printf("%p\n", &c);
//printf("%p\n", &b);
//printf("%p\n", &a);
a += 10;
printf("%d\n", a);//20
//getchar();
}
int main01()
{
printf("%d\n", a);
//变量的作用范围:从创建到所在函数结束
int a = 10;
printf("=================\n");
//{//程序体 代码体 函数体}
//int *p;
//{
// printf("%d\n", a);
// int a = 1000;
// p = &a;
// printf("%d\n", a);
//}
//int b = 100;
//printf("p=%d\n", *p);
printf("=================\n");
int i = 100;
for (int i = 0; i < 10; i++)
{
printf("%d\n", i);
}
printf("%d\n", i);
printf("=================\n");
//int i = 100;
fun01(a,a,a);
printf("%d\n", a);
//system("pause");
return EXIT_SUCCESS;
}
//如果全局变量写在主函数下面 想使用需要申明
//int a = 100;
test.c
//变量的定义 分配内存空间
//全局变量
int a = 100;
02 静态、声明、函数
静态全局和局部变量
1、静态局部变量和局部变量 可以被赋值
2、静态局部变量和局部变量区别: 只能被初始化一次,可以被多次赋值
全局静态变量只能作用于当前文件中,不能在全部文件中使用
3、auto区分局部变量和全局变量
注意:定义的时候自带声明,但只能在使用它的函数之上
4、声明为严谨起见,都写在头文件 .h 中
静态函数作用域当前文件
5、一个括号之内就是未命名的函数体;
静态全局和局部变量.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//extern int a1;
extern int a2;
//static int a1 = 10;
//int a2 = 100;
void fun02()
{
//static int a = 10;
//a++;
//int a = 10;
//printf("%d\n", a++);
}
int main03()
{
//int a1 = 10;
//a1 = 100;
静态局部变量
//static int a2 = 10;
//a2 = 100;
//printf("%d\n", a1);
//printf("%d\n", a2);
//for (int i = 0; i < 10; i++)
//{
// fun02();
//}
//static int a = 10;
//赋值
//a1 = 100;
//printf("%d\n", a1);
//a2 = 1000;
printf("%d\n", a2);
system("pause");
return EXIT_SUCCESS;
}
//int a = 10;
test.c
static int a1 = 10;
int a2 = 100;
声明变量.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include "06test.h"
signed int aa = 100;
int main05()
{
//auto signed int a = 10;
//extern int a;
//int a = 10;
fun03();
system("pause");
return EXIT_SUCCESS;
}
void fun03()
{
printf("hello world");
}
test.h
#pragma once
//声明
extern int aa;
//声明
extern void fun03();
静态函数.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
extern void fun04();
int main07()
{
fun04();
system("pause");
return EXIT_SUCCESS;
}
test.c
//作用域 是当前文件
//static void fun04()
void fun04()
{
printf("hello world");
}
03 作用域和声明周期
04 内存四区模型
1、程序没有加载到内存前,可执行程序内部已经分好3段信息,分别为代码区(text)、初始化数据区(data)和未初始化数据区(bss)
2、数据区:
内存四区模型
注意:
栈区:
①只有c语言将数组放在栈区;
②如果在程序中创建的的数据应该放在堆区;栈去大小:在不同的操作系统中系统分配给每一个程序的战区空间大小不同,一般Windows是1-8M不等,一般LINUX是1-16M不等;
③死循环搞不死电脑 ,不会沾满内存但会沾满CUP;
④递归会导致程序崩溃,栈溢出;
⑤不是公用,可以被访问;
堆区:开辟堆空间大小与内存有关;
位初始化变量值.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int c;
static int d;
int main09()
{
//int a;
//static int b;
//b++;
//b *= b;
//c++;//1
//c *= c++;//1
//printf("%d\n", d);//2
int arr[7900000] = {0};//4 0000 0000
//int i = 0;
//while (1)
//{
// printf("%d",i++);
//}
//开辟堆空间
//int *p = (int *)malloc(100000000 * 10);
//getchar();
system("pause");
return EXIT_SUCCESS;
}
05 数据存储范围和内存存储方向
内中位置模型:
注意:栈区向下生长,大小端对齐
数据存储范围.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX 100
int e;
int f = 10;
static int g;
static int h = 10;
int main10()
{
int a = 10;
static int b;
static int c = 10;
int i[10];
int j[10] = { 0 };
int *k;
int *l = &a;
char *p = "hello world";
char ch[] = "hello world";
const int m = 10;
printf("局部变量a的地址:%p\n", &a);
printf("未初始化局部静态变量b的地址:%p\n", &b);
printf("初始化局部静态变量c的地址:%p\n", &c);
printf("未初始化全局变量e的地址:%p\n", &e);
printf("初始化全局变量f的地址:%p\n", &f);
printf("未初始化静态全局变量g的地址:%p\n", &g);
printf("初始化静态全局变量h的地址:%p\n", &h);
printf("未初始化数组i的地址:%p\n", i);
printf("初始化数组j的地址:%p\n", j);
printf("未初始化指针k的地址:%p\n", &k);
printf("初始化指针l的地址:%p\n", &l);
printf("字符串常量p的地址:%p\n", p);
printf("常量m的地址:%p\n", &m);
printf("字符数组ch的地址:%p\n", ch);
//printf("defien定义的常量", &100);
//printf("defien定义的常量", &MAX);
system("pause");
return EXIT_SUCCESS;
}
06 开辟堆空间和堆空间常见错误
3、malloc在内存的动态存储区(堆区)中分配一块长度为size字节的连续区域
格式:malloc(分配大小)
释放堆空间
注意:创建完的堆空间,在使用完之后不释放,会占用内存空间
4、误区:
开辟0个空间即是野指针
为野指针赋值操作
未释放空间,释放会报错
报错结果:
注意:多次释放空间会报错
5、释放空间流程
先判断在释放 释放完成 变成空指针
6、置为空,在释放程序不会报错
对空间开辟和释放.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main11()
{
int a = 10;
//定义一个变量 在堆中 单位是BYTE
//char *p = (char *)malloc(sizeof(char));
//*p = 100;
//printf("%c\n", *p);
//int arr[10];
int * p = (int *)malloc(sizeof(int) * 10);
for (int i = 0; i < 10; i++)
{
p[i] = i;
}
for (int i = 0; i < 10; i++)
//printf("%d\n", *(p + i));
printf("%d\n", p[i]);
//释放 根据首地址自动释放 如果创建完的堆空间在使用结束之后不释放 会占用系统资源
free(p);
system("pause");
return EXIT_SUCCESS;
}
堆空间的误区.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main1201()
{
//操作野指针
int * p = (int *)malloc(0);
printf("%p\n", p);
//未野指针赋值
*p = 100;
printf("%d\n", *p);
//system("pause");
//堆空间开辟没有释放 释放会报错
//free(p);
return EXIT_SUCCESS;
}
int * test01()
{
int *p = (int *)malloc(sizeof(int) * 10);
//free(p);
//p = NULL;
return p;
}
int main1202()
{
free(NULL);
int *p = test01();
if (!p)
return;
for (int i = 0; i < 10; i++)
{
p[i] = i;
}
for (int i = 0; i < 10; i++)
printf("%d\n", p[i]);
//先判断 在释放
if (p != NULL)
free(p);
//释放完成 变成空指针
p = NULL;
free(p);
return 0;
}
07 堆空间冒泡排序
①空间开辟
②随机数
③循环赋值
④冒泡排序
堆空间开辟数组冒泡排序.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <time.h>
#define MAX 10
int main13()
{
srand((unsigned int)time(NULL));
int * p = (int *)malloc(sizeof(int) * MAX);
//int len = sizeof(p)
for (int i = 0; i < MAX; i++)
{
//*(p + i) = rand() % 50;
p[i] = rand() % 50;
//*p++ = rand() % 50;
}
for (int i = 0; i < MAX; i++)
{
printf("排序前:\n");
printf("%d\n", p[i]);
}
for (int i = 0; i < MAX - 1; i++)
{
for (int j = 0; j < MAX - i - 1; j++)
{
if (p[j] > p[j + 1])
{
int temp = p[j];
p[j] = p[j + 1];
p[j + 1] = temp;
}
}
}
printf("排序前:\n");
for (int i = 0; i < MAX; i++)
{
printf("%d\n", p[i]);
}
free(p);
system("pause");
return EXIT_SUCCESS;
}
08 对空间操作字符串
8、strcopy 拷贝
strcopy操作对空间,会将拷贝的字符串全都放到堆空间中,这样就会导致超出堆空间 使程序出现错误;
注意:开辟多大堆空间,就要操做多大堆空间
堆空间操作字符串.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main1401()
{
//开辟多大堆空间 就要操作多大堆空间
char * p = malloc(sizeof(char) * 10);//\0
strcpy(p, "hello world");
printf("%s", p);
free(p);
system("pause");
return EXIT_SUCCESS;
}
int main14()
{
char arr[100] = "hello world";
arr[1] = 'A';
char * p = malloc(sizeof(char) * 100);
char * p1 = "hello world";
char * p2 = "hello world";
printf("%p\n", p1);
printf("%p\n", p2);
strcpy(p, "hello world");
*p = 'A';
printf("%p\n", p);
printf("%s\n", p);
free(p);
return 0;
}
09 内存处理函数
9、重置 memset 参数:目标 值 字节大小
注意:①memset可以重置内存区域的值 初始化值为0 但在char类型中可以初始相同的值
②memset 重置内存的值,前提是重置区域可读可写
重置数组(栈区内容)
10、memcpy拷贝:拷贝src所指的内存内容的前n个字节到dest所值的内存地址上
①可以从栈区拷贝到堆区 也可以从堆区拷贝到栈区
注意:源地址与目标地址不能发生重叠
strcpy 与mencpy的不同
①函数参数不同
②strcpy拷贝字符串 memcpy 可以拷贝一块内存
③strcpy与memcpy拷贝结束标志不同
11、memmove()功能用法和memcpy()一样,
区别在于:dest和src所指的内存空间重叠时,memmove()仍然能处理,不过执行效率比memcpy()低些。
注意:
拷贝重叠内存地址不会出现问题,但是效率比较低
如果拷贝源与拷贝目标没有重叠两个函数效率一样
12、memcmp:比较s1和s2所指向内存区域的前n个字节
类型不同,但在内存中存的ASCII码相同,所以比较的内容相同
注意:不限类型比对
13、栈内存存储过程
栈遵从规则:后进先出 先进后出
内存操作函数.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main1501()
{
//int * p = (int *)malloc(sizeof(int) * 10);
参数:目标 值 字节大小
//memset(p, 0, 40);
//for (int i = 0; i < 10; i++)
//{
// printf("%d\n", p[i]);
//}
//char * p = malloc(sizeof(char) * 10);
//memset(p, 0, 10);
//printf("%s\n", p);
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
memset(arr, 0, 40);
for (int i = 0; i < 10; i++)
{
printf("%d\n", arr[i]);
}
//free(p);
//system("pause");
return EXIT_SUCCESS;
}
int main1502()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//int *p = malloc(sizeof(int) * 10);
//memcpy(p, arr, 40);
//for (int i = 0; i < 10; i++)
//{
// printf("%d\n", p[i]);
//}
//free(p);
memcpy(&arr[2], arr, 20);
for (int i = 0; i < 10; i++)
{
printf("%d\n", arr[i]);
}
char arr1[] = { 'h','e','l','l','o' };
char * p = malloc(100);
memset(p, 0, 100);
//1、函数参数不同
//2、strcpy拷贝字符串 memcpy 可以拷贝一块内存
//3、拷贝结束标志不同 strcpy \0 memcpy 以个数为结尾
strcpy(p, arr1);
memcpy(p, arr1, 5);
printf("%s\n", p);
free(p);
return 0;
}
int main1503()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//memmove拷贝重叠内存地址不会出现问题 但是效率比较低 如果拷贝源和拷贝目标没有重叠 两个函数效率一样
memmove(&arr[2], arr, 20);
for (int i = 0; i < 10; i++)
{
printf("%d\n", arr[i]);
}
}
10 练习题思路讲解
1、求出三名学生三门功课成绩 并排序 通过堆空间实现
思路:二维数组模型arr[3][3]
①开辟一个指针的堆空间
②存三门成绩
③为三门成绩赋值
④释放:先释放内层 在释放外层
释放例图演示:
2、冒泡排序
int main()
{
//int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
//int arr2[5] = { 1,2,3,4 };
//int val = memcmp(arr1, arr2, 20);
//if (!memcmp(arr1, arr2, 8))
//{
// printf("前两个数组元素内容相同");
//}
//printf("%d\n", val);
//int * p1 = malloc(sizeof(int) * 10);
//char * p2 = malloc(sizeof(char) * 40);
//memcpy(p1, "hello", 6);
//memcpy(p2, "hello", 6);
//if (!memcmp(p1, p2, 6))
//{
// printf("内容相同\n");
//}
//else
//{
// printf("内容不相同\n");
//}
int a = 0xffff;
char b = 0xffff;
//printf("%d\n", b);
if (!memcmp(&a, &b, 2))
{
printf("内容相同\n");
}
else
{
printf("内容不相同\n");
}
//free(p1);
//free(p2);
//练习 求出三名学生 三门功课成绩 并排序 通过堆空间来实现 arr[3][3];
int ** p = (int **)malloc(sizeof(int *) * 3);
p[0] = (int *)malloc(sizeof(int) * 3);
p[1] = (int *)malloc(sizeof(int) * 3);
p[2] = (int *)malloc(sizeof(int) * 3);
p[0][0] = 90;
p[0][1] = 80;
p[0][2] = 70;
//排序
free(p[0]);
free(p[1]);
free(p[2]);
free(p);
return 0;
}