【C/C++学院】0724-堆栈简介/静态区/内存完成篇/多线程

【送给在路上的程序员】

对于一个开发者而言,能够胜任系统中任意一个模块的开发是其核心价值的体现。

对于一个架构师而言,掌握各种语言的优势并可以运用到系统中,由此简化系统的开发,是其架构生涯的第一步。

对于一个开发团队而言,能在短期内开发出用户满意的软件系统是起核心竞争力的体现。

每一个程序员都不能固步自封,要多接触新的行业,新的技术领域,突破自我。

堆栈简介、内存完成篇

Const是一个伪常量

#include<stdio.h>
#include<stdlib.h>
#define N 10   //CPU产生,10 . 1010
//const是伪常量,限定编译器尽量不直接修改

void main()
{
	//int a=10; int *p=&a;
	const int num = 10;//避免直接赋值的修改,不可以避免间接赋值的修改
	//num=1;
	const int *p1 = #//创建指针指向const int
	int *p2 = (int *)p1;
	*p2 = 100;
	printf("%d", num);
	getchar();
}

void main1()
{
	//&N;
	//N = 3;
	//num = 3;
	int data[N];
	//int data[num];
}

代码区是只读的

函数名称就是函数的地址

#include<stdio.h>
#include<stdlib.h>

void gogogo()
{
	printf("AAAAA\n\n\n\n");
}

void main1()
{
	printf("%p", gogogo);//函数名存放函数的地址
	//gogogo = gogogo;代码区只能读不可写
	//void gogogo();
	//void ()();
	gogogo();//直接调用

	void(*p)()=gogogo;
	p();//间接调用

	getchar();
}

void main()
{
	char *p = "ABCDEFG";//p存储常量字符串的地址
	printf("%d,%d\n", sizeof(p), sizeof("ABCDEFG"));//4 ,8
	printf("\n%p", &p);//查看指针变量的地址
	printf("\n%p", p);//查看字符串的地址
	//*p = 'a';//代码区只能读,常量字符串在代码区

	getchar();
}

堆的空间,由程序员控制

#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>

//内存分配,malloc calloc,realloc
void  test()
{
	int *p = (int *)malloc(sizeof(int)* 10);//指针除了地址,更重要的是指针的类型,
	printf("%p\n", p);//打印地址

	int num = 0;
	for (int *px = p; px < p + 10; px++)
	{
		*px = num;//对内容赋值
		printf("%p,%d\n", px, *px);//打印地址还有数据
		num++;
	}
}

void mainA()
{
	test();
	test();//调用了2次函数,而内存空间是不一样的地址
	system("pause");
}

void mainB()
{
	unsigned  long long ll = 1024 * 1024 * 1024;//ll   2^64-1  鲸吞
	ll *= 1;
	void *p = malloc(ll);
	if (p == NULL)
	{
		printf("内存分配失败");
	}
	else
	{
		printf("成功");
	}
	system("pause");
}

void   main()
{
	while (1)//蚕食
	{
		//内存一定要及时释放
		void *p = malloc(1024*1024*100);//p, 栈    *(p+3)地址指向的内容
		Sleep(3000);
	}
}

堆栈的生长方向

栈是连续的,向上增长,堆是链接的,向下增长。

通过打印的地址,可以进行验证。

#include<stdio.h>
#include<stdlib.h>

void main()
{
	void *p1 = malloc(10); //p1,p2栈上
	void *p2 = malloc(20);
	printf("%p,%p", &p1, &p2);//地址在栈上
	printf("\n%p,%p", p1, p2);//堆区

	getchar();
}

函数指针外挂

外挂原理,使用dllinject工具,给进程打针。后期可以自己实现这个工具。

打开任务管理器的时候,可以直接跳转跟踪到进程。利用打针的技术,可以实现移花接木的手段,比如,弹出一个对话,360警察哥哥,淘宝网银风险等。

#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>

int num = 100;
void add(int x);
void add(int x)
{
	num += x;//加血
}
void  msg()
{
	MessageBoxA(0, "1", "2", 0);
}

void main()
{
	printf("add=%p,msg=%p\n", add,msg);
	while (1)
	{
		printf("%d\n", num);
		Sleep(5000);
	}

}
#include<stdio.h>
#include<stdlib.h>

//导出函数,可以加载的时候调用
_declspec(dllexport) void go()
{
	//函数指针类型必须一致,否则无法调用成功
	//int ** 变量名挖掉就是类型
	//间接调用的方式调用函数,根据地址来调用
	void(*p1)(int a) = (void(*)(int a)) 0x2c10eb;
	p1(10);
	void(*p2)() = (void(*)())0x2c111d;
	p2();
    //这里加上自己的猥琐代码,可以移花接木,唬住门外汉。
}

