百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

C语言函数和变量的作用域,memset()、memcpy()内存处理函数

liebian365 2024-11-16 23:10 19 浏览 0 评论

1、变量的作用域、生命周期和存储位置

变量类型

作用域

生命周期

存储位置

局部变量

函数内部

从局部变量创建到函数结束

栈区

全局变量

项目中所有文件

从程序创建到程序销毁

数据区

静态局部变量

函数内部

从程序创建到程序销毁

数据区

静态全局变量

定义所在的文件中

从程序创建到程序销毁

数据区

1.1局部变量

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>

void fun01(int a)
{
	int b = 20;
}

int main01()
{
	//定义变量 局部变量  在函数内部定义的变量
	//作用域:在函数内部
	//生命周期:从创建到函数结束

	auto int a = 10;//auto平时省略
	printf("%d\n", a);
	return 0;
}

1.2全局变量

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>

//全局变量存在数据区		全局变量可以与局部变量重名,采用就近原则 
//全局变量 在函数外部定义的量
//作用域:整个项目中所有文件  如果在其他文件中使用需要声明
//声明周期:从程序创建到程序销毁 
int a = 10;

void fun02()
{
	a = 100;
	printf("%d\n", a);
}
int main02()
{
	printf("%d\n", a);
	int a = 123;//数据在操作时会采用就近原则
	printf("%p\n", &a);
	{//匿名内部函数
		//int a = 456;
		a = 567;
		printf("%p\n", &a);
		printf("%d\n", a);
	}
	printf("%d\n", a);//a=456时,此时打印结果为456;int a=456时结果还是123
	fun02();
	fun03();
	return 0;

}
#include<stdio.h>

extern int a;//要在其他文件中调用a 需要在此声明
//int a = 110;//err全局变量名称不可重复
void fun03()
{
	printf("%d\n", a);
}
//void BubbleSort(int a, int b, int c)
//{
//  C 语言中全局函数的名称是作用域中唯一的
//}


void BubbleSort(int* src, int len)
{
	for (int i = 0; i < len - 1; i++)//外层控制行
	{
		for (int j = 0; j < len - 1 - i; j++)
			//内层控制列,10个数字对比9次 9个数字对比8次,故j<10-1-i  
		{
			if (src[j] < src[j + 1])//升序排列,将 < 改为 > 则成降序排列
			{
				int temp = src[j];
				src[j] = src[j + 1];
				src[j + 1] = temp;
			}
		}

	}
	for (int i = 0; i < 10; i++)
	{
		printf("%d\n", src[i]);
	}
	return 0;
}

1.3静态局部变量

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>

void fun04()
{
	//静态局部变量只初始化一次  可以多次赋值
	//在数据区进行存储
	//作用域:只能在函数内部使用
	//声明周期:从程序创建到程序销毁
	static int b = 10;
	b++;
	printf("%d\n", b);
}

int main()
{
	//静态局部变量  只能在本函数中使用
	//static int b = 10;
	//printf("%d\n", b); 
	for (int i = 0; i < 10; i++)
	{
		fun04();
	}
	return 0;
}

1.4静态全局变量

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>


//静态全局变量
//作用域:可以在本文件中使用  不可以在其他文件中使用
//声明周期:从程序创建到程序销毁
static int c = 10;
void fun05()
{
	c = 20;
	printf("%d\n", c);
}
int main04()
{
	printf("%d\n", c);
	fun05();
	//fun06();
	return 0;

}

2、未初始化函数

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>

//未初始化全局变量
//int abc;
//未初始化的静态全局变量
static int abc; 
int main05()
{
	//int abc;//局部变量未初始化值为乱码
	static int abc;//未初始化的静态局部变量 
	printf("%d\n", abc);
	return 0;
}

3、全局函数和静态函数

在C语言中函数默认都是全局的,使用关键字static可以将函数声明为静态,函数定义为static就意味着这个函数只能

在定义这个函数的文件中使用,在其他文件中不能调用,即使在其他文件中声明这个函数都没用。

对于不同文件中的static函数名字可以相同。

函数类型

作用域

生命周期

存储位置

