C语言基础知识之五

函数指针

int *a; //定义变量,a是整型指针变量
int a(); //定义函数,a是函数,返回值为int
int * a(); /定义函数,a是函数,返回值为int*
int *a[10]; //定义变量,a是数组,存放10单元整型指针的数组
int (*a)[10]; //定义变量,a是指针,指向10个数组单元的指针
int (*a)(); //定义函数,a是指针,指向函数的指针,返回值为int

1.函数代码存储空间的起始地址(又称入口地址)称为这个函数的指针。
如:

int (* p)( int ,int );

这是定义一个指向函数的指针变量,指针变量p的返回值类型是整型,并且这个函数有两个整型参数。
2.用函数指针变量调用函数
举例:

int Max(int a,int b)
{
return a>b?a:b;
}
int main()
{
int a=5;
int b=3;

      //int c=Max(a,b);  //1)通过函数名调用Max函数
      //printf("%d\n",c);

int (*p)(int ,int );  //定义指向函数的指针变量p,
             //只需要说明p的返回值是整型且有两个整型参数就行,即只指明int,用int x也可以
p=Max;  //使p指向Max函数首地址, p=&Max也可以
    //int c=(*p)(a,b);  //2)通过指针变量调用Max函数
printf("%d\n",p(a,b));  //printf("%d\n",(*p)(a,b));也可以

return 0;
}

3.定义和使用指向函数的指针变量

形式:类型名 (*指针变量名)(函数参数表列);
如:
int (*p)(int ,int );
说明:
(1)定义指向函数的指针变量,只能指向在定义时指定的那个类型的函数,如int (*p)(int ,int);是属于一个整型返回值,两个整型变量的参数的类型。即函数指针指向一个函数族
(2)如果指针调用函数,必须使指针指向该函数,如 p=Max;
(3)在给函数指针变量赋值时,只给出函数名不必给出参数
如:p=Max; //将函数入口地址赋给p
(4)函数指针调用函数时,只需用(*p)代替函数名即可
(5)指向函数的指针变量不能进行算术运算
(6)函数名调用函数,只能调用指定的某一个函数;而指针变量调用函数,可以根据不同的情况先后调用不同的函数。

结构体

C语言允许用户自己建立有不同类型数据组成的组合型的数据结构,它称为结构体
1.结构体类型形式:
struct 结构体名
{
类型名 成员名;
};
2.结构体中可以使用的类型:
(1)基本数据类型 (2)前面已经定义好的结构体 (3)结构体本身的指针

//以下是举例,不是具有功能的完整代码
#include<stdio.h>
#include<string.h>
struct Student  //struct Student是类型名,student是结构体名
{
char name[20];
int age;
};

struct A
{
    int a;
    //char a;//error,不能同名
    char b;
};
struct B
{
    int c;  //(1)
    struct A sa;  //(2)
    //struct B sb;   //error,因为不知道sb的内存大小
    struct B *pb;   //OK,因为指针为4个字节,已知  (3)
};
struct C
{
    struct A c;
    int a;//此处的结构体名称a与结构体A中的a不在一个级别,不冲突
};
int main()
{
struct Student stu1={"liubei",30};
struct Student stu2;
stu2=stu1;   //同类的结构体变量可以互相赋值
//stu2.name="caocao";//error 不能直接将字符串常量赋给字符数组
strcpy(stu2.name,"caocao");//ok,用字符串拷贝函数
printf("%s,%d\n%s\n",stu1.name,stu1.age,stu2.name);

struct C sc;
    sc.c.a=10;
    sc.a=100;//a不冲突,因为等级不同
    printf("%d.%d\n",sc.c.a,sc.a);
    return 0;
}

3.定义结构体类型变量
(1)先声明结构体类型,再定义该类型的变量
如:

struct Student
{
char name [20];
int age;
};
int main()
{
struct Student stu1;
struct Student *p;
return 0;
}

(2)在声明类型的同时定义变量

struct Student 
{char name[20];
int age;
};stu1;

4.访问成员的方式:(1)结构体普通变量通过 · 访问成员;(2)结构体指针变量通过->访问成员

struct A
{
    int a;
    int *p;
};
struct B
{
    struct A c;
    struct A *d;
    int e;
    int *f;
};
struct Student 
{
    char name[20];
    int age;
};
int main()
{
    struct B bb;
    struct B *pb;
    bb.c.a;   //访问成员
    bb.c.p;
    bb.d->a;
    bb.d->p;
    bb.e;
    bb.f;

    pb->c.a;//或(*pb).c.a    (*pb)是对pb进行解引用,不过用起来麻烦,使用较少
    pb->c.p;
    pb->d->a;
    pb->d->p;
    pb->e;
    pb->f;

    struct Student stu1={"liubei"};//聚合类型(数组和结构体)只初始化一部分时,其余部分默认为0,此处即age=0
    stu1.age=33;//修改stu1的年龄为33
    struct Student *ps=&stu1;
    (*ps).age=28;//或ps->age=28;比较常用   //指向符->和[]自带解引用
}

区分函数调用与函数声明的方法:函数声明有数据类型,函数调用没有数据类型
在C语言中,调用不带参数的函数,如 Student stu1();
在C++中,调用不带参数的函数,如 Student stu1; //c++没有参数的时候不用带括号
在C语言中,结构体关键字struct在调用时不可以省略;
在C++中,结构体关键字struct在调用时可以省略;

struct A
{
  int a;
  A()
  {  
     printf("haha ");
  }
  A(int x)
  {
     a=x;
     printf("A(int x)\n");
  }
};

int main()
{
  A  aa;   //c++没有参数的时候不用带括号
  A  bb(3);
return 0;
}

打印结果: haha A(int x)

用typedef声明新类型名

typedef是关键字,作用是类型重定义,即给类型取个别名
如:typedef unsigned longlong uint64;即给unsigned long long类型取个别名叫uint64
1.用一个别名代替复杂的类型名
(1)用别名代替结构体类型
typedef struct Student Student;    //Student是别名

即:

typedef  struct Student
{
char name[20];
int age;
}Student;   //Student为新的类型名(别名),代替typedef  struct Student{code}

用typedef声明后再去定义变量时不需要再写类型名struct Student,如直接定义为Student sa;
(2)用别名代替数组类型
typedef int Num[20];    //声明Num为整型数组类型名
Num  a;    //定义整型数组a
(3)用别名代替指针类型
typedef int * p;    //声明p为整型指针类型
p a[10];    //a是指针数组
(4)用别名代替指向函数的指针类型
typedef int (* pfun)(int ,int);   //pfun是函数指针类型,该函数返回整型值
pfun p;    //p为函数指针类型

归纳  声明新类型名的方法:
按定义变量的方式,把变量名换上新类型名,并且在最前面加上typedef,就声明了新类型名代替原来的类型。

typedef 与#define

typedef int * Pint;//重定义类型
# define PINT int *//字符替换
int main()
{
    Pint d,e;    //d为指针,e为指针
    PINT f,h;//int *f,h,故f为指针,h为int型
}

typedef 是类型重定义,在编译阶段有效,有类检查功能,有自己的作用域
# define 作用是字符替换,是预编译命令,没有检查功能,没有作用域的限制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值