寄存器变量

C和汇编的混合编程

#include<stdio.h>
#include<stdlib.h>

void main1()
{
	int  a = 1;
	int b = a + 1;
	//a + 1 = 2;
	b = a + 2;
	b = a + 3;
	getchar();
}

void main2()
{
	//register  int a = 3;
	//&a;//地址是内存的地址,CPU没有地址
	int a = 10;
	int b;//b=a+5;
	_asm
	{
		mov eax, a

		add eax, 5

	    mov  b,eax

	}
	printf("%d", b);
	getchar();
}

利用栈变量,卡死cpu,给进程打针实现恶搞。

#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>

//导出函数,可以加载的时候调用
_declspec(dllexport)  void  go()
{
	 MessageBoxA(0, "你的360云盘存放的岛国大片被网络警察所监督", "请自首", 0);
	 while (1)
	 {
		 double  db[1024 * 100];
	 }
}

栈的大小

#include<stdio.h>
#include<stdlib.h>

void main2x ()
{
	int a[1024*300];//1M=1024*1024  栈的大小编译器决定
	//无法使用较大内存,
	//用完了就立刻回收
	getchar();

}

void main()
{
	while (1)
	{
		//注入进程,卡死CPU,卡死内存
		double   db[1024 * 200];
		void  *p = malloc(1024 * 1024);
	}
}

静态区、内存完成篇

函数参数的入栈顺序,从右向左

#include<stdio.h>
#include<stdlib.h>

void main()
{
	int a=4;
	printf("%d,%d", a, a++);//参数压栈的顺序从右向左
	//5, 4
	getchar();
}
#include<stdio.h>
#include<stdlib.h>

void main()
{
	int a=4;
	printf("%d,%d", a, ++a);//参数压栈的顺序从右向左
	//5, 5
	getchar();
}

全局static变量,//限定只有本C文件访问

局部static变量,只会初始化一次。

#include<stdio.h>

void main()
{
	for (int i = 0; i < 10; i++)
	{
		int a = 10;//用完就回收
		static int b = 10;//与程序共存亡,静态局部变量 ,编译的时候就初始化了,只会初始化一次
		a += 1;
		b += 1;
		printf("%d,%d\n", a, b);
	}
	getchar();

}

void  main2()
{
	for (int i = 1; i <= 100; i++)
	{
		static int res = 0;//只会初始化一次
		res += i;
		printf("%d\n", res);
	}
	//res = 3;//程序污染

	getchar();
}

变量的作用域

#include<stdio.h>
#include<stdlib.h>

//int  a = 10;
//int a = 10;//全局变量,声明+赋值=定义

int a;//声明    定义只能有一个,声明可以多个
int a;
int a = 10;//定义

void main()
{
	/*
	int a = 10;重定义
	int a = 10;*/

	/*int a; 对于局部变量来说,无论是否赋值都是定义
	int a;*/
}

静态区与栈区,静态区与程序共存亡,静态区分配优先于main函数

栈区,反复回收,反复释放

静态区与全局变量

#include<stdio.h>
#include<stdlib.h>

int num = 10;//静态区
//静态区与栈区,静态区与程序共存亡,静态区分配优先于main函数
//栈区,反复回收,反复释放

void test()
{
	int  data = 3;//栈区
	printf("%p,%p\n", &num, &data);

	num = 101;

	data = 34;

	printf("\n");

}

void main()
{
	test();

	printf("\n");

	test();

	printf("\n");

	system("pause");
}

全局变量

#include<stdio.h>
#include<stdlib.h>

int a;
int a;
int a;//没有定义会把最后一个声明当作定义初始化为0
//int a = 10;

void main()
{
	printf("%d", a);//0

	system("pause");
}

多线程

单线程的局限

总共5碗饭,一个人一次一碗一碗吃。 5个人每个人吃一碗。

一个女人10个月生一个孩子,10个女人一个月却不能生一个孩子。多线程的局限

#include<Windows.h>
#include<process.h>//进程
#include<stdlib.h>

void  run(void *p)
{
	int *px = (int *)p;//指针转换
	//printf("线程%d启动", *px);
	char str[100] = {0};//字符数组
	sprintf(str, "线程%d启动", *px);

	MessageBoxA(0,str, "多线程", 0);
}

void main1()
{
	for (int i = 0; i < 5; i++)
	{
		//run(NULL);
		_beginthread(run, 0, &i);
		Sleep(10);
	}
	system("pause");
}

阻塞模式与并行模式

