一、数据声明
数据声明的原则是:右侧的优先级高于左侧,()的优先级最高;
int a; //一个整型变量a;
int *a; //一个指向整形数的指针a;
int **a; //一个指向指针的指针a,a指向的指针是指向一个整型数;(a是指针的指针)
int a[10]; //一个有10个整型数的数组a;(a是一个数组)
int *a[10]; //一个有10个指针的数组a,该数组中的指针指向的是整型数;(a是一个数组,数组的内容是指针)
int (*a)[10]; //一个指向有10个整型数大小的数组的指针;(a是一个指针,指向的范围是10个int大小的空间)
int (*a)(int); //一个指向函数的指针a,该函数的形参为整型,返回值为整型;(a是一个指针,指向一个函数)
int (*a[10])(int); //a是一个数组,数组中的内容是指针,其他数组的10下表处的指针指向一个函数;
二、const
-
一般来讲,在c语言中const修饰过的变量无法二次赋值,通过这种方式达到保护变量的目的。
可以看出,当我们尝试给const a二次赋值时,编译器报错,a为只读变量。 -
常量指针与指针常量
const char *p; //const修饰内容,表明这段char类型的内存空间只读,但指针的指向可变;(类似于“”修饰的字符串定义)
char * const p; //const修饰指针p,表明指针只能指向这段char类型的内存空间,但这段空间中的内容可变;(一般用于指向固定的硬件资源地址)
const char * const p; //指针的指向,以及指向内存空间的内容都不可变;(例如指向ROM设备)
-
const修饰的变量并没有放在常量区,而是在栈区;
我们知道局部变量是存放在栈区。可以看出字符常量的地址在0x56038...
,而const修饰的数组a的地址和局部变量b的地址十分接近,都位于0x7ffff06...
-
常量修饰的变量并不是真正的常量,而是只读的变量;因为const修饰的局部变量依然在栈区这种可读写区,因此我们可以通过越界的方式更改const修饰过的局部变量;
从1中看出,a所在地址比b地址高16个字节,而int为4字节,因此将p+4
就可得到a[0]地址。通过这种方式将a[0]的值从0修改到5
,而编译器并未报错。通过这种指针越界的方式绕过编译器检查,使得const修饰的局部变量的值得以修改。