解读C的声明
解读步骤:
1,首先着眼于标识符(变量名或者函数名);
2,从距离标识符最近的地方开始,依照优先顺序解释派生类型(指针,数组,函数);优先顺序:1:用于整理声明内容的括弧;2:用于表示数组的[ ],用于表示函数的();3:用于表示指针的*;
3,解释完成派生类型,使用“of”, "to", "returning"将他们连接起来。
4,最后,追加数据类型修饰符(在左边,int, double等);
5,英语不好的人, 可以倒序用中文解释。
例子:
int (*func_p)(double);
1,先看标识符func_p;
读为:func_p。
2,然后看到附近的指针;
读为:func_p是一个指针。
3,解释用于函数的(),参数为double;
读为:func_p是一个指向函数(参数为double)的指针。
4,最后解释数据类型修饰符int;
读为:func_p是一个指向返回值为int的函数(参数为double)的指针。
指向数组的指针
数组和指针都是派生类型,他们都是由基本类型开始重复派生生成的。
也就是说,派生出数组之后,再派生出指针,就可以生成“指向数组的指针”。
指向数组的指针和指向数组初始元素的指针不是一回事。
int array[3];
int (*array_p)[3];
在数组前加上&可以取得指向数组的指针,因此这样是可以的:
array_p = &array;
这样是错误的:
array_p = array;
从地址的角度上说,array和&array也许就是指向的同一个地址,但是他们在运算的时候结果不同。
在上面的例子中,array+1,指针前进4个字节;array_p+1,指针前进12个字节。
函数类型的派生
数组类型就是将几个派生类型排列而成的类型。因此,数组类型的全体长度为:
派生源的类型的大小 x 数组的元素个数。
函数类型是无法得到特定长度的。
对指向函数类型的指针不能做指针运算,因为我们无法得到当前指针的类型的大小。
计算类型的大小
除了函数类型和不完全类型,其他类型都有大小。
通过sizeof(类型名),编译器可以帮我们计算当前类型的大小,无论是多么复杂的类型。
比如:sizeof(int (*[5](double0);
下面我们自己计算一下各种类型的大小:
在这里:
int 4个字节
double 8个字节
指针 4个字节
计算类型的顺序:
1,基本类型
2,指针
3,数组
4,函数(无法计算大小)
比如说int (*[5])(double);
首先因为是返回int类型,计算结果为4个字节;指向返回int的函数的指针的数组,因为是函数,无法计算大小;指向返回int的的函数的指针,计算结果4个字节;返回int的函数的指针的数组(5个元素)结果为4X5=20;共20+4+4=28;
数组和指针相关的运算符
解引用:
单目运算符*被称为解引用;
地址运算符:
单目运算符&被称为地址运算符
下标运算符:
后置运算符[ ]被称为下标运算符;
—>运算符:
通过指针访问结构体的成员的时候会使用->运算符。
const修饰符
const将类型修饰为只读;
const主要用于修饰函数的参数;
/*const参数的实例*/
char *strcpy(char *dest, const char *src);
此时所谓的只读是如何表现的呢?做个实验就知道,上面例子中的src这个变量没有定义为只读。
char *strcpy(char *dest, const char *src);
{
src = NULL: //即使对src赋值,编译器也没有报错;
}
此时成为只读的不是src,而是src指向的对象;
char *strcpy(char *dest, const char *src);
{
src = 'a': //报错;
}
如果对src所指向的对象进行赋值,就会报错;
如果将src自身定义为只读,需要写成下面这样。
char *strcpy(char *dest, char * const src);
{
src = NULL: //报错;
}
如果想要将src的指向以及自身都定义为只读,可以写成下面这样:
char *strcpy(char *dest, const char * const src);
{
src = NULL: //报错;
*src = 'a'; //报错;
}
const修饰的是紧跟在它后面的单词;
此外容易造成混乱的是:
char const *src;
与
const char *src;
意思完全相同。
对于一个结构体:
typedef struct {
char *title;
int price;
char inbn[];
} Bookdata;
将上面这个结构体作为输入参数的函数原型,可以写成下面这样:
/*注册书的数据*/
void regist_book(BookData const *book_data);
因为使用了const,所以book_data所指向的对象是禁止改写的。
但是,书的标题(book_data->title)所指向的内容是可以改写的。这是因为,根据指定的const而成为只读的对象只是“book_data所指向的对象的本身”, 而不包括“book_data所指向的对象再往前追溯到的对象”。
typedef
typedef用于给某类型定义别名。
比如: typedef char *String;
通过以上声明,对于“指向char的指针”可以使用“string”这个别名:
String a[10];