#define  _CRT_SECURE_NO_WARNINGS//关闭安全检查
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>//_beginthread();_endthread();
#include<process.h>//WaitForSingleObject

void gogogo(void *p)
{
	int *px = (int*)p;//指针转换
	//return ; //线程执行完成以后返回
	int i = 0;
	while (1)
	{
		if (i > 5)
		{
			printf("%d   %d\n", i,*px);
			_endthread();//结束线程
		}
		Sleep(1000);
		i++;
	}

}

void  time(void *p)
{
	int i = 0;
	while (1)
	{
		char str[100] = { 0 };
		sprintf(str, "title 当前时间第%d秒", i);
		system(str);
		i++;
		Sleep(1000);
	}
}

void main()
{
	//time(NULL);
	_beginthread(time, 0, NULL);
	for (int i = 0; i < 5; i++)
	{
		//gogogo(NULL);
		HANDLE  hd = _beginthread(gogogo, 0, &i);//hd是编号
		//WaitForSingleObject(hd, INFINITE);//等待,阻塞模式  ,没有wait并行模式
		Sleep(1000);
	}
	getchar();
}

多线程实现数据的查找

#include<stdio.h>
#include<stdlib.h>
#include<process.h>
#include<Windows.h>

int  flag = 0;//意味着没有找到
int  * addrfind = NULL;//查找到的数据所在的地址

struct MyStruct
{
	int *pfindstart;//要查找的首地址
	int  length;//限定长度,从地址开始
	int  num;//要查找的数据
	int  bh;//编号
	int  *pflag;//传递flag的地址,修改flag,访问
	int **addr;//传递一个指针的地址,
};

void find(void *p)
{
	struct MyStruct *pstruct = (struct MyStruct *)p;//指针类型转换
	//内存的遍历,从地址开始累加100个元素的大小,遍历所有元素
	for (int *px = pstruct->pfindstart; px < pstruct->pfindstart + 100; px++)
	{
		Sleep(100);//0.1s 查找一次
		if (*(pstruct->pflag) != 0)
		{
			printf("\n属下%d无能,其他线程已经找到", pstruct->bh);
			return;
		}

		if (*px == pstruct->num)//判断是否相等
		{
			printf("\n第%d个线程找到%p,%d",pstruct->bh, px,*px);//查找
			*(pstruct->pflag) = 1;//改变标识,代表找到
			*(pstruct->addr) = px;
			return;
		}
	}
	printf("\n没有找到第%d个线程", pstruct->bh);
	return;
}

void main()
{
	int a[1000];//要查找783;数组
	for (int i = 0; i < 1000; i++)
	{
		a[i] = i;//数组初始化
	}
	struct MyStruct threaddata[10];//创建结构体数组,处理不同的线程,
	for (int i = 0; i < 10; i++)//创建10个线程并行查找
	{
		//a , a+100 a+200               a+900
		threaddata[i].pfindstart  = a + i * 100;//计算数组的地址
		threaddata[i].length = 100;//长度
		threaddata[i].bh = i;//编号
		threaddata[i].num = 783;//要查找的数据
		threaddata[i].pflag = &flag;//标识
		threaddata[i].addr = &addrfind;//存储了变量的地址

		printf("\n%d\n", threaddata[i].bh);//调试输出
		_beginthread(find, 0, &threaddata[i]);//线程干活

		//Sleep(30);//避免同时访问同一个变量,引起访问冲突
	}

	Sleep(30000);//避免同时访问同一个变量,引起访问冲突

	system("pause");
	printf("\n\n%d,%p\n\n", *addrfind, addrfind);//打印地址,还有数据
	system("pause");
}

|=========== 吴英强CSDN博客专栏==============|

|== C/C++学院 专栏文章的内容(不定期更新)===|

|== linux驱动开发 探索linux底层的奥秘
==========|

|== Java基础学习篇 掌握java语言的基础知识=====|

|====== 每天进步一点点,健康快乐每一天 ========|

版权声明:欢迎转载,希望在您转载的同时,添加原文地址,谢谢配合!

时间: 2024-10-10 22:20:44

【C/C++学院】0724-堆栈简介/静态区/内存完成篇/多线程的相关文章

C语言的内存管理分析 栈区 代码区 堆区 静态区 常量区

系统为了管理内存 把内存划分了几个区域 1> 栈区 栈区之中的数据在栈区之中以栈的形式进行存储. 栈区的特点:数据是先进后出, 放在栈区里面存放的是局部变量.(例如定义在函数内部的变量) 栈区之中的数据(局部变量)的作用范围过了之后,系统就会回收自动管理栈区的内存(分配内存 , 回收内存),不需要开发人员来手动管理 2> 堆区 高效的使用内存 这里的内存可以由程序员自己手动管理 高效的使用内存  例如: 申请内存 释放内存.优化内存 ARC 申请内存的函数 malloc()  memary a

