指针与数组
//text.cpp
int arr[5] = { 1,2,3,4,5 };
//main.cpp
extern int* arr;
int main()
{
int ar[3] = { 1,2,3 };
cout << arr <<endl; //打印出00000001 输出的为数组的第一个元素,为什么呢?因为在main.cpp中是按指针引用了,此事得arr是一个指针变量,变量在取值时都会进行一次解引用,所以将arr这个地址中的值取了出来,所以输出的结果为1
cout << *arr <<endl; //执行到此处程序崩溃,为什么崩溃?arr已经进行了一次解引用,*arr是将arr解引用取出的值,也就是0000 0001这个地址中的值再一次取出,那么自然就会崩溃了
return 0;
}
int main()
{
int ar[3] = { 1,2,3 };
printf("%p\n", ar);//打印出ar这个地址
printf("%d\n", *ar);//打印出1
return 0;
}
为什么两次的结果不相同?原因是常量与变量的区别
常量与变量
- 常量在编译期将常量的值直接写入到常量的使用点
- 常量的初始化必须使用常量,如果使用变量就会退化成常变量
- ar作为数组名是一个地址,而地址是一个常量,编译时常量的值会直接编译到代码中
- 指针是一个变量
常量与变量赋值的区别
int main()
{
int a = 10;
int* p = &a;
int arr1[] = { 1,2,3,4,5 };
cout << arr1 << endl;//输出地址
//执行这句时的汇编
//lea eax,[arr1] 直接将arr1这个地址放到eax寄存器中
//push eax
cout << p << endl;//输出地址
//执行这句时的汇编
//mov eax,dword ptr [p] //去p的地址中取四个字节放到eax寄存器
//push eax
}
int main()
{
int a = 10;
int b = 20;
int* p = nullptr;
p = &a;
//汇编
//mov dword ptr [b],14h
int c = a;
//mov eax,dword ptr [a]
//mov dword ptr [b],eax
b = *p;
//mov eax,dword ptr [p] //先去p的地址中里边存储的地址拿出来,放到eax
//mov ecx,dword ptr [eax] //再从拿出来的地址中取出数放到ecx
//mov dword ptr [b],ecx //将ecx寄存器中的数,放到p的地址中
return 0;
}
const修饰符
int main()
{
const int a = 10;
//a = 20;
//int *p = &a;//行不通
int* p = (int*)&a;
*p = 20;
cout << a << endl; //打印出10
cout << *p << endl; //打印出20 为什么结果会这样?看下一段代码
}
- 面试:为什么常量必须初始化?
- 因为在编译期会将所有使用到常量的点,都替换为该常量的值
- 根据下面的代码,可以知道,常量就是常量,即使指针p看上去是指向了a,但是本质上指向的是一个临时量的,是不可能让你取改变这一常量的
int main()
{
const int a = 10;
//a = 20;
//int *p = &a;//行不通,const int *类型的变量不能初始化int *类型的变量
int* p = (int*)&a;//在这里生成一个临时的变量,取的是临时量的值,所以在上边那个代码中,不是改变了a的值,而是改变一个临时量的值,才会出现那种情况
//lea eax,[a]
//mov dword ptr [p],eax
*p = 20;
int b;
b = a; // 因为a是常变量,在编译期直接将常量的值写入常量的使用点
//mov dword ptr [b],0Ah
b = *p; //在这里,p是指针变量
//mov eax,dword ptr [p]
//mov ecx,dword ptr [eax]
//mov dword ptr[b],ecx
}
- 在c语言中,const的用法与C++中略有不同
- const修饰的内容不能做左值
int main()
{
int a = 10;
int* p1 = &a;
const int* p2 = &a;
int const* p3 = &a;
int* const p4 = &a;
int* q1 = &a;
const int* q2 = &a;
int const* q3 = &a;
int* const q4 = &a;
p1 = q1;
p1 = q2; //error 泄露常量的地址给非常指针
p1 = q3; //error
p1 = q4;
p2 = q1;
p2 = q2;
p2 = q3;
p2 = q4;
p3 = q1;
p3 = q2;
p3 = q3;
p3 = q4;
p4 = q1; //error
p4 = q2; //error
p4 = q3; //error
p4 = q4; //error
return 0;
}
- const修饰的内容如果不包含指针,则不参与类型
int fun(int a)
{
cout << typeid(a).name() <<endl;
return 0;
}
int fun(const int a)
{
cout << typeid(a).name() <<endl;
return 0;
}
//这两个函数不可以形成重载,因为const修饰的内容如果不包含指针,则不参与类型
int fun(int *a)
{
cout << typeid(a).name() <<endl;
return 0;
}
int fun(const int *a)
{
cout << typeid(a).name() <<endl;
return 0;
}
//如果改成这样,则可形参重载