目录
什么是地址?
在内存中,最小的存储单位(可寻址)是字节(Byte)。为了高效地操作内存,我们为每个字节都引入了唯一的地址。通常以十六进制表示,如0x000001(十六进制通常使用0x
开头,用于区分,详见https://stackoverflow.com/questions/2670639/why-are-hexadecimal-numbers-prefixed-with-0x)
(由于安全原因,大部分情况下,地址并不是物理内存中的真实地址,而是由操作系统分配的虚拟地址)
比如说你有一条4GiB的内存,其中共有232字节(4 × 210 × 210 × 210),因此其地址就从0开始,一直到232-1。32位的电脑使用32位来寻址,因此,一台32位的电脑最多只支持4GiB的内存;而对于64位的电脑,其使用64位地址,因此其最大内存为264Byte = 224TiB = 214PiB = 24EiB = 17179869184 GiB
对储存单位的说明:我们使用两种不同的计量方法,一种是基于十进制的,如GB(Gigabyte)MB(Megabyte)其换算方法为1GB=1000MB;另一种是基于二进制的,如GiB(Gibibyte)MiB(Mebibyte)其换算方法为1GiB = 210MiB = 1024MiB。在Windows中显示的GB实际为GiB。详见https://en.wikipedia.org/wiki/Gigabyte
指针
指针类似与变量,但存储的是地址,而非具体的数值
操作符
&
引用(reference):用于取地址。
*
解引用(dereference):取其中的内容。
比如:
int myAge = 43; // int变量
int* ptr = &myAge; // ptr是一个指针变量,存储了myAge的地址
// 输出age的值 (43)
printf("%d\n", myAge);
// 输出myage的地址 (0x7ffe5367e044)
printf("%p\n", &myAge);
// 输出ptr存储的地址 (0x7ffe5367e044)
printf("%p\n", ptr);
指针如何工作?
int main(){
int num = 10;
int *p1, *p2;
p1 = #
p2 = #
*p1 = 20;
*p2 = 30;
cout << &num << p1 << p2 << &p1 << &p2;
}
输出:0x61fe1c,0x61fe1c,0x61fe10,0x61fe08
由此可见,指针也是变量,指针也有他自己的地址。
数组中的指针
之前我们使用[]来访问数组中的元素,实际上,一个数组变量就是一个指向数组首位的指针
int a[5] = {1, 2, 3, 4, 5};
cout << a << endl; // 输出:0x31e6fffc80(数组首位的地址)
cout << *a << endl; // 输出:1(数组首位的值)
cout << a + 1 << endl; // 输出:0x31e6fffc84
cout << *(a + 1) << endl; // 输出:2
指针也能进行运算,比如说a+1表示a的第二个元素,如上
而指针运算所带来的偏移量(如上,a+1后地址+4)即为数据类型的大小。在这里a为int类型,因此每个数组元素占用4Byte空间,偏移量也是4Byte。
指针和数组的区别
数组是一个常量指针(constant pointer),意味着他不能被修改(reassigned)
int numbers[4] = {0, 1, 2, 3};
int *p = numbers; // 合法
p = p + 1; // 合法
numbers = p; // 错误: array names cannot be reassigned
使用sizeof()函数返回数组的大小(占用空间)单位Byte
int a[5] = {1, 2, 3, 4, 5};
cout << sizeof(a) << endl; // 输出: 20 (4Byte × 5)
内存操作 Memory
在之前的c中,我们使用malloc来开辟内存空间,使用free来释放内存空间。c++中也可以沿用这种方法。
在c++中,有两种新的operator:new和delete,其具有一些新特性
int * p1 = new int; //allocate an int, default initializer (do nothing)
int * p2 = new int(); //allocate an int, initialized to 0
int * p3 = new int(5); //allocate an int, initialized to 5
int * p4 = new int{};//C++11 allocate an int, initialized to 0
int * p5 = new int {5};//C++11 allocate an int, initialized to 5
Student * ps1 = new Student; //allocate a Student object, default initializer
//allocate a Student object, initialize the members
Student * ps2 = new Student {"Yu", 2020, 1}; //C++11
对于数组:
//allocate 16 int, default initializer (do nothing)
int * pa1 = new int[16];
//allocate 16 int, zero initialized
int * pa2 = new int[16]();
//allocate 16 int, zero initialized
int * pa3 = new int[16]{}; //C++11
//allocate 16 int, the first 3 element are initialized to 1,2,3, the rest 0
int * pa4 = new int[16]{1,2,3}; //C++11
//allocate memory for 16 Student objects, default initializer
Student * psa1 = new Student[16];
//allocate memory for 16 Student objects, the first two are explicitly initialized
Student * psa2 = new Student[16]{{"Li", 2000,1}, {"Yu", 2001,1}}; //C++11
使用delete关键字来释放内存。对于单个变量,使用delete
;对于数组,使用delete[]
//deallocate memory
delete p1;
//deallocate memory
delete ps1;
//deallocate the memory of the array
delete []pa2;
//deallocate the memory of the array, and call the destructors of all the elements
delete []psa2;
二维数组
由于内存是线性的,c++中我们使用下面的方式(行主序Row-major layout),来存储一个二维数组。
行主序意味着多维数组(例如二维数组)在内存中是按行优先存储的。也就是说,数组的元素会按照行的顺序依次存储:先存储第一行的所有元素,然后是第二行的所有元素,依此类推。

定义方式:int A[3][3];
如果d有N行M列,那么,d[i][j] 与 ptr[i*M+j] 同义
我们也可以使用A[1]来访问每一行第一个元素的地址,当成一维数组来用
int a[2][2] = {{1,2},{3,4}};
cout << a[0] << endl; // 输出0x5f33dff750
cout << a[1] << endl; // 输出0x5f33dff758
命令行参数
在实际使用中,有些时候,我们需要向程序内传递参数。比如,在使用mingw编译器时,我们会加上-o参数来指定可执行文件的名字。
int main(int argc, char *argv[]) {
cout << argc << endl;
for (int i = 0; i < argc; i++) {
cout << argv[i] << endl;
}
return 0;
}
编译完成后,在命令行内运行:
PS C:\Users\sy\Desktop\test> ./a.exe arg1 arg2 arg3
4
C:\Users\sy\Desktop\test\a.exe
arg1
arg2
arg3
可以看出,命令行内输入的参数会作为main函数的参数传入,第一个参数为数量,第二个参数是一个cstring数组,第一个元素是运行的位置,后面几个元素存储了传入的参数。
数据结构
todo
Comments NOTHING