java中堆栈(stack)和堆(heap)(还在问静态变量放哪里,局部变量放哪里,静态区在哪里.....进来)

(1)内存分配的策略 按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的. 静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编 译时就可以给他们分配固定的内存空间.这种分配策略要求程序代码中不允许有可变数据结构(比如可变数组)的存在,也不允许有嵌套或者递归的结构出现,因为 它们都会导致编译程序无法计算准确的存储空间需求. 栈式存储分配也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的.和静态存 储分配相反,在栈式存储方案中,程序对

局部变量、 全局变量、 堆、 堆栈、 静态和全局

文章转自armfly开发板V4软件开发手册,分享学习~ 一个由C/C++编译的程序占用的内存分为以下几个部分(1)栈区(stack)— 由编译器自动分配释放,存放函数的参数值,局部变量的值等.(2)堆区(heap) — 由程序员分配和释放,若程序员不释放,程序结束时可能由OS回收.(3)全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量.未初始化的静态变量在相邻的另一块区域.(4)文字常量区 — 常量字符串就是放在

内存分配及变量存储位置(堆、栈、方法区常量池、方法区静态区)

转载来源:http://www.cnblogs.com/protected/p/6419217.html 侵删! 程序运行时,有六个地方都可以保存数据: 1. 寄存器:这是最快的保存区域,因为它位于和其他所有保存方式不同的地方:处理器内部.然而,寄存器的数量十分有限,所以寄存器是根据需要由编译器分配.我们对此没有直接的控制权,也不可能在自己的程序里找到寄存器存在的任何踪迹. 2. 堆栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中(new 出来的对象).驻留于常规RAM

局部变量、全局变量、堆、堆栈、静态和全局【转】

转自:http://blog.csdn.net/jeffade/article/details/7958013 预备知识—程序的内存分配 一个由C/C++编译的程序占用的内存分为以下几个部分 栈区(stack)— 由编译器自动分配释放,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. 堆区(heap) — 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收 .注意它与数据结构中的堆是两回事,分配方式倒是类似于链表. 全局区(静态区)(static)—,全局变量和静态

内存布局:栈,堆,BSS段(静态区),代码段,数据段

摘自:https://www.cnblogs.com/Spider-spiders/p/8884729.html 简介 我们程序运行的时候都是放在内存里的.根据静态.成员函数.代码段.对象.等等.放在不同的内存分块里.大概分为5块 1  栈 2  堆 3 BSS段-全局区-(静态区) 4 代码段 5 数据段 栈 存放局部变量.临时变量.声明.返回值.指向堆对象的地址(指针).总之存放一些小的东西.当不需要时候.栈会自动清除.比如一个加法方法里面.声明了两个int并赋值.这两个就是放在栈里面.类里

内存分配中的堆、栈、静态区、只读区

内存中的栈区处于相对较高的地址以地址的增长方向为上的话,栈地址是向下增长的,栈中分配局部变量空间,堆区是向上增长的用于分配程序员申请的内存空间.另外还有静态区是分配静态变量,全局变量空间的:只读区是分配常量和程序代码空间的:以及其他一些分区.对于常量,在实际情况中,是会复用的,比如变量a和b都赋值为”abc”则实际上他们指向同一块地址. main.cpp int a = 0; //全局初始化区 char *p1; //全局未初始化区 main() { int b; //栈 char s[] =

#运算符、不同的指针类型、数组和指针、指针运算、堆、栈、静态区、只读区、下标VS指针

#运算符:用于在预编译期将宏参数转换为字符串 #define CONVERS(x)  #x   //注:没用双引号包括. 不同类型的指针占用的内存空间大小相同. 局部变量 定义: a[5]; 打印a[i]时,a[i]为随机数. 若定义a[5]={1,2}; 打印时,a[0]=1;a[1]=2;a[2]=a[3]=a[4]=0; 数组地址与数组名: 1.数组名代表数组首元素的地址.  a=&a[0]; 2.数组的地址需要用取地址符号&才能得到 (&a) 3.数组首元素的地址值与数组的

解释内存中的栈(stack)、堆(heap)和静态区(static area)的用法。

答: 通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用内存中的栈空间:而通过new关键字和构造器创建的对象放在堆空间:程序中的字面量(literal)如直接书写的100."hello"和常量都是放在静态区中.栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间,理论上整个内存没有被其他进程使用的空间甚至硬盘上的虚拟内存都可以被当成堆空间来使用. String str = new String("hello"); 上面的语句中