全局函数

项目所有文件

从程序创建道程序销毁

代码区

静态函数

定义所在文件中

从程序创建到程序销毁

代码区

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>

//函数可以调用自己  称为递归函数
void BubbleSort(int*, int);
int main0601()
{
	int arr[] = { 9,1,5,6,8,2,7,10,4,3 };
	BubbleSort(arr,10);
	//C 语言中全局函数的名称是作用域中唯一的
	//作用域:在整个项目中所有文件中使用
	for (int i = 0; i < 10; i++)
	{
		printf("%d\n", arr[i]);

	}
	return 0;
}
void fun07();
//静态函数
//静态函数可以和全局函数重名
//作用域:当前文件中
//生命周期:从程序创建到程序销毁
static void fun07()
{
	printf("hello world2\n");
}
int main0602(void)
{
	fun07();
}

4、数据存储位置

代码区(text segment):加载的是可执行文件代码段,所有的可执行代码都加载到代码区,这块内存是不可以

在运行期间修改的。

未初始化数据区(BSS):加载的是可执行文件BSS段,位置可以分开亦可以紧靠数据段,存储于数据段的数据

(全局未初始化,静态未初始化数据)的生存周期为整个程序运行过程。

全局初始化数据区/静态数据区(data segment):加载的是可执行文件数据段,存储于数据段(全局初始化,静态初始化数据,

文字常量(只读))的数据的生存周期为整个程序运行过程。

栈区(stack):栈是一种先进后出的内存结构,由编译器自动分配释放,存放函数的参数值、返回值、局部变量等。在程序运行

过程中实时加载和释放,因此,局部变量生存周期为申请到释放该段栈空间。

堆区(heap):堆是一个大容器,它的容量要远远大于栈,但没有栈那样先进后出的顺序。用于发动态分布内存。堆在内存中位于

BSS区和栈区之间。一般由程序员分配和释放,若程序员不释放,程序结束时操作系统回收。


代码区:
程序执行二进制码(程序指令)

共享
只读

数据区:
1、初始化数据区(date)
2、未初始化数据区(bss)
3、常量区

内存四区

栈区:
系统为每一个应用程序分配一个临时
空间。
1、局部变量
2、函数信息
3、函数参数
4、数组
栈区大小为:1M
在windows中可扩展到10M
在linux中可扩展到16M

堆区:
存储大数据,图片,音乐,视频

需要手动开辟 malloc
手动释放 free

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>

//安全的常量 存储区域为数据区中的常量区
const int abc = 123;
//未初始化全局变量
int a1;
//初始化全局变量
int b1 = 10;
//未初始化静态全局变量
static int c1;
//初始化静态全局变量
static int d1 = 10;
int main0701()
{
	int e1 = 10;
	//未初始化局部变量
	static int f1;
	//初始化局部变量
	static int h1 = 10;
	//字符串常量
	char* p = "hello world";
	int arr[] = { 1,2,3,4 };//数组
	int* pp = arr;//指针
	printf("未初始化全局变量:%p\n", &a1);
	printf("初始化全局变量:%p\n", &b1);
	printf("未初始化静态全局变量:%p\n", &c1);
	printf("初始化静态全局变量:%p\n", &d1);

	printf("局部变量:%p\n", &e1);
	printf("未初始化的静态局部变量:%p\n",& f1);
	printf("初始化的静态局部变量:%p\n", &h1);
	printf("字符串常量:%p\n", p);
	printf("数组:%p\n", arr);
	printf("指针变量:%p\n", pp);
	printf("指针地址:%p\n", &pp);
	return 0;
}

5、栈区存储模型

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>

int swap(int a, int b)
{
	printf("a=%p\n", &a);
	printf("b=%p\n", &b);
	int temp = a;
	a = b;
	b = temp;
	return a,b;
}

int main0801()
{
	int a = 10;
	int b = 20;

	printf("a=%p\n", &a);
	printf("b=%p\n", &b);
	swap(a, b);
	printf("%d\n", a);
	printf("%d\n", a);
	return 0;
}

6、堆空间开辟和使用

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>

