指针基础

/*
 指针基础
 指针是一种数据类型,就像int,double类型一样,int是装整数数据,double是装小数数据,指针是装地址类型的数据,仅此而已。
 */

#include <iostream>
using namespace std;

int main() {
    // 一、指针的声明与定义
    // 以int类型指针为例:
    int a=10; //定义了a变量
    int *p; //声明一个int类型的指针,后面再赋值
    int *p1 = &a; //定义一个int类型的指针(赋值为a的地址)&为取地址符号
    
    p = &a; //把a变量空间的地址赋值给p指针,那么p就指向了a的空间
    cout<<a<<endl; //输出a变量的值
    cout<<&a<<endl; //输出a变量的地址
    cout<<p<<endl;  //输出p变量的值
    cout<<p1<<endl; //输出p1变量的值
    cout<<endl;
    /*
     输出:
     10
     0x7ff7bfeff348
     0x7ff7bfeff348
     0x7ff7bfeff348
     */
    
    /*
     形式:类型 + * + 变量名
     注意:int 表示p装的地址是整型变量的地址
     *表示p是一个指针变量
     p是指针的名字
     
     指针就是装地址的变量,变量要赋值,一定要装一块空间的地址,或指向一块空间,才能被使用。目前p是没有初始化,没有指向一块空间的地址。不赋值地址的情况下,什么也不能做,也叫野指针。
     
     & 取地址,可以取任何变量的地址
     */
    
    // 二、操作地址所对应的空间
    // 格式: *+地址 表示操作此地址所对应空间的值,可以存和取
    cout<<*p<<endl; //取:获取p变量的值所对应空间的值
    *p = 12; //存:通过指针对对应空间的值进行修改  *p相当于a
    cout<<*p<<endl;
    cout<<a<<endl; // a的值也相应修改,因为*p就是操作了a的空间
    *p = *p + 10; //通过*p修改p地址对应空间的值,自增加了10
    cout<<*p<<endl;
    cout<<a<<endl;
    cout<<endl;
    /*
     输出:
     10
     12
     12
     22
     22
     */
    
    // 三、指针变量指向别的地址
    int b = 30;
    p = &b; //把b的地址给p,那现在p保存的是b的地址了,不是原来a的地址
    *p = 100; //修改p地址对应空间的值,实际是修改b的值
    cout<<*p<<endl;
    cout<<b<<endl; //b的值通过*p操作改变了
    cout<<a<<endl; //a的值没改变
    cout<<endl;
    /*
     输出:
     100
     100
     22
     */
    
    // 四、& *嵌套
    // 可以多层嵌套,利用等替换去思考 可以这么理解:p = &a; *p==a,p是a的地址,那么*p就是a本身
    cout<<&*p<<endl; //输出a的地址,&取地址符 *地址对应空间操作符,&和*都是一元运算符,且结合性为从右向左 &*p 等价于 &(*p)而 *p相当于 a,&a就是a的地址
    cout<<*&*p<<endl; //输出a的值,从右向左
    cout<<endl;
    /*
     输出:
     0x7ff7bfeff33c
     12
     */
    
    
    // 五、其它类型的指针变量
    /*
     可以定义其它类型的指针变量
     注意,整数类型的指针只能装整数变量的地址,double类型的指针只能装double变量的地址,一定要注意类型
     为什么有不同类型的指针?
     理解:如果一个指针变量只装一个地址对于这个地址本身来说意义并不大,最重要的是通过这个地址找到所对应的空间,操作空间的值(*p)才是指针的价值,我们知道,不同类型的变量所占用空间长度(字节)不同,int占4个字节,double占8个字节,而且存储方式也不一样。而每个字节都有一个地址编号,对于int类型空间来说,是有4个地址的,而且是连续的,那p=&a其实只是把a的首地址给了p,如果要通过这个首地址来操作a的空间,那必须知道a到底占用了多少个字节,在这里,要操作*p就知道要操作4个字节的空间,所以说指针是有类型的。类型决定了内存操作,一个小范围的指针可以指向一个大范围的指针,操作不会异常,但结果可能不对,一个大范围指针不可以指向小范围的指针,操作不异常,结果肯定不对。
     */
    
    // 不同类型的指针,装不同类型变量的地址
    char *p2;
    long long *p3;
    double *p4;
    
    // 错误1:比如把整数变量b的地址给p4,这是错误的,p4是装double类型变量的地址
//    p4 = &b;
    
    // 错误2:由于p2声明后没赋值地址,使用*p2去操作地址对应的空间是错误的(没有地址,也就不存储对应的空间了)
//    *p2 = 'B';
    
    
    return 0;
}