工具配置 配置Toolchains
打开Clion,File->Settings->Build->Toolchains然后添加minggw64的路径
1 https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/8.1.0/threads-posix/sjlj/x86_64-8.1.0-release-posix-sjlj-rt_v6-rev0.7z/download
中文乱码
settings->Editor->File Encodings,Global Encoding设置utf-8,Project Encoding设置utf-8,点击+把代码文件也设置utf-8,配置文件也改成utf-8,按住Ctrl+Shift+Alt+/选中Registry,然后取消掉run.processes.with.pty后面的√,点击close即可
变量 常量 const int a =100;
宏常量 #define name "john"
,宏常量在预编译的时候就替换进去了,反编译的代码里不会有这个
整型 int
(4字节), short int == short
(2字节), long int == long
(Windows为4字节,32位Linux为4字节、64位Linux为8字节), long long int == long long
(8字节)
溢出的话,就是short
类型赋值为65536,就会丢失数据
取数据大小,sizeof
(变量名)
浮点型 0.105可以写成.105
代码中直接出现的浮点数默认为double
使用float b = .105f,可以指定为float类型
cout输出默认显示6位有效数字,要显示更多需要配置,但是这种情况下会精度丢失
1 2 3 std::out.setf(std::ios::fixed); std::out.setf(std::ios::showpoint); std::out.precision(20);
字符型 使用单引号,只能写一个字符,不能是中文,占一个字节(Java里2个字节)
本质上也是数值,存的ASCII码的值,可以加减
有符号数和无符号数 signed和unsigned,不写默认有符号数
字符串 1 2 3 4 5 char cc[10 ] = "测试的" ;char cc[] = "测试的" ;char * str = "测试的" ;std ::string ccc = "test" ;ccc.c_str();
sprintf 用来格式化输出的
1 2 char aa[10 ];sprintf (aa,"%x" ,100 );
bool类型 C++才有,C没有,占一个字节
Java类型和C类型 比较
1 2 3 基本数据类型,两者通用 对于Java的引用类型,需要jni转换
jni用来解决Java和C之间的相互调用的问题
1 2 3 4 5 程序最终处理的都是数据 Java处理数据后的结果,只要转成C认识的类型,那么C就能接着处理 jni就规定了Java数据和C数据的映射关系,Java语言调用c语言的规则,并且提供了一系列的方法,用于转换数据、C调用Java等
Java
字节数
C
int
4
int
short
2
short
byte
1
char
long
8
long long
double
8
double
float
4
float
char
2
short
boolean
1
0代表假 1代表真
数据输入 cin >> a
数组 1 2 3 4 5 6 7 8 数据类型 数组名[数组长度] 数据类型 数组名[数组长度] = {值1,值2...} 数据类型 数组名[] = {值1,值2...} char a[] = {'a','b','c','\0'}; //最后要有\0 或者 char a[] = {'abc'}; //最后有没有\0都行
下标越界
计算数组长度sizeof(arr)/sizeof(arr[0])
数组地址
1 2 3 std::cout << arr << std::endl; //数组首地址_十六进制 std::cout << (long long)arr << std::endl; // 数组首地址_十进制 std::cout << &a[0] << std::endl; //数组首个元素的地址
字符串数组,char *代表字符串
1 char* a[4] = {'hello','you','yyyyyy','aaaaaaaa'};
指针 就是地址
定义和初始化 1 2 3 4 5 6 int *p; p = &a; 或者 int *p = &a; *p可以访问到p所指向的变量的值
运算符*和&
1 2 3 4 5 6 7 8 9 10 &:取地址符 a:变量a本身 p:指针变量p本身 &a:变量a的地址值 *p:指针变量p所指向的变量,也就是变量a &p:指针变量p的地址值,无意义 *a:把a看作指针,*a代表指针指向的变量,无意义 int a = 0x84025789(假定是合法地址) *a不合法,a根本不是指针变量
指针类型和所指向的变量类型必须匹配否则结果不可预知
空指针指向地址0,野指针不可预知
指针的大小,32位是4字节,64位8字节
指针与const 1 2 3 4 5 int a = 100; const int* p1 = &a; // 常量指针,p1本身可以变,但是p1的指向不能变,*p1 = 300 不合法 int* const p2 = &a; //指针常量,p2被定义为常量,那么p2的内容不能变,p2 = &b 不合法 const int* const p3 = &a; // 都不能变
指针应用 1 2 3 4 5 6 7 实现函数参数引用传递 实现函数多个返回值 处理字符串 表示结构体等复杂的数据结构,在作为参数传递的时候更节省内存
数组指针 数组的地址,int arr[] = {1,2,3}
,那么arr
、&arr
、&arr[0]
都表示数组的首地址
数组指针 int * arr_p = arr;
依次取数据的成员,arr_p++; printf(*arr_p)
,指针+1,加的是1个数据类型的长度(注意*p+1
和*(p+1)
不一样,后者才是对的)
1 2 3 4 char* a[4] = {'hello','you','yyyyyy','aaaaaaaa'}; // char*类型,想指向它就得是char**类型,就这么理解 char** arr_p = a; *arr_p访问到的就是hello
函数指针 指向函数的指针
定义和初始化 void (*pFunc)(int*, int*) = nullptr;
,函数名就是函数的首地址,所以赋值 pFunc = &swap
也可以 pFunc = swap
,函数指针代表的是这一类函数,返回值是void
,参数是俩int *
的
调用 (*pFunc)(...)
或者 pFunc(...)
函数指针数组 void (*pFunc[2])(int*, int*);
只要是参数为两个int*的就能赋值
函数指针作为函数的参数
1 2 3 4 5 6 7 8 9 10 typedef void (*pFunc)(int*, int*); // 定义类型,后面直接用pFunc就可以 ... void call_Func(pFunc pf){ ... } int main(){ pFunc = ...; }
全局变量 1 2 在本文件中定义的全局变量 引用别的文件中定义的全局变量
extern 1 2 3 4 5 6 7 8 9 10 11 extern int a; 表示引用别的文件中的全局变量a demo.h里写上 extern int a;,然后在demo.cpp里定义int a = 30;,然后在main.cpp里导入include "demo.h" 或者在main.cpp里不导入.h,直接写extern int a;也行(前提是demo.cpp里没有别的数据需要导入的) 第二种方法,编译器之所以知道去哪里找a变量,是在cmakelist.txt里确定的 extern "C" ..; 表示后续的代码以C语言的方式编译 extern "C" int swap(){ ... } 代表这个函数名在编译的时候不进行符号修饰
静态变量static 1 2 3 4 5 6 静态局部变量 swap()函数里定义了static int c = 1;c++; ,主函数连续调用三次swap函数,依次输出 1 2 3 静态全局变量,只能在当前文件内使用,在其他的cpp内不能用 静态函数,同上
内存区域 代码区,只读
全局区,全局变量、全局常量、静态变量、字符串常量
栈区,存放函数的参数和局部变量
堆区,由程序员分配和释放
char指针和char数组的区别 1 2 3 char *str1 = "test"; // 相当于常量,在全局区,不可被改变,*str1 = "new"会报错 char str2[] = "test"; // 本质是数组,可以修改
malloc和calloc 返回的都是void *,需要根据具体使用来强转类型
1 2 3 char* realResult = (char *)malloc(33); char* realResult = (char *)calloc(33, 1);
注意不要把函数内的局部变量的地址赋值给函数外的指针
1 2 3 4 5 6 7 int test(){ int a =100; return &a; } int main(){ int *p = test();//访问不到,局部变量被释放 }
多级指针 指向指针的指针
1 2 3 int a = 100; int *p = &a; int **pp = &p;//访问a就是**pp
多级指针的应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 想把参数当返回值,传入的实参是char*等指针的时候 void swap(int* result){ *result = 300; } int main(){ int result = 100; swap(&result); } 上述的可以修改值 void swap(char* result){ result = "new"; } int main(){ char* result = "old"; swap(result);// 无法修改值 } 上述的无法修改,因为在函数栈中新生成了局部变量result,这个局部变量被赋值为"old"字符串的地址,然后在函数内被修改为"new"字符串的地址,全程动的只是这个局部变量的值 void swap(char** result){ *result = "new"; } int main(){ char* result = "old"; swap(&result);// 可以 } 上述的可以修改值 传入的实参是一级指针,那么想把参数当返回值,形参就得是二级指针 形参要比实参多一级指针才能把参数当返回值用
demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 void swap1 (char ** result) { char temp[3 ]; char * realResult = (char *)calloc (33 , 1 ); for (int i = 0 ; i < 16 ; i++){ int index = i; sprintf (temp, "%.2x" , index); strcat (realResult, temp); } cout << "swap1: " << realResult << endl ; *result = realResult; } int main () { char * result = "kong" ; swap1(&result); cout << "main: " << result << endl ; free (result); return 0 ; }
也就是可以说,参数是二级指针,那么一般就是要改一级指针的指向,char **的话一般就是改字符串
结构体 相当于自定义数据类型
1 2 3 4 struct People { string name; int age; }
使用
1 struct Student s1;// C++里struct可以忽略
结构体里还可以定义函数指针
结构体指针和结构体传参
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 #include <iostream> using namespace std ; struct Student { string name; }; typedef struct { string name; int age = 30 ; bool sex; Student s; void (*pFunc)(); } testname; void swap () { cout << "this Func is Called" << endl ; } void swap1 (testname* x) { cout << x->name << endl ; } int main () { int a; int b = 100 ; testname p; p.name = "john" ; p.age = 31 ; p.sex = true ; p.s.name = "rw" ; p.pFunc = swap; p.pFunc(); cout << p.name << endl ; cout << p.age << endl ; cout << p.sex << endl ; cout << p.s.name << endl ; Student sArr[2 ]; sArr[0 ].name = "rw" ; sArr[1 ].name = "umr" ; cout << sArr[0 ].name << endl ; cout << sArr[1 ].name << endl ; testname* pp = &p; (*pp).pFunc(); pp->pFunc(); swap1(&p); return 0 ; }