int main0901()//开辟堆空间 malloc()、free()
{
	//栈区大小  1M
	//int arr[210000] = { 0 };

	
	int* p =(int*) malloc(sizeof(int));//开辟堆空间存储数据
	printf("%p\n", p);
	
	*p = 123;//使用堆空间(初始化)
	printf("%d\n", *p);
	
	free(p);//释放堆空间
	p = NULL;
	// p 野指针出现可能报错也可能不报错 尽量避免出现
	/*printf("%p\n", p);
	*p = 456;
	printf("%d\n", *p);*/   // 不报错 可以读取 地址和数据 但是野指针
	return 0;
}

int main0902()
{
	//int* p = (int*)malloc(sizeof(int) * 8200000*10*10/3);
	//printf("%p\n", p);
	//free(p);

	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));//将赋值输出
	}
	free(p);
	//if (p = NULL)
	//{
	//	printf("程序异常\n");
	//	return -1;

	//}
	return 0;

}

7、练习题

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>
#define MAX 10
void BubbleSort(int* src, int len);//声明冒泡排序法 下面调用

int main010()
{
	srand((size_t)time(NULL));//添加随机数种子
	int* p = (int*)malloc(sizeof(int) * MAX);

	printf("%p\n", p);
	for (int i = 0; i < MAX; i++)
	{
		p[i] = rand() % 100;//获取0~99的随机数
		printf("%d ", p[i]);
	}
	printf("\n");
	BubbleSort(p, MAX);//冒泡排序法
	for (int i = 0; i < MAX; i++)//将排序好数组的输出
	{
		//printf("%d\n", p[i]);
		printf("%d\n", *p);
		p++;
	}
	printf("%p\n", p);
	p -= 10;
	printf("%p\n", p);

	free(p);	 
	return 0;
}

8、内存处理函数

memset()
#include<string.h>
		void* memset(void* s,int c,size_t n);
		功能:将s的内存区域的前n个字节以参数c填入  c通常设置为0
		参数:	s:需要操内存s的首地址
			c:填充的字符,c虽然参数为int,但必须是unsigned char,范围为:0~255.
			n:指定需要设置的大小
		返回值:	s的首地址
memcpy()
		#include<string.h>
		void* memcpy(void* dest,const void *src,size_t n);
		功能:拷贝src所指的内容内容前n个字节到dest所指的内存地址上。
		参数:	dest:目的内存首地址
			src:源内存首地址 
			注意:dest和src所指的内从空间不可重叠,可能导致程序报错
			n:需要拷贝的字节数
		返回值:	dest的首地址
memmove()
		memmove()功能用法和memcpy()一样,区别在于:dest和src所指的内存空间重叠时,
	memmove()仍然能处理,不过执行效率比memcpy()低些
memcpm()
		#include<string.h>
		int memcmp(const void* s1,const void* s2,size_t n);
		功能:比较s1和s2所指向内存区域的前n个字节
		参数:	s1:内存首地址1
			s2:内存首地址2
			n:需比较的前n个字节
		返回值:	相等:=0
			大于:>0
			小于:<0
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>

int main11_01()//memset(void* s,int c,size_t n)函数    将s的内存区域的前n个字节以参数c填入
{
	//int* p = (int*)malloc(sizeof(int) * 10);//开辟40个字节空间,连续10个整型变量
	////memset()重置内存空间的值
	////memset(p, 0, 40);
	//memset(p, 1, 40);
	//for (int i = 0; i < 10; i++)
	//{
	//	printf("%d\n", p[i]);
	//}
	//free(p);

	char ch[10];
	//memset(ch, 'A', sizeof(char) * 10);
	memset(ch, 0, sizeof(char)*10);
	printf("%s\n", ch);

	return 0;
}

