C语言基础知识之五

来源:互联网 发布:土工cbr试验量算法 编辑:程序博客网 时间:2024/05/22 07:00

函数指针

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 作用是字符替换,是预编译命令,没有检查功能,没有作用域的限制

0 0
原创粉丝点击