C语言C指针(二)

初稿链接:http://www.orlion.ga/924/

一、指针与const限定符

    const限定符与指针结合起来常见的状来瞬间几乎栽:

const int *a;
int const *a;

    这半种写法是同的,a是一个对准const
int型的指针,a所针对的内存单元不可改写,所以(*a)++是休容许的,但a可以改写,所以a++可以。

int * const a;

    a是一个针对性int型的const指针,*a是可改写的,但a不容许改写。

int const * const a;

    a是一个针对性const int型的const指针,因此*a与a都不允许改写。

 

    本着非const变量的指针或非const变量的地点可以招给指向const变量的指针,编译器可以做隐式类型转换:

char c = 'a';
const char *pc = &c;

    但是据于const变量的指针或const变量的地点不可以传染被指向非const变量的指针,以免通过后者改写了前者所指向的内存单元,例如下面的代码编译器会警告:

const char c = 'a';
char *pc = &c;

    

    字符串字面值类似于数组名,做右值使用时自动转换为对首元素的指针,这种指针应该是const
char *路。printf函数原型的率先独参数是const char *型,可以把char *
或const char *指南针传给它。

 

第二、指针与结构体

 

    首先定义一个组织体类型然后定义这种类型的变量和指针:

struct unit {
    char c;
    int num;
};
struct unit u;
struct unit *p = &u;

    要经过指针p访问结构体成员好形容成(*p).c和(*p).num,为了写好,c语言提供了->运算符,也足以形容成p->c和p->num。

 

其三、指向指针的指针与指针数组

int i;
int *pi = &i;
int *ppi = π

    这样定义后,表达式*ppi取pi的值,表达式**ppi取i的值。

    数组中之每个元素得以是核心型,也得是复合类型,因此呢堪是指针类型。如定义一个数组a由十只元素做,每个元素还是int
*指针:

int *a[10];

    这称为指针数组

    

    main函数的原型是int main(int argc, char
*argv[]);。argc是令执行参数的个数。而argv是一个针对性指针的指针而非是依靠针数组。函数原型中之[]代表指针而未代表数组,等价于char
**argv。为什么不写成char **argv而写char *
argv[]否?主要是为吃读代码的总人口供行之有效之消息,argv不是指为单个指针,而是依靠于指针数组的首元素。数组中每个元素还是char
*指南针,指向一个发令行参数字符串。

 

季、指为数组的指针与多维数组

 

    以下定义一个针对数组的指针,数组有10只因素:

int (*a)[10];

    我们可看[]比*产生重强的优先级,如果a先和*结缘则代表a是一个指南针,如果a先跟[]结合则表示a是一个数组。现在看指向数组的指针怎么用:

int a[10];
int (*pa)[10] = &a;

    a是一个反复组,在&a这个表达式中,数组名叫做左值,取全方位数组的首地址赋给指针pa。注意&a[0]代表数组a的首元素的首地址,而&a代表数组a的首地址,显然这片单地点一样,但立刻有限单表达式的种是片种不同的指针类型,前者是int
*,而后者类型是int
(*)[10]。*pa就象征pa所指向的数组a,所以取数组的a[0]素得以就此表达式(*pa)[0]。注意到*pa可以形容成pa[0],所以(*pa)[0]这个表达式也堪改写成pa[0][0],pa就比如一个二维数组的名字,它象征什么意思呢?下面将pa和二维数组放在同分析。

    int a[5][10];和int (*pa)[10];之间的干近乎int a[10];和int
*pa之间的关系:a是由于同样种植因素结合的往往组,pa则是依于这种元素的指针。所以如果pa指向a的首元素:

int a[5][10];
int (*pa)[10] = &a[0];

    则pa[0]和a[0]获取是和一个要素,唯一比原复杂的地方在于这个因素是由于10个int组成的累组,而休是核心型。这样,我们可以将pa当成二维数组名来用,pa[1][2]和a[1][2]取得的吧是跟一个要素,而且pa比a用起又活,数组名无支持赋值、自增等运算,而指针可以支撑,pa++使pa跳了二维数组的等同执行(40独字节),指向a[1]的首地址。

 

五、函数类型和函数指针类型

    

    在C语言中函数也是均等栽档次,可以定义指于函数的指针,指针变量的内存单元存放一个地点值,而函数指针存放的就是函数的入口地址(位于.text段)。

    例:

#include <stdio.h>
void say_hello(const char *str)
{
     printf("Hello %s\n", str);
}
int main(void)
{
     void (*f)(const char *) = say_hello;
     f("Guys");
     return 0;
}

    变量f的类C语言声明void (*f) (const char
*),f首先跟*号结合在一起,因此是一个指南针。(*f)外面是一个函数原型的格式,参数是const
char
*,返回值是void,所以f是恃为这种函数的指针。而say_hello的参数是const
char
*,返回值是void,正好是这种函数,因此f可以指向say_hello。say_hello是同栽函数类型类似于数组类型,做右值使用时自动转换成为函数指针类型。当然也得写成void
(*f)(const char *) =
&say_hello;把函数ay_hello先取地址再赋予给f,不需活动类型转换。

    可以由此函数指针来调用函数:f(“Guys”),也可先行用*f取出它所依靠的函数类型又调用函数:(*f)(“Guys”)。

    

    可以先定义函数类型F:

typedef int F(void);

    这种类型的函数不带来参数,返回值是int,可以这样声明f和g:

F f, g;

    相当给声明:

int f(void);
int g(void);

    下面这函数声明是不当的:

F h(void);

    因为函数可以返回void类型、标量类型、结构体、联合体,但无可知回去函数类型,也未克回数组类型。而脚是函数声明时对的:

F *e(void);

    函数e返回一个F *列的函数指针,但是这么:

int (*fp)(void);

    是声称了一个函数指针,而未是声称一个函数。e也得这样声明:

F *fp;