数组
对于
int array[3]; int* ptr = array;
以下三行代码等价。
array[2];
*(ptr + 2);
*(int*)((char*)ptr + 8);
数组名有时可看做一个指针,(但数组名 != 指针)
array = ptr; //报错,数组名不能做修改
int* ptr = &array ; //报错,类型不匹配
cout << &array ; //可查看数组首个元素的地址
数组没有越界检查,在使用数组时要时刻注意数组的容量,避免越界。
出于效率考虑,数组作为形参传入函数后,会被当做指针处理。
当不得不使用数组作为函数形参时,得为函数增加一个参数用于提供数组的长度。
void checkSize(char a[])
{
cout << sizeof(a) << endl;
}
//输出4,为一个指针的大小
sizeof()如何得知数组的长度
来源:How does sizeof know the size of the operand array?
sizeof在编译阶段被诠释(interpreted),编译器知道数组如何被声明以及数组所占的空间。
“Calling sizeof on a dynamically-allocated array will likely not do what you want, because the end point of the array is not specified.”个人理解:数组没有结尾标记,所以应避免对运行阶段才创建的数组使用sizeof。
int a1[5];
int *a2[5] = new int[5];
//都申请了20byte内存,a1申请在栈内存上,会自动释放;
a2申请在堆内存上,需要手动释放。
指针
指针是一个整数(integer),一个数字,它存出一个内存的地址。一个指针所占内存大小与指针类型没有关系。
指针的类型决定了指针++时走过多少个字节。
指针的不正确使用经常会运行错误,所以应养成指针初始化的习惯。
空指针(int *p = nullptr)不能赋值。对空指针的赋值操作不会在编译阶段报错,程序运行时会崩溃。
指针的运算表达式
p++、++p和p+1
p++和++p都会使指针后移;p+1会返回指针后移后的位置,指针p不变 。
指针p具体后移多少字节(byte),取决于指针的类型。char类型后移1字节、int类型后移4字节、double类型后移8字节。
补充:自增(++)、自减(–)运算符的优先级高于解引用(*)运算符
int a[] = { 1,2,3,4,5 };
int* p = a;
cout << *(p++) << " " << *p << endl;
cout << *(++p) << " " << *p << endl;
int* q = a;
cout << *q++ << " " << *q << endl;
cout << *++q << " " << *q << endl;
//VS输出结果(前两行)
1 2
3 3
void 类型指针(C++中很少使用)
void类型指针可以接收任何类型的指针,能转换为任何类型(“A void pointer can hold address of any type and can be typcasted to any type.”)
void指针可以被任意类型的指针赋值或初始化,但无法解引用,必须将其转换为任意一种数据类型后才能解引用。
不常用void类型指针的原因:
在存取数据时,我们需要知道该数据占多少内存。对一个void指针赋值或初始化(如 void *ptr = 10;)会报错。因为编译器不知道该写入多少字节的数据,所以应该用带类型的指针告诉编译器。
(补充 :void *ptr = 0; 是允许的)
void 类型指针的用途:
C语言中malloc() 和 calloc() 返回void类型指针,使得函数可以根据任意数据类型分配内存。但在C++中必须强制转换返回指针类型为需要的数据类型。
cosnt指针
const char * s 或 char const * s // 指针s所指向的数据的值不能修改
char * const p // 指针p不能修改
(记法:从左往右读,char类型->>指针->>常量,指针是常量,∴指针本身不能修改)
引用
引用能做的事情指针都能做,但如果条件允许,最好使用引用,因为它能使代码看起来更简单,更有可读性。
虽然有很多相似处,但引用不等于指针常量
int i;
int &ri = i;
int * const cpi = &i;
//不能将ri与cpi看做完全等价的变量
引用与指针的区别:
引用必须初始化;
引用初始化后无法修改;
引用无法指向nullptr;
无法创建引用数组……
https://www.geeksforgeeks.org/references-in-c/
拷贝构造函数中必须使用引用。
非法引用的两个例子:
1、
#include<iostream>
using namespace std;
int main()
{
int* ptr = NULL;
int& ref = *ptr;
cout << ref;
}
2、
#include<iostream>
using namespace std;
int& fun()
{
int x = 10;
return x;
}
int main()
{
fun() = 30;
cout << fun();
return 0;
}