022 C语言基础:C内存管理与C命令行参数

文章目录

  • 一:概述
  • 二:内存四区
  • 三:内存四区的底层结构
  • 四:malloc和free
  • 五:C命令行参数

一:概述

 
首先给出大佬的链接:https://zhuanlan.zhihu.com/p/272920885

在计算机中,每个应用程序之间的内存是相互独立的,通常情况下应用程序 A 并不能访问应用程序 B,当然一些特殊技巧可以访问,但此文并不详细进行说明。例如在计算机中,一个视频播放程序与一个浏览器程序,它们的内存并不能访问,每个程序所拥有的内存是分区进行管理的。在计算机系统中,运行程序 A 将会在内存中开辟程序 A 的内存区域 1,运行程序 B 将会在内存中开辟程序 B 的内存区域 2,内存区域 1 与内存区域 2 之间逻辑分隔。

 

二:内存四区

在程序A开辟的内存区域1会被分为几个区域,这就是内存四区。内存四区分为栈区、堆区、数据区与代码区。

栈区

  • 存储一些临时变量的区域,临时变量包括了局部变量、返回值、参数、返回地址等,当这些变量超出了当前作用域时将会自动弹出。该栈的最大存储是有大小的,该值固定,超过该大小将会造成栈溢出。

堆区

  • 指的是一个比较大的内存空间,主要用于对动态内存的分配;在程序开发中一般是开发人员进行分配与释放,若在程序结束时都未释放,系统将会自动进行回收。

数据区

  • 指的是主要存放全局变量、常量和静态变量的区域,数据区又可以进行划分,分为全局区与静态区。全局变量与静态变量将会存放至该区域。

代码区

  • 就比较好理解了,主要是存储可执行代码,该区域的属性是只读的。

 

三:内存四区的底层结构

首先看个实例:

#include 
int e = 0;
int main(){
	int a = 0;
	int b = 0;
	char c = '0';
	static int d = 0;
	printf("a: %d \n", &a);
	printf("b: %d \n", &b);
	printf("c: %d \n", &c);
	printf("d: %d \n", &d);
	printf("e: %d \n", &e);
}
运行结果:
	a: 6422300
	b: 6422296
	c: 6422295
	d: 4227108
	e: 4227104

我们可以观察到变量 a 的地址是 6422300 变量 b 的地址是 6422296,由于 int 的数据大小为 4 所以两者之间间隔为 4;再查看变量 c,我们发现变量 c 的地址为 6422295,与变量 b 的地址 6422296 间隔 1,因为 c 的数据类型为 char,类型大小为 1。在此我们观察发现,明明我创建变量的时候顺序是 a 到 b 再到 c,为什么它们之间的地址不是增加而是减少呢?

那是因为栈区的一种数据存储结构为先进后出。可以想象有一个桶,往里面装大米,然后再拿出来,先进去的大米总是后面才能拿出来。首先栈的顶部为地址的“最小”索引,随后往下依次增大,但是由于堆栈的特殊存储结构,我们将变量 a 先进行存储,那么它的一个索引地址将会是最大的,随后依次减少;第二次存储的值是 b,该值的地址索引比 a 小,由于 int 的数据大小为 4,所以在 a 地址为 6422300 的基础上往上减少 4 为 6422296,在存储 c 的时候为 char,大小为 1,则地址为 6422295。由于 a、b、c 三个变量同属于一个栈内,所以它们地址的索引是连续性的

通过上述内容得知,全局变量与静态变量都应该存储在静态区,创建了一个变量 d,变量 d 为静态变量,运行代码后从结果上得知,静态变量 d 的地址与一般变量 a、b、c 的地址并不存在连续,他们两个的内存地址是分开的,而全局变量e则和d处在同一块,都在数据区。

从以上运行结果中证实了上述内容的真实性,并且也得到了一个知识点,栈区、数据区都是使用栈结构对数据进行存储。在以上内容中还说明了一点栈的特性,就是容量具有固定大小,超过最大容量将会造成栈溢出。
查看如下代码:

#include 
int main(){
	char arr_char[1024*1000000];
	arr_char[0] = '0';
}