int main11_02()//memcpy(void* dest,const void *src,size_t n)函数 拷贝src所指的内容内容前n个字节到dest所指的内存地址上 
{
	//int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	//int* p = (int*)malloc(sizeof(int) * 10);
	////字符串拷贝 strcpy()
	//memcpy(p, arr, sizeof(int) * 10);//内存拷贝
	//for (int i = 0; i < 10; i++)
	//{
	//	printf("%d\n", p[i]);

	//}
	//free(p);

	char ch[] = "hello\0world";
	char str[100];
	//strcpy(str, ch);// 字符串拷贝遇到\0结束
	//printf("%s\n", str);

	//memcpy(str, ch, 13);//内存拷贝    拷贝的内容和字节有关 \0不影响
	//for (int i = 0; i < 13; i++)
	//{
	//	printf("%c", str[i]);

	//}

	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };//将4,5,6,7,8拷贝到6,7,8,9,10的位置
	memcpy(&arr[5], &arr[3], 20);//如果拷贝的目标和源反生重叠,可能报错
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

//memmove 函数 功能与memcpy一样但是dest和src所指的内存空间重叠时
//memmove()仍然能处理,不过执行效率比memcpy()低些
int main11_03()
{

	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };//将4,5,6,7,8拷贝到6,7,8,9,10的位置
	//memcpy(&arr[5], &arr[3], 20);//如果拷贝的目标和源反生重叠,可能报错

	memmove(&arr[5], &arr[3], 20);

	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
}



// memcmp(const void* s1,const void* s2,size_t n)
//比较s1和s2所指向内存区域的前n个字节
int main11_04() 

{
	//int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	//int arr2[] = { 1,2,3,4,5 };

	char arr1[] = "hello\0 world";
	char arr2[] = "hello\0 world";
	//strcmp();只能比较\0之前的内容

	int value = memcmp(arr1, arr2,13);//  \0不影响比较
	printf("%d\n", value);
}

9、内存常见问题

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>

int main12_01()
{
	//char ch[11] = "hello world";//数组下标越界
	char* p = (char*)malloc(sizeof(char) * 11);
	strcpy(p, "hello world");
	
	printf("%s\n", p);
	free(p);
	return 0;
}

int main12_02(void)
{
	//int* p = (int*)malloc(0);
	int* p = (int*)malloc(10);
	//int*p=(int*)malloc(sizeof(int)*10)//最好使用这种方式

	p[0] = 123;
	p[1] = 456;
	p[2] = 789;
	printf("%p\n", p);
	//*p = 100;
	printf("%d\n", *p);
	printf("%d\n", *(p + 1));
	printf("%d\n", *(p + 2));
	free(*p);//开辟了0个字节大小空间  需释放4个字节大小空间 会报错
	return 0;
}

int main12_03()
{
	int* p = (int*)malloc(sizeof(int) * 10);
	int* temp = p;
	for (int i = 0; i < 10; i++)
	{
		*p++ = i;
		p++;//指针叠加不断改变指针方向 释放会出错
	}

	free(p);//堆空间不允许多次释放



	p = NULL;
	//空指针允许多次释放
	free(p);
	free(p);

	return 0;
}



void fun08(int* p)
{
	p = (int*)malloc(sizeof(int) * 10);
	printf("形参:%p\n", p);
}
void fun09(int** p)
{
	*p = (int*)malloc(sizeof(int) * 10);
	printf("形参:%p\n", *p);
}
int* fun10()
{
	int* p = (int*)malloc(sizeof(int) * 10);
	return p;
}
int main012_04(void)
{
	int* p = NULL;
	//fun08(p);//值传递
	//fun09(&p);//地址传递
	p = fun10();
	printf("实参:%p\n", p);
	for (int i = 0; i < 10; i++)
	{
		p[i] = i;
	}
	for (int i = 0; i < 10; i++)
	{
		printf("%d\n", p[i]);
	}
	free(p);
	return 0;
} 

相关推荐

精品博文嵌入式6410中蓝牙的使用

BluetoothUSB适配器拥有一个BluetoothCSR芯片组,并使用USB传输器来传输HCI数据分组。因此,LinuxUSB层、BlueZUSB传输器驱动程序以及B...

win10跟这台计算机连接的前一个usb设备工作不正常怎么办?

前几天小编闲来无事就跑到网站底下查看粉丝朋友给小编我留言询问的问题,还真的就给小编看到一个问题,那就是win10跟这台计算机连接的一个usb设备运行不正常怎么办,其实这个问题的解决方法时十分简单的,接...

