int *f();//返回指向int指针的函数。.
int (*pf)(); //指向返回int的函数的指针。pf is pointer to function returning int
C语言的声明中分为”类型”和”标识符”,把标识符取出后,剩下就是类型名(基本类型和派生类型,派生类型是由结构体、联合体、数组、函数、指针这些类型本身和有;之所以被叫做派生类是因为他们可以无限的派生出很多派生类型)。
解读C的声明(英语版)
- 找到标识符(变量名或函数)名称。
- 从标识符最近的地方开始依照”小括号、数组[ ]、函数()、指针* “的顺序解读。
- 用of,to,returning连接。
- 追加最左边的数据类型修饰符。
- 也可用倒叙中文版。
举例:用英语的方式解读
int (*func_p)(double)
//1.找到函数名:func_p
func_p is
//2.存在小括号(*func_p)
func_p is pointer to
//3.遇见了函数标识符(*func_p)(double)
func_p is pointer to function(double) returning
//4.追加数据类型修饰符int
func_p is pointer to function(double) returning int //翻译过来就是:func_p是返回int的函数的指针。
举例:用中文的方式解读
int (*func_p)(double)
//1.找到函数名:func_p
func_p
//2.存在小括号(*func_p)
func_p是一个指针(此时找到描述func_p的形容词)
//3.遇见了函数标识符(*func_p)(double)
func_p是一个指向函数的指针(此时找到描述指针的形容词)
//4.追加数据类型修饰符int
func_p是一个指向返回值是int类型的函数的指针(此时找到描述函数的形容词)
练习:
double (*p)[3];//指向double类型的数组(长度为3)的指针。
double *pp [3];//double类型的指针的数组(长度为3)。
int (*func_table[10])(int a);//指向返回值为int的函数(参数为int)的数组(长度为10)。
const关键字:const修饰的是紧跟在它后面的单词。
//成为只读的不是src,而是src所指向的对象。
char *strcpy(char *dest,const char *src){
src = NULL;//编译通过
*src = 'a';//报错
}
char *strcpy(char *dest, char const *src){
src = NULL;//编译通过
*src = 'a';//报错
}
//将src自身定义为只读
char *strcpy(char *dest, char *const src){
src = NULL;//报错
*src = 'a';//编译通过
}
char *strcpy(char *dest,const char *const src){
src = NULL;//报错
*src = 'a';//报错
}
char const* src 等价于 char const *src
const修饰结构体:定义为const的只读,只是结构体所指向的对象自身,不包括结构体指向对象所指向的对象。
typedef struct {
char *title;
int price;
char isbn[32];
} BookData;
void regist_book(BookData const bookData){
bookData .title = 'a';//报错
*bookData .title = 'a';//编译通过
}
上面例子的解释:
typedef关键字:用于给某些类型定义别名。
typedef char *String;//String是指向char的指针
String hoge[10];//hoge是指向char的指针的数组
数组的特殊说明
下标运算符[]可以忽略元素个数(中括号里面的数字不生效)的几种情况:
当做函数的形参声明时,只有在这种情况下,int s[]和int *s才具有相同的意义。
void f(int s[]){} void f(int *s){}//上面会被编译器自动解读为这种情况。
根据初始化表达式可以确定数组大小时。
int a[] = {1,2,3};
使用extern声明全局变量时。
file_1.c中的int a[100]; file_2.c中的extern int *a;
关于数组的初始化
//一维数组初始化
int s[3] = {1,2};
printf("%d",s[1]);//2
printf("%d",s[2]);//0
printf("%d",s[4]);//地址值
//多维数组的初始化:观察运行结果即可发现规律。
int a[][3] = {
{1,2,3,8},
{4,5},
{6}
};
printf("%d",a[0][3]);//4
printf("%d",a[0][8]);//0
printf("%d",a[0][9]);//内存地址值
字符串常量
str和str1具有相同的含义,编译器会对字符串常量做特殊处理。
char str[] = "abc";
char str1[] = {'a','b','c','\0'};
char str[] = "abc";//允许修改
str[0] = 'd';
char *str1[] = "abc";//不允许
str1[0] = 'd';
char str[] = {};//编译不通过
str = "abc";
练习两个复杂声明
int atexit(void (*func)(void));//返回int的函数,参数是指向返回void没有参数的函数的指针
void (*signal(int sig,void (*func)(int)))(int);//signal是返回“指向返回void参数为int的函数的指针“的函数,
// 它有两个参数,一个是int,另一个是“指向返回void参数为int的函数指针”
指针的数组和数组的数组
//指针的数组
char *color_name[] = {
"red","green","blue",
};
//数组的数组
char color_name1[][6] = {
"red","green","blue",
};