以上代码定义了一个字符数组arr_char,并设置了大小为1024*1000000,设置该数据是方便查看大小;随后在数组头部进行赋值。这是程序运行出错,原因是造成了栈的溢出。在平常开发中若需要大容量的内存,需要使用堆。堆并没有栈一样的结构,也没有栈一样的先进后出。需要人为的对内存进行分配使用。

代码如下:

#include 
#include 
#include 
int main(){
	char *p1 = (char *)malloc(1024*1000000);    // 使用malloc手动开辟空间
	strcpy(p1, "这里是堆区");       // 往内存空间p1中传数据“这里是堆区”
	printf("%s \n", p1);
}

 

四:malloc和free

在 C 语言(不是 C++)中,malloc 和 free 是系统提供的函数,成对使用,用于从堆中分配和释放内存。malloc 的全称是 memory allocation 译为“动态内存分配”。

malloc和free的使用:
在开辟堆空间时我们使用的函数为malloc,malloc在C语言中是用于申请内存空间,malloc函数的原型如下:void *malloc(size_t size);在malloc函数中,size是表示需要申请的内存空间大小,申请成功将会返回该内存空间的地址,申请失败则会返回NULL,并且申请成功也不会自动进行初始化。该函数的返回值说明为 void *,在这里 void * 并不指代某一种特定的类型,而是说明该类型不确定,通过接收的指针变量从而进行类型的转换。在分配内存时需要注意,即时在程序关闭时系统会自动回收该手动申请的内存 ,但也要进行手动的释放,保证内存能够在不需要时返回至堆空间,使内存能够合理的分配使用。释放空间使用free函数,函数原型如下:void free(void *ptr);
free函数的返回值为void,没有返回值,接收的参数为使用malloc分配的内存空间指针。

重新调整内存的大小和释放内存:
当程序退出时,操作系统会自动释放所有分配给程序的内存,但是,建议在不需要使用内存时,都应该调用函数free()来释放内存。或者通过调用函数realloc()来增加或减少已分配的内存块的大小。

使用realloc()和free()函数来看看下面的实例:

#include 
#include 
#include 
int main(){
	char name[100];
	char *description;
	strcpy(name, "Zara Ali");

	// 动态分配内存
	description = malloc(30 * sizeof(char));
	if(description == NULL){
		fprintf(stderr, "Error - unable to allocate required memory \n");
	}else{
		strcpy(description, "Zara ali a DPS student.");
	}
	// 假设您想要存储更大的描述信息
	description = realloc(description, 100 * sizeof(char));
	if(description == NULL){
		fprintf(stderr, "Error - unable to allocate required memory \n");
	}else{
		strcat(description, "she is in class 10th");
	}

	printf("Name = %s \n", name);
	printf("Description: %s \n", description);

	// 使用free()函数释放内存
	free(description);
}
结果:
┌──(rootkali)-[~/Desktop/c_test]
└─# ./realloc_free 
Name = Zara Ali 
Description: Zara ali a DPS student.she is in class 10th 

 

五:C命令行参数

执行程序时,可以从命令行传值给C程序,这些值被称为命令行参数。

命令行参数是使用main()函数参数来处理的,其中,argc是指传入参数的个数,argv[]是一个指针数组,指向传递给程序的每个参数。

实例:

#include 
int main(int argc, char *argv[]){
	if(argc == 2){
		printf("The argument supplied is %s \n", argv[1]);
	}else if (argc > 2){
		printf("Too many arguments supplied. \n");
	}else{
		printf("One argument expected. \n");
	}
	printf("argv[0]: %s \n", argv[0]);
	printf("argv[1]: %s \n", argv[1]);
}
结果:
	┌──(rootkali)-[~/Desktop/c_test]
	└─# ./minglinghangcanshu testing
	The argument supplied is testing
	argv[0]: ./minglinghangcanshu
	argv[1]: testing

应当指出的是,argv[0] 存储程序的名称,argv[1] 是一个指向第一个命令行参数的指针,*argv[n] 是最后一个参数。如果没有提供任何参数,argc 将为 1,否则,如果传递了一个参数,argc 将被设置为 2。多个命令行参数之间用空格分隔,但是如果参数本身带有空格,那么传递参数的时候应把参数放置在双引号 “” 或单引号 ‘’ 内部。

你可能感兴趣的:(C语言,c语言,算法,c++)