制作成本上千元的键盘,厉害在哪?

这是稚晖君亲自写的开源资料!下方超长超详细教程预警!!全文导航:项目简介、项目原理说明、硬件说明、软件说明项目简介瀚文智能键盘是一把我为自己设计的——多功能、模块化机械键盘。键盘使用模块化设计。左侧的...

E-Marker芯片,USB数据线的“性能中枢”?

根据线缆行业的研究数据,在2019年搭载Type-C接口的设备出货量已达到20亿台,其中80%的笔记本电脑和台式电脑采用Type-C接口,50%的智能手机和平板电脑也使用Type-C接口。我们都知道,...

ZQWL-USBCANFD二次开发通讯协议V1.04

修订历史:1.功能介绍1.1型号说明本文档适用以下型号:  ZQWL-CAN(FD)系列产品,USB通讯采用CDC类实现,可以在PC机上虚拟出一个串口,串口参数N,8,1格式,波特率可以根据需要设置(...

win10系统无法识别usb设备怎么办(win10不能识别usb)

从驱动入手,那么win10系统无法识别usb设备怎么办呢?今天就为大家分享win10系统无法识别usb设备的解决方法。1、右键选择设备管理器,如图:  2、点击更新驱动程序,如图:  3、选择浏览...

微软七月Win8.1可选补丁有内涵,含大量修复

IT之家(www.ithome.com):微软七月Win8.1可选补丁有内涵,含大量修复昨日,微软如期为Win7、Win8.1发布7月份安全更新,累计为6枚安全补丁,分别修复总计29枚安全漏洞,其中2...

如何从零开始做一个 USB 键盘?(怎么制作usb)

分两种情况:1、做一个真正的USB键盘,这种设计基本上不涉及大量的软件编码。2、做一个模拟的USB键盘,实际上可以没有按键功能,这种的需要考虑大量的软件编码,实际上是一个单片机。第一种设计:买现成的U...

电脑识别U盘失败?5个实用小技巧,让你轻松搞定USB识别难题

电脑识别U盘失败?5个实用小技巧,让你轻松搞定USB识别难题注意:有些方法会清除USB设备里的数据,请谨慎操作,如果不想丢失数据,可以先连接到其他电脑,看能否将数据复制出来,或者用一些数据恢复软件去扫...

未知usb设备设备描述符请求失败怎么解决

出现未知daousb设备设备描述符请求失du败解决办zhi法如下:1、按下Windows+R打开【运行】;2、在版本运行的权限输入框中输入:services.msc按下回车键打开【服务】;2、在服务...

读《飘》47章20(飘每章概括)

AndAhwouldn'tleaveMissEllen'sgrandchildrenfornotrashystep-patobringup,never.Here,Ah...

英翻中 消失的过去 37(消失的英文怎么说?)

翻译(三十七):消失的过去/茱迪o皮考特VanishingActs/JodiPicoult”我能做什么?“直到听到了狄利亚轻柔的声音,我才意识到她已经在厨房里站了好一会儿了。当她说话的时候,...

RabbitMQ 延迟消息实战(rabbitmq如何保证消息不被重复消费)

现实生活中有一些场景需要延迟或在特定时间发送消息,例如智能热水器需要30分钟后打开,未支付的订单或发送短信、电子邮件和推送通知下午2:00开始的促销活动。RabbitMQ本身没有直接支持延迟...

Java对象拷贝原理剖析及最佳实践(java对象拷贝方法)

作者:宁海翔1前言对象拷贝,是我们在开发过程中,绕不开的过程,既存在于Po、Dto、Do、Vo各个表现层数据的转换,也存在于系统交互如序列化、反序列化。Java对象拷贝分为深拷贝和浅拷贝,目前常用的...

如何将 Qt 3D 渲染与 Qt Quick 2D 元素结合创建太阳系行星元素?

Qt组件推荐:QtitanRibbon:遵循MicrosoftRibbonUIParadigmforQt技术的RibbonUI组件,致力于为Windows、Linux和MacOSX提...

取消回复欢迎 发表评论: