指针是c/c艹的灵魂,通过指针大家可以直接访问内存对内存中的数据进行操作。这是像java,c#等高级语言所不具备的功能,但指针为大家带来优势的同时,它也是一把双刃剑,c与c艹程序员的很大一部分错误都出在指针上。而且通常这样的bug很难定位。就例如题主在题目描述中给出的这个问题。
大家先来回顾一下指针的概念,int *a表示定义了一个指向整形的指针变量a,a中应当存储的是一个32位的地址值(x86平台)或者64位的地址值(x64平台)(实际上,不管a指向的是什么样的变量,其位数都是固定的,因为地址长度不会随变量发生改变)。通过*a的操作大家就可以从a中存储的地址开始,读出一个int型长度的值,在大多数编译平台中int是四个字节的。大家称*a的操作为解引用。
接下来大家再来看看声明和定义有何不同。
int a;这是声明,表示在内存中已经存在了一个名为a的整形变量,在内存地址中占据四个字节。如果这句话写在函数外部表示a是全局变量,编译器在程序运行时会默认将其初始化为0(实际上,不管a是什么类型的变量,只要其是全局变量,都会被初始化为0)。在c++中如果a是类内部的static型变量,也会被初始化为0。而对其他情况而言,比如这句话是写在函数内部的,那么a就不会被程序初始化,而大家显然也没有将其初始化,那么它的值是未定的。也就是在创建这个变量时,内存地址是什么值,它的值就是什么。有时大家会在运行程序时看到“烫烫烫”,这就是因为内存在上电时统一初始化为0xcdcd,而大家如果声明了一个变量而未赋初值,那么它的值就是这个,而这个变量对应的中文gbk编码就是“烫”,所以有时你就会看到“烫烫烫”。但是通常这类错误编译平台会帮大家检测出来。
int a=1;这是定义,大家不光声明了一个a,还将其初始值定为1。所以通常这样的写法才是安全的。
再来看题主的问题。int *a;表示大家声明了一个指向整形的指针a,a中存储的是一个整形变量的地址,大家对其解引用即可得到其所指向的整形变量。但是大家只是声明,而没有初始化,a中存储的值是未知的。
*a=12;表示大家将该值取出后转到这个值的地址,再读出一个四字节长度的值,并把这四字节赋为12。这一操作显然是不合理的,因为a中的值未知,所以这一操作很可能会抹掉程序中的重要数据甚至导致程序崩溃。
所以在使用指针时一定要谨慎谨慎再谨慎。所有的指针都应该在声明时立即初始化。没有指向的指针应初始化为nullptr。
题主画了一句话“无论怎样,指针都不会创建一个整型变量”。看起来很疑惑,这句话的意思是说你只声明了一个指向整型的变量a,但是并没有整型变量存在,a必须是指向整型变量的,只有同时声明整型变量b,整型指针a,并把b的地址赋给a,a才是有意义的。
int b;
int *a=&b;
*a=12;