一、解读C的声明
1. const修饰符
const 不一定代表常量,const 主要被用于修饰函数的参数。使用 const 修饰符(变量名),只意味着使其“只读”。
比较const char *src
与char * const src
,前者*src
是可读的,后者src
是可读的。对于前者,src = 'a'
是能够通过编译的,但是*src = 'a'
会报错,而后者相反。
const 修饰的是紧跟在它后面的单词。
关于const修饰的范围问题,假设有下面这样一个结构体:
typedef struct {
char *title;
int price;
char isbn[32];
} BookData;
/* 注册书的数据 */
void regist_book(BookData const *book_data);
因为使用了const,所以book_data指向的对象是禁止改写的。但是,书的标题(book_data->title
)仍然是可以改写的。具体原因参照下图:
解决方法是如此改写char const *title
。
2. 函数形参的声明
void func(int a[])
{
...
}
在上面这种写法中,给人的感觉是函数传递的参数是数组,但是,C语言中是不能够将数组作为函数的参数进行传递的。能够传递的只有指向数组初始元素的指针。
上述代码在解读过程中会自动解读为
void func(int *a)
{
...
}
在声明函数形参时,作为类型分类的数组,会被解读为指针。需要注意的是,在C语言中,只有在这种情况下,int a[]
与int *a
才会具有相同的含义。
3. 强制类型转换
强制类型转换一般有两种。第一种是基本类型的强制转换,比如将int转换为double来使用。第二种是指针类型的强制转换,比如将指向int的指针强制转换为指向double的指针。在运行时,无论是指向 int 的指针,还是指向 double 的指针,从机器语言的角度来看,它们在大多数的处理环境中都只是地址。所谓的指针的强制类型转换,就是对指针进行强制读取转换。
需要注意的是,一旦对指针类型进行了强制转换,就无法追踪指针原本指向的对象了。要开发出可移植性高的程序应该尽量避免对指针类型进行强制转换。
二、指针与数组是不同的事物
C语言中的指针与数组是完全不同的事物!
对于下面这个指针,int *p
,如果p指向了某个数组,自然可以通过p[i]
的方式进行访问,但这并不代表p就是数组。p[i]
只是*(p + i)
的语法糖,只要p指向一个数组,就可以通过p[i]
对其进行访问,如下图示。
如果是“指针的数组”和“数组的数组”就会有很大的不同。
// 指针的数组
char *color_name[] = {
"red",
"green",
"blue",
};
上述代码的图解如下:
// 数组的数组
char color_name[][6] = {
"red",
"green",
"blue",
};
上述代码的图解如下:
以上两种情况都可以用color_name[i][j]
的方式对数组进行访问,但是内存中数据的布局是完全不同的。