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 作用是字符替換,是預編譯命令,沒有檢查功能,沒有作用域的限制

發佈了32 篇原創文章 · 獲贊 14 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章