c语言分区
- 栈Stack(大地址,由高向低使用)
- 堆Heap(由低向高使用)
- 全局or静态常量区
- 文本and代码区(小地址)
#include<stdlib.h>
#include<stdio.h>
int total = 0; //全局or静态常量区
void hehe() { //函数,在stack中
static int he = 0; //全局or静态常量区,因为static只会创建一次
he++;
total++;
}
int main() {
int k = 3; //函数的内部变量,在stack中,但3在代码区
char *str = "Hello, world!"; // str函数中内部变量,在stack中,“hello world”在常量区
int *p = (int *) malloc(sizeof(int)); // p在stack中,malloc动态分配的内存在堆中
hehe();
hehe();
printf("%d%s%d", k, str, *p);
free(p);
return 0; //stack中内存释放
}
类和对象
- 类:类是一个模板,它描述一类对象的行为和状态。
- 对象:对象是类的一个实例
c语言如何处理类和对象:
-
没有“类”,只有“类型”
-
没有“对象”,只有“变量”
-
结构体变量+函数
c语言采用结构体变量+函数的方式来实现类似功能,如下
#include "stdio.h" struct Student{ int id; }; void printID(struct Student *in){ printf("My id is %d.\n",in->id); } int main(){ struct Student one; one.id=999; printID(&one); return 0; }
但我们发现,Student的属性和加在属性上的操作是割裂开的,我们可以使用函数指针类解决此问题
- 函数指针
#include "stdio.h"
struct Student{
int id;
void (*printID)(struct Student *in);
};
void printID(struct Student *in){
printf("My id is %d.\n",in->id);
}
int main(){
struct Student one;
one.id=999;
one.printID=printID;
one.printID(&one);
return 0;
}
不一样的体验,用纯文本命令行写C++程序
- 打开vmware运行ubuntu
- 桌面右键打开终端
- 输入命令
ls
查看当前所在位置 - 输入命令
cd 桌面
进入桌面这个文件夹 - 输入命令
touch test.cpp
创建test.cpp文件 - 打开test.cpp文件,输入以下代码并保存
- 输入命令
g++ test.cpp
编译test.cpp文件,我们发现桌面上产生了一个新的文件a.out,这就是编译产生的可执行文件,接下来我们运行之 - 输入命令
./a.out
运行,发现如下输出:
c++的新特性
类(class)
之前说过了
bool类型和auto类型
bool,c语言中,真假用整形来代替,0 -->False
&& !0-->True
&& True-->
&& False-->0
c++中,可以true,false,也可以用0和1
auto,让编译器推断是什么类型,但必须在初始化时赋值,否则编译报错
cout,在打印浮点数是会省略后面的部分
引用
int a = 3; //定义了变量a,并用3使其初始化,=不是运算符=含义是初始化
int b; //定义了变量b,没有初始化
b = 3; //把3赋值给b,=是运算符
int array[10]={1,2,3}; //定义了数组array,并用{1,2,3}使其初始化
array={1,2,3}; //错误
array[10]={1,2,3}; //错误
int *p; // *的含义是p是一个指针,不是取值运算符,p是指向int类型的指针
int a = 3;
p = &a;
*p = 6; // *的是取值运算符
int b = 6;
int &r = b; // &的含义是r是一个引用类型,不是取地址运算符,r是int类型的引用,=表示用b来初始化r,让r成为b的引用,不是赋值,可以理解为给b起个外号,自此之后r就是b,b就是r
r = 123;
cout << r << endl; // 123
cout << b << endl; // 123
在C++中函数的参数传递:
- 按值传递(pass by value)
- 地址传递(pass by pointer)
- 引用传递(pass by reference)
引用必须在定义时初始化,一旦创建就不可更换引用的对象
int b = 6;
int &r; //error: 'r' declared as reference but not initialized
r = b; //把b的值赋值给r,但此时r并没有任何的引用
关于赋值
int a, b, c;
(a = b = c = 3) = 666;
cout << a << endl; //666
cout << b << endl; //3
cout << c << endl; //3
赋值之后返回的是左值的引用
初始化的新语法
int a{3};
int array[5]{1, 2, 3, 4, 5};
new和delete
int *p;
p = (int *) malloc(sizeof(int));
free(p);
p = new int;
delete p;
deleete[] p; //复杂类型应该这样写
#include "iostream"
using namespace std;
class Student {
public:
int sid;
};
int main() {
Student one, two;
one.sid = 1;
two.sid = 2;
cout << &one << endl;
cout << &two << endl;
one = two;
two.sid = 999;
cout << &one << endl;
cout << &two << endl;
return 0;
}
#include "iostream"
using namespace std;
class Student {
public:
int sid;
};
int main() {
Student *one = new Student();
Student *two = new Student();
// Student *one, *two;
// one = new Student();
// two = new Student();
one->sid = 1;
two->sid = 2;
cout << &one << endl; //0x63fde8
cout << &two << endl; //0x63fde0
one = two; //内存泄漏
two->sid = 999;
cout << one << endl; //0x1c1770
cout << two << endl; //0x1c1770
return 0;
}
进一步理解Java的引用,相当于c++中的指针,java的引用和c++的引用是不一样的
class Student {
public int sid;
}
public class test {
public static void main(String args[]) {
Student one = new Student(); //创建对象一定需要new
Student two = new Student();
one.sid = 1;
two.sid = 2;
System.out.println("one: " + one); //one: Student@7291c18f
System.out.println("two: " + two); //two: Student@34a245ab
one = two;
two.sid = 999;
System.out.println("one: " + one); //one: Student@34a245ab
System.out.println("two: " + two); //two: Student@34a245ab
}
}
新的for循环
for-each不再赘述,可以使用auto,each是取出来的容器里的值,&each可以修改容器里本来的值
重载
C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。
在同一个作用域内,可以声明几个同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。不能仅通过返回类型的不同来重载函数。
我们可以重定义或重载大部分 C++ 内置的运算符。这样,您就能使用自定义类型的运算符。
重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。
注:在一个函数声明中,const可以修饰形参表明他是一个输入参数,在函数内部不可以改变其值;
lambda
auto f = [](auto a, auto b) -> auto { return a + b; };
cout << f(3.1, 5) << endl; // 8.1