Hello Word
#include <iostream>
using namespace std;
int main()
{
cout<< "Hello Word!!"<<endl;
return 0;
}
数据类型
整形:
int
占用4字节空间
短整形:short int
占用两个字节
长整型:long int
占用4字节空间
超长型:long long
占用8字节空间精度浮点型:float
占用4字节
双精度浮点型:double
占用8字节空间
字符型:char
占用1字节
字符串:string
40个字节在不同的机器上可能不一样
逻辑型:bool
1个字节->注意在c/c++中没有true和false 一律使用0与非0表示
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
cout << "int字节:"
<<sizeof(int)
<<"\nshort int字节:"
<< sizeof(short int)
<< "\nlong int字节:"
<< sizeof(long int)
<< "\nlong long字节:"
<< sizeof(long long)
<< "\nfloat字节:"
<< sizeof(float)
<< "\ndouble字节:"
<< sizeof(double)
<< "\nchar字节:"
<< sizeof(char)
<< "\nstring字节:"
<< sizeof(string)
<< endl;
system("pause");
return 0;
};
image.png
输出与输入
强制让cout小数显示
当一个小数足够大
double a = 10.0/3.0;
cout << a * 10000000 << endl; 输出结果会是科学计数法3.333333e+07
怎么让他显示全呢?在cout语句之前加上
cout <<fixed;
double a = 10.0/3.0;
cout << a * 10000000 << endl;
让cout显示精度(保留多少位小数)只是显示效果,不会改变值
#include <iomanip> 引入头文件并在cout语句前加上setprecision(length)
cout << setprecision(12);
double a = 10.0/3.0;
cout << a << endl;
输出空格(setw(length))
#include <iomanip>
cout<<"测"<<setw(8)<<"试"<<endl;
设置控制台程序的标题
#include <windows.h>
setConsoleTitle("标题");
输入(cin与scanf相似)
int num;
cin >> num; 注意箭头方向
把0/非0输出成true/false
cout<<boolalpha;
思考题
int n = -5,n1 = 2;
n = (n1 ++ ) - (--n1);
cout<<"n:"<<n<<"\t"<<"n1:"<<n1<<endl;
分析:n++是整个表达式运行完成才++ 而--n 是立即执行--操作
结果为什么是n:0 ,n1:2
n = 1-1 因为n1 --了 变为1 而第一个()这里就是1了
位运算符
在位运算中一切操作都是在二进制中进行的
运算符 | 作用 | 示例 |
---|---|---|
& | 按位与 | 两个操作数同时为1结果为1 |
| | 按位或 | 两个操作数只要有一个为1结果为1 |
^ | 按位异或 | 操作数为1,结果为0,操作数为0,结果为1 |
~ | 按位非 | 两个操作数相同,结果为0,不相同为1 |
<< (重点 ) | 左移 | 右侧空位补0 |
>> (重点) | 右移 | 左侧空位补符号位 |
>>> | 无符号右移 | 左侧空位补0 |
案例:
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
cout << (2<<3)<<endl; 结果是16
cout<<(16>>2)<<endl; 结果是4
cout<<(63>>2)<<endl; 结果是15
return 0;
}
分析:2的二进制是 1 0 然后左移3 左移是往右侧补0 那么就是1 0 0 0 0 转为十进制就是16
16>>2分析16的二进制是 1 0 0 0 0 就是去掉2个0 结果就是100 转为十进制就是4
63>>2分析63的二进制是1 1 1 1 1 1 去掉2个1 结果就是1111 转为十进制就是15
循环小案例
int i = 0;
while(i ++ <=2);
cout<<i<<endl;结果是4
分析,当i为三的时候,再去比较一次是否小于等于2,不小于跳出循环但是还有一次++哦,所以结果是4;
容器vector(数组)
vector数组和普通数组不同
1、他可以在运行阶段改变数组长度,而普通数组只能在定义时给定长度,或者就给初始值
2、可以插入和删除数组元素
vector属于vector头文件
vector<double> test; //test集合中只能存放double类型的数据
vector<string> str(5); //存放字符型且空间大小事5
vector<int> num(20,998);给20个空间(元素)每个元素都是998
方法 | 常用方法 |
---|---|
clear() | 移除容器中所有的数据 |
empty() | 判断容器是否为空 |
size() | 返回容器中的元素个数 |
[index]、at[index] | 返回索引为index的元素 (查找下标为index的元素) |
erase(pos) | 删除pos位置处的数据 |
erase(beg,end) | 删除[beg,end) 区间的数据 |
front() | 返回第一个元素 |
insert(pos,elem) | 在pos位置插入一个元素 |
pop_back() | 删除最后一个元素 |
push_back(elem) | 末尾追加元素 |
resize(num) | 重新设置容器大小 |
begin()、end() | 返回容器收尾元素的迭代器 |
find(vector.begin(),vector.end(),element) | 查找目标是否在vector中 |
实践
#include <iostream>
#include <Windows>
#include <vector> //导入头文件
using namespace std;
int main()
{
vector<int> num = {1,2,3,4,5,6,7};
num.push_back(8) ; //追加一个元素为8
for (int i = 0; i < num.size(); i++)
{
cout << num[i] << endl;
}
num.clear(); //清空元素 此时的num.size()为0
-------------------------
//高级vector循环的例子
vector<double>::iterator it; 这个it就是指针
循环含义 收it等于num容器的首个指针 ,然后指针一直往后移动 当指针不等于最后一个指针之后 就不再循环
for(it = num.begin() ;it != num.end(); ++it ) 这里进行 ++it 让指针往后移动
{
cout << *it <<endl; 指针
}
return 0;
}
sort()用法
1、
#include <algorithm>
vector<int> num = {50,45,7962,1454,2,12,45,284,2142,541};
sort(num.begin(),num.end());传入第一个和最后一个 小到大排序
reverse(num.begin(),num.end());从大到小排序
vector<int>::iterator it;
for(it = num.begin() ;it != num.end(); ++it )
{
cout << *it <<endl; 指针
}
实践 - 查找某值是否在vector中
bool is_element_in_vector(vector<int> v, int element)
{
vector<int>::iterator it;
it = find(v.begin(), v.end(), element);
if (it != v.end()) {
return true;
}
else {
return false;
}
}
array类型(普通数组)
#include <array>
array<int,5> myArr; => 相当于 int myArr[5] 一模一样
指针
void 类型指针一般用来比较,他不能改变值
int num = 2014;
int * ptr_num = #
void *ptr_num1 = #
*ptr_num = 2048;
*ptr_num1 = 4849; 报错
引用
注意引用不能直接引用常量!如
int &test = 2;这个是错误的必须引用变量
当形参是引用类型是,进行数据改变,会改变原数据
int num = 1024;
int& test_num = num;
cout << test_num <<endl; 结果1024
例子引用改变数据
void test(int& a,int& b)
{`如果形参前加上const 就不会改变原数据` const int& a
a ++;
b ++
}
int main()
{
int a = 3,b = 4;
test(a,b);
cout << a << setw(8) << b <<endl; 结果a等于4 b等于5
return 0;
}
动态分配内存(new方法)一般与指针相配合使用
告别c语言中的malloc以及calloc
为什么动态分配内存要与指针配合使用呢?分配了内存,我们怎么找到该内存?所以我们用指针指向这块内存区域就行
温习下两者分配内存的用法
//malloc
int * p = (int *)malloc(10);int类型的10个空间
int * t = calloc(5,sizeof(int)) 分配20个空间
使用new方法申请内存
int *p = new int; 申请4个字节的内存空间
delete p; 释放内存
注意动态分配内存之后我们需要释放掉内存,即使使用malloc或者calloc也要用free释放掉
使用delete
释放内存
int *p = new int[5];分配了5个空间的整形
类似
int num[5];
int *p = num;
释放内存
delete[] p
分配二维数组的动态内存
int (*p)[3] = new int[5][3];
函数指针
int sum(int,int);//定义函数原型
int sum(int a ,int b) //函数的实现
{
return a +b;
}
int main()
{//主函数
int (*ptr_fn))(int,int);
ptr_fn = sum;
cout << ptr_fn (3,4)<<endl; 调用
或者
cout << (*ptr_fn )(3,4)<<endl;一样也可以
}
内联函数
相对于普通函数来说,运行速度及效率内联函数都是高于普通函数;
普通函数运行机制:当代码运行到执行函数的时候,现在栈区找到改函数对应的内存地址,再去执行;
内联函数:当代码运行到执行函数的时候,直接执行函数里面的内容,相当于直接把函数的代码块搬过来;
通俗一点解释:普通函数看书需要查目录,而内联函数直接看内容
inline
关键字
//定义函数
inline int sum(int,int); // 比普通函数多一个inline
什么时候使用内联:当程序逻辑及代码较少的情况可以使用内联,使用内联,会消耗相对大的
内存消耗
重载
重载讲的是一个函数多次定义,但是参数不同
案例,对数组进行排序,但是按传统排序方法,传入的数组可能是个整数型数组、浮点型数组、、、这样我们得写很多份函数,
#include <iostream>
#include <Windows.h>
#include <iomanip>
using namespace std;
/*
模板
*/
template<typename T> void Sorts(T [], int);
template<typename A> void showArr(A[], int);
int main()
{
int intArr[6] { 45,8,12,48,21 };
Sorts(intArr, 6);
showArr(intArr, 6);
system("pause");
return 0;
}
template<typename T>
void Sorts(T arr[], int len)
{
T temp;
for (int i = 0; i < len; i++)
{
for (int j = 0; j < len - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
template<typename A>
void showArr(A arr[],int len)
{
for (int i = 0; i < len; i++)
{
cout << arr[i] << endl;
}
}
面向对象
类
类的关键字:class
//新建类文件
#ifndef ***
#define ***
#include <iostream>
#include <string>
using namespace std;
class newClass
{
private: //私有的属性 ,不写private 默认是私有的属性
string name;
public: //静态的方法/属性
newClass(); //构造函数
~newClass(); //析构函数
show();//自购函数
}
newClass::newClass()
{
}
newClass::~newClass()
{
}
newClass:show()
{
}
#endif
main.cpp
#include "导入刚刚创建的头文件"
newClass.name = "测试"
会报错的!!!因为这个name属性是私有的无法在外面访问该属性
我们应该把这个属性 放在public里面,但是有一个很不好,因为会被随便变更值,所以我们写个方法
setName 放在public中 设置name的值
在写一个getName 返回name就行
public
在这里面定义的方法/属性在任何地方都可以使用
private
只能在类里面或者有团函数可以使用
protected
受保护的只能是同家族的可以使用
类里面的构造函数一般是用来初始化成员变量(private静态变量)也可以
类里面的够着函数可以带参数的
类形指针
创建一个类例如studen
class Student{
private:
string name;
int classInt; //班级
string teacher; //老师
public:
Student(string,string,int);
~Student();
void showInfo();
}
Student::Student(string a,string b,int c){
name = a;
classInt= c;
teacher = b;
};
Student::~Student(){};
void Student::showInfo(){};
实例化指针
Student* st1 = new Student("小明","王老师",3); 和js一样new对象
st1->showInfo();
delete st1;
当类型指针用完之后!一定要释放内存
delete st1
析构函数
作用用来释放资源(内存)一般用于当实例化类用完之后,调用该析构函数 释放掉内存
用上述的student的类
Student::~Student(){
cout<<"释放内存"<<endl;
}
this指针
this的字面意思指这个,一般在类里面使用
class Student{
string name;
string teacher;
float *scroe; //分数数组 我们用指针的方式来生成数组可以看本笔记的new分配内存
public:
Student();
~Student();
};
Student::Student()
{
this->name = "小明";
this->teacher = "王老师"
this->scroe = new float[1]; //分配一个空间
}
Student::~Student()
{
delete this->scroe ; 在析构函数中得释放内存
}
运算符重载
运算符重载关键字
operator
什么叫做运算符重载?比如有一个MyTime
类
MyTime t1,t2,t3;
t3 = t1 +t2;
或者其他运算,我们知道,+-*/怎么能运算类与类呢?
C/C++与汇编
在C中汇编关键字_asm
#include <iostream>
using namespace std;
int main()
{
int a,b,c;
_asm{
mov a,1h 把1放入a变量 => a = 1
mov b,5h 把5放入b变量 => b = 5
mov eax,a 把a变量的值放入寄存器eax中 => eax = a
mov ebx,b 把b变量的值放入寄存器ebx中 => ebx = b
add eax,ebx 然后两个寄存器的值相加 => eax = eax(a) + ebx(b)
mov c,eax 最后把 eax的值放到c变量中 c = eax(a+b)
};
cout<< c <<endl; 结果会是6
return 0;
}
稍微解释下汇编知识:
在汇编中数值一律都是十六进制的向上述案例1h代表的是十六进制的1
寄存器:这里指32寄存器一般把值放在寄存器中进行运算
EAX
EBX
ECX
EDX
这四个寄存器
mov
把右边的值赋值给左边
add
把两个寄存器里面的值相加之后把值放在左边这个寄存器
shl
左移运算
int a = 6;
_asm{
mov eax,a 把a的值给寄存器eax =>eax = a
shl eax,2 =>eax = eax << 2
mov a,eax => a = eax
};
cout << a<<endl; 结果是64
拓展C++数据类型
短整形 长度:-32768 ~ 32767
short
、__int16
无符号整形长度:0-65534
USHORT
、unsigned __int16
、WORD
长整型 长度:-2147483648~2147483647
int
、__int32
、long
无符号长整型长度:0~4294967295
unsigned int
、unsigned long
、unsigned __32
、DWORD
、DWORD32
、size_t
、ULONG
超长整形长度:-9223372036854775808~9223372036854775807
long long
、__int64
、LONG64
无符号超长整形
DWORD64
、ULONG64
、unsigned long long
、unsigned __int64
单字节类型长度:-128~127
char
、__int8
无符号单字节类型长度0~255
BYTE
、UCHAR
双字节
WCHAR
、wchar_t
自适应字节
TCHAR
、DWORD_PTR
小数
float
、double
线程与创建
c++11
thread类
createThread
方法
_beginthreadex
方法
thread类
#include <thread>
void hello_thread()
{
cout <<"这是第一个线程"<<endl;
}
int main()
{//主函数
thread t1(hello_thread);
t1.join();
return 0;
}
CreateThread函数原型
HANDLE WINAPI CreateThread(
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ SIZE_T dwStackSize,
_In_ LPTHREAD_START_ROUTINE lpStartAddress,
_In_opt_ LPVOID lpParameter,
_In_ DWORD dwCreationFlags,
_Out_opt_ LPDWORD lpThreadId
);
CreateThread参数说明
- 第一个参数
lpThreadAttributes
表示线程内核对象的安全属性,一般传入NULL
表示使用默认设置。- 第二个参数
dwStackSize
表示线程栈空间大小。传入0表示使用默认大小(1MB)。- 第三个参数
lpStartAddress
表示新线程所执行的线程函数地址,多个线程可以使用同一个函数地址。- 第四个参数
lpParameter
是传给线程函数的参数。- 第五个参数
dwCreationFlags
指定额外的标志来控制线程的创建,为0表示线程创建之后立即就可以进行调度,如果为CREATE_SUSPENDED
则表示线程创建后暂停运行,这样它就无法调度,直到调用ResumeThread()
。- 第六个参数
lpThreadId
将返回线程的ID号,传入NULL
表示不需要返回该线程ID号。
createThread使用
DWORD WINAPI test_thread(void * p)
{
cout << "我是子线程, pid = "
<< GetCurrentThreadId()
<< endl;
//输出子线程pid
return 0;
}
int main()
{
HANDLE hThread;
DWORD threadId;
hThread = CreateThread(NULL, 0, test_thread, 0, 0, &threadId); // 创建线程
cout << "我是主线程, pid = "
<< GetCurrentThreadId()
<< endl;
return 0;
}
image.png
_beginthread创建线程
unsigned __stdcall test_call(PVOID p)
{
cout << "这是子线程 PID = "
<< GetCurrentProcessId()
<< endl;
return 0;
};
_beginthreadex(NULL,0, test_call,NULL,NULL,NULL);
sendMessage()
SendMessage((HWND)0x000901AC, WM_PASTE, 0, 0);
将剪切板的内容发送到窗口句柄为0x000901AC的窗口
窗口句柄的获取方式可以使用Spy++进行获取,或者使用代码:FindWindow();
实战利用sendMessage以及多线程往记事本/QQ对话框发送消息
- 首先我们打开三个记事本/QQ消息对话框分别用Spy++获取它们的窗口句柄
HWND jubing[3] = {(HWND)0x003906C2 ,(HWND)0x0050069C ,(HWND)0x004E087E };
把他们的窗口句柄数据用数组保存下来
- 然后我们创建线程函数
unsigned __stdcall test_thread(void * p)
{
SendMessage((HWND)p, WM_PASTE, 0, 0); 剪切板的内容我们可以事先黏贴好,或者我们使用代码设置剪切板的内容
Sleep(20);
return 0;
}
- 然后使用线程调用它
for (size_t i = 0; i < 30; i++)
{
for (size_t k = 0; k < 3; k++)
{
_beginthreadex(NULL, 0, test_thread, jubing[k], NULL, NULL);
}